tor-0.2.4.20/0000755000175000017500000000000012255753765007563 500000000000000tor-0.2.4.20/aclocal.m40000644000175000017500000011223712255745705011344 00000000000000# generated automatically by aclocal 1.11.6 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, # Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.6], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.6])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, # 2010, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 12 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_PROG_CC_C_O # -------------- # Like AC_PROG_CC_C_O, but changed for automake. AC_DEFUN([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC_C_O])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi dnl Make sure AC_PROG_CC is never called again, or it will override our dnl setting of CC. m4_define([AC_PROG_CC], [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2009, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # (`yes' being less verbose, `no' or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [ --enable-silent-rules less verbose build output (undo: `make V=1') --disable-silent-rules verbose build output (undo: `make V=0')]) case $enable_silent_rules in yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few `make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using `$V' instead of `$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/ax_check_sign.m4]) m4_include([acinclude.m4]) tor-0.2.4.20/LICENSE0000644000175000017500000001704712255745673010520 00000000000000 This file contains the license for Tor, a free software project to provide anonymity on the Internet. It also lists the licenses for other components used by Tor. For more information about Tor, see https://www.torproject.org/. If you got this file as a part of a larger bundle, there may be other license terms that you should be aware of. =============================================================================== Tor is distributed under this license: Copyright (c) 2001-2004, Roger Dingledine Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson Copyright (c) 2007-2013, The Tor Project, Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of the copyright owners nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================== src/ext/strlcat.c and src/ext/strlcpy.c by Todd C. Miller are licensed under the following license: * Copyright (c) 1998 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================== src/ext/tor_queue.h is licensed under the following license: * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. =============================================================================== src/config/geoip is licensed under the following license: OPEN DATA LICENSE (GeoLite Country and GeoLite City databases) Copyright (c) 2008 MaxMind, Inc. All Rights Reserved. All advertising materials and documentation mentioning features or use of this database must display the following acknowledgment: "This product includes GeoLite data created by MaxMind, available from http://maxmind.com/" Redistribution and use with or without modification, are permitted provided that the following conditions are met: 1. Redistributions must retain the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 2. All advertising materials and documentation mentioning features or use of this database must display the following acknowledgement: "This product includes GeoLite data created by MaxMind, available from http://maxmind.com/" 3. "MaxMind" may not be used to endorse or promote products derived from this database without specific prior written permission. THIS DATABASE IS PROVIDED BY MAXMIND, INC ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MAXMIND BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DATABASE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================== If you got Tor as a static binary with OpenSSL included, then you should know: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/)" =============================================================================== tor-0.2.4.20/config.guess0000755000175000017500000012743212255745723012027 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-02-10' # This file 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: tor-0.2.4.20/Makefile.nmake0000644000175000017500000000046612166112775012232 00000000000000all: cd src/common $(MAKE) /F Makefile.nmake cd ../../src/or $(MAKE) /F Makefile.nmake cd ../../src/test $(MAKE) /F Makefile.nmake clean: cd src/common $(MAKE) /F Makefile.nmake clean cd ../../src/or $(MAKE) /F Makefile.nmake clean cd ../../src/test $(MAKE) /F Makefile.nmake clean tor-0.2.4.20/README0000644000175000017500000000143412120436355010345 00000000000000Tor protects your privacy on the internet by hiding the connection between your Internet address and the services you use. We believe Tor is reasonably secure, but please ensure you read the instructions and configure it properly. To build Tor from source: ./configure && make && make install Home page: https://www.torproject.org/ Download new versions: https://www.torproject.org/download.html Documentation, including links to installation and setup instructions: https://www.torproject.org/documentation.html Making applications work with Tor: https://wiki.torproject.org/noreply/TheOnionRouter/TorifyHOWTO Frequently Asked Questions: https://www.torproject.org/faq.html https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ tor-0.2.4.20/install-sh0000755000175000017500000003325612255745723011513 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-01-19.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for `test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: tor-0.2.4.20/configure.ac0000644000175000017500000013160112255745673011772 00000000000000dnl Copyright (c) 2001-2004, Roger Dingledine dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson dnl Copyright (c) 2007-2013, The Tor Project, Inc. dnl See LICENSE for licensing information AC_INIT([tor],[0.2.4.20]) AC_CONFIG_SRCDIR([src/or/main.c]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_CONFIG_HEADERS([orconfig.h]) AC_CANONICAL_HOST if test -f /etc/redhat-release ; then if test -f /usr/kerberos/include ; then CPPFLAGS="$CPPFLAGS -I/usr/kerberos/include" fi fi # Not a no-op; we want to make sure that CPPFLAGS is set before we use # the += operator on it in src/or/Makefile.am CPPFLAGS="$CPPFLAGS -I\${top_srcdir}/src/common" #XXXX020 We should make these enabled or not, before 0.2.0.x-final AC_ARG_ENABLE(buf-freelists, AS_HELP_STRING(--disable-buf-freelists, disable freelists for buffer RAM)) AC_ARG_ENABLE(openbsd-malloc, AS_HELP_STRING(--enable-openbsd-malloc, Use malloc code from openbsd. Linux only)) AC_ARG_ENABLE(instrument-downloads, AS_HELP_STRING(--enable-instrument-downloads, Instrument downloads of directory resources etc.)) AC_ARG_ENABLE(static-openssl, AS_HELP_STRING(--enable-static-openssl, Link against a static openssl library. Requires --with-openssl-dir)) AC_ARG_ENABLE(static-libevent, AS_HELP_STRING(--enable-static-libevent, Link against a static libevent library. Requires --with-libevent-dir)) AC_ARG_ENABLE(static-zlib, AS_HELP_STRING(--enable-static-zlib, Link against a static zlib library. Requires --with-zlib-dir)) AC_ARG_ENABLE(static-tor, AS_HELP_STRING(--enable-static-tor, Create an entirely static Tor binary. Requires --with-openssl-dir and --with-libevent-dir and --with-zlib-dir)) AC_ARG_ENABLE(curve25519, AS_HELP_STRING(--disable-curve25519, Build Tor with no curve25519 elliptic-curve crypto support)) if test "$enable_static_tor" = "yes"; then enable_static_libevent="yes"; enable_static_openssl="yes"; enable_static_zlib="yes"; CFLAGS="$CFLAGS -static" fi if test x$enable_buf_freelists != xno; then AC_DEFINE(ENABLE_BUF_FREELISTS, 1, [Defined if we try to use freelists for buffer RAM chunks]) fi AM_CONDITIONAL(USE_OPENBSD_MALLOC, test x$enable_openbsd_malloc = xyes) if test x$enable_instrument_downloads = xyes; then AC_DEFINE(INSTRUMENT_DOWNLOADS, 1, [Defined if we want to keep track of how much of each kind of resource we download.]) fi AC_ARG_ENABLE(transparent, AS_HELP_STRING(--disable-transparent, disable transparent proxy support), [case "${enableval}" in yes) transparent=true ;; no) transparent=false ;; *) AC_MSG_ERROR(bad value for --enable-transparent) ;; esac], [transparent=true]) AC_ARG_ENABLE(asciidoc, AS_HELP_STRING(--disable-asciidoc, don't use asciidoc (disables building of manpages)), [case "${enableval}" in yes) asciidoc=true ;; no) asciidoc=false ;; *) AC_MSG_ERROR(bad value for --disable-asciidoc) ;; esac], [asciidoc=true]) # By default, we're not ready to ship a NAT-PMP aware Tor AC_ARG_ENABLE(nat-pmp, AS_HELP_STRING(--enable-nat-pmp, enable NAT-PMP support), [case "${enableval}" in yes) natpmp=true ;; no) natpmp=false ;; * ) AC_MSG_ERROR(bad value for --enable-nat-pmp) ;; esac], [natpmp=false]) # By default, we're not ready to ship a UPnP aware Tor AC_ARG_ENABLE(upnp, AS_HELP_STRING(--enable-upnp, enable UPnP support), [case "${enableval}" in yes) upnp=true ;; no) upnp=false ;; * ) AC_MSG_ERROR(bad value for --enable-upnp) ;; esac], [upnp=false]) AC_ARG_ENABLE(threads, AS_HELP_STRING(--disable-threads, disable multi-threading support)) if test x$enable_threads = x; then case $host in *-*-solaris* ) # Don't try multithreading on solaris -- cpuworkers seem to lock. AC_MSG_NOTICE([You are running Solaris; Sometimes threading makes cpu workers lock up here, so I will disable threads.]) enable_threads="no";; *) enable_threads="yes";; esac fi if test "$enable_threads" = "yes"; then AC_DEFINE(ENABLE_THREADS, 1, [Defined if we will try to use multithreading]) fi case $host in *-*-solaris* ) AC_DEFINE(_REENTRANT, 1, [Define on some platforms to activate x_r() functions in time.h]) ;; esac AC_ARG_ENABLE(gcc-warnings, AS_HELP_STRING(--enable-gcc-warnings, enable verbose warnings)) AC_ARG_ENABLE(gcc-warnings-advisory, AS_HELP_STRING(--enable-gcc-warnings-advisory, [enable verbose warnings, excluding -Werror])) dnl Adam shostack suggests the following for Windows: dnl -D_FORTIFY_SOURCE=2 -fstack-protector-all dnl Others suggest '/gs /safeseh /nxcompat /dynamicbase' for non-gcc on Windows dnl This requires that we use gcc and that we add -O2 to the CFLAGS. AC_ARG_ENABLE(gcc-hardening, AS_HELP_STRING(--disable-gcc-hardening, disable compiler security checks)) dnl Linker hardening options dnl Currently these options are ELF specific - you can't use this with MacOSX AC_ARG_ENABLE(linker-hardening, AS_HELP_STRING(--disable-linker-hardening, disable linker security fixups)) AC_ARG_ENABLE(local-appdata, AS_HELP_STRING(--enable-local-appdata, default to host local application data paths on Windows)) if test "$enable_local_appdata" = "yes"; then AC_DEFINE(ENABLE_LOCAL_APPDATA, 1, [Defined if we default to host local appdata paths on Windows]) fi # Tor2web mode flag AC_ARG_ENABLE(tor2web-mode, AS_HELP_STRING(--enable-tor2web-mode, support tor2web non-anonymous mode), [if test x$enableval = xyes; then CFLAGS="$CFLAGS -D ENABLE_TOR2WEB_MODE=1" fi]) AC_ARG_ENABLE(bufferevents, AS_HELP_STRING(--enable-bufferevents, use Libevent's buffered IO.)) dnl check for the correct "ar" when cross-compiling AN_MAKEVAR([AR], [AC_PROG_AR]) AN_PROGRAM([ar], [AC_PROG_AR]) AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL([AR], [ar], [ar])]) AC_PROG_AR AC_PROG_CC AC_PROG_CPP AC_PROG_MAKE_SET AC_PROG_RANLIB dnl autoconf 2.59 appears not to support AC_PROG_SED AC_CHECK_PROG([SED],[sed],[sed],[/bin/false]) dnl check for asciidoc and a2x AC_PATH_PROG([ASCIIDOC], [asciidoc], none) AC_PATH_PROG([A2X], [a2x], none) AM_CONDITIONAL(USE_ASCIIDOC, test x$asciidoc = xtrue) AM_CONDITIONAL(USE_FW_HELPER, test x$natpmp = xtrue || test x$upnp = xtrue) AM_CONDITIONAL(NAT_PMP, test x$natpmp = xtrue) AM_CONDITIONAL(MINIUPNPC, test x$upnp = xtrue) AM_PROG_CC_C_O ifdef([AC_C_FLEXIBLE_ARRAY_MEMBER], [ AC_C_FLEXIBLE_ARRAY_MEMBER ], [ dnl Maybe we've got an old autoconf... AC_CACHE_CHECK([for flexible array members], tor_cv_c_flexarray, [AC_COMPILE_IFELSE( AC_LANG_PROGRAM([ struct abc { int a; char b[]; }; ], [ struct abc *def = malloc(sizeof(struct abc)+sizeof(char)); def->b[0] = 33; ]), [tor_cv_c_flexarray=yes], [tor_cv_c_flexarray=no])]) if test $tor_cv_flexarray = yes ; then AC_DEFINE([FLEXIBLE_ARRAY_MEMBER], [], [Define to nothing if C supports flexible array members, and to 1 if it does not.]) else AC_DEFINE([FLEXIBLE_ARRAY_MEMBER], [1], [Define to nothing if C supports flexible array members, and to 1 if it does not.]) fi ]) AC_PATH_PROG([SHA1SUM], [sha1sum], none) AC_PATH_PROG([OPENSSL], [openssl], none) TORUSER=_tor AC_ARG_WITH(tor-user, [ --with-tor-user=NAME Specify username for tor daemon ], [ TORUSER=$withval ] ) AC_SUBST(TORUSER) TORGROUP=_tor AC_ARG_WITH(tor-group, [ --with-tor-group=NAME Specify group name for tor daemon ], [ TORGROUP=$withval ] ) AC_SUBST(TORGROUP) dnl If _WIN32 is defined and non-zero, we are building for win32 AC_MSG_CHECKING([for win32]) AC_RUN_IFELSE([AC_LANG_SOURCE([ int main(int c, char **v) { #ifdef _WIN32 #if _WIN32 return 0; #else return 1; #endif #else return 2; #endif }])], bwin32=true; AC_MSG_RESULT([yes]), bwin32=false; AC_MSG_RESULT([no]), bwin32=cross; AC_MSG_RESULT([cross]) ) if test "$bwin32" = cross; then AC_MSG_CHECKING([for win32 (cross)]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #ifdef _WIN32 int main(int c, char **v) {return 0;} #else #error int main(int c, char **v) {return x(y);} #endif ])], bwin32=true; AC_MSG_RESULT([yes]), bwin32=false; AC_MSG_RESULT([no])) fi AM_CONDITIONAL(BUILD_NT_SERVICES, test x$bwin32 = xtrue) dnl Enable C99 when compiling with MIPSpro AC_MSG_CHECKING([for MIPSpro compiler]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [ #if (defined(__sgi) && defined(_COMPILER_VERSION)) #error return x(y); #endif ])], bmipspro=false; AC_MSG_RESULT(no), bmipspro=true; AC_MSG_RESULT(yes)) if test "$bmipspro" = true; then CFLAGS="$CFLAGS -c99" fi AC_C_BIGENDIAN AC_SEARCH_LIBS(socket, [socket network]) AC_SEARCH_LIBS(gethostbyname, [nsl]) AC_SEARCH_LIBS(dlopen, [dl]) AC_SEARCH_LIBS(inet_aton, [resolv]) saved_LIBS="$LIBS" AC_SEARCH_LIBS([clock_gettime], [rt]) if test "$LIBS" != "$saved_LIBS"; then # Looks like we need -lrt for clock_gettime(). have_rt=yes fi if test "$enable_threads" = "yes"; then AC_SEARCH_LIBS(pthread_create, [pthread]) AC_SEARCH_LIBS(pthread_detach, [pthread]) fi dnl ------------------------------------------------------------------- dnl Check for functions before libevent, since libevent-1.2 apparently dnl exports strlcpy without defining it in a header. AC_CHECK_FUNCS( _NSGetEnviron \ accept4 \ clock_gettime \ flock \ ftime \ getaddrinfo \ getifaddrs \ getrlimit \ gettimeofday \ gmtime_r \ inet_aton \ ioctl \ issetugid \ llround \ localtime_r \ lround \ memmem \ prctl \ rint \ socketpair \ strlcat \ strlcpy \ strptime \ strtok_r \ strtoull \ sysconf \ uname \ vasprintf \ _vscprintf ) if test "$enable_threads" = "yes"; then AC_CHECK_HEADERS(pthread.h) AC_CHECK_FUNCS(pthread_create) fi dnl ------------------------------------------------------ dnl Where do you live, libevent? And how do we call you? if test "$bwin32" = true; then TOR_LIB_WS32=-lws2_32 TOR_LIB_IPHLPAPI=-liphlpapi # Some of the cargo-cults recommend -lwsock32 as well, but I don't # think it's actually necessary. TOR_LIB_GDI=-lgdi32 else TOR_LIB_WS32= TOR_LIB_GDI= fi AC_SUBST(TOR_LIB_WS32) AC_SUBST(TOR_LIB_GDI) AC_SUBST(TOR_LIB_IPHLPAPI) dnl We need to do this before we try our disgusting hack below. AC_CHECK_HEADERS([sys/types.h]) dnl This is a disgusting hack so we safely include older libevent headers. AC_CHECK_TYPE(u_int64_t, unsigned long long) AC_CHECK_TYPE(u_int32_t, unsigned long) AC_CHECK_TYPE(u_int16_t, unsigned short) AC_CHECK_TYPE(u_int8_t, unsigned char) tor_libevent_pkg_redhat="libevent" tor_libevent_pkg_debian="libevent-dev" tor_libevent_devpkg_redhat="libevent-devel" tor_libevent_devpkg_debian="libevent-dev" dnl On Gnu/Linux or any place we require it, we'll add librt to the Libevent dnl linking for static builds. STATIC_LIBEVENT_FLAGS="" if test "$enable_static_libevent" = "yes"; then if test "$have_rt" = yes; then STATIC_LIBEVENT_FLAGS=" -lrt " fi fi TOR_SEARCH_LIBRARY(libevent, $trylibeventdir, [-levent $STATIC_LIBEVENT_FLAGS $TOR_LIB_WS32], [ #ifdef _WIN32 #include #endif #include #include #include #include ], [ #ifdef _WIN32 #include #endif void exit(int); void *event_init(void);], [ #ifdef _WIN32 {WSADATA d; WSAStartup(0x101,&d); } #endif event_init(); exit(0); ], [--with-libevent-dir], [/opt/libevent]) dnl Now check for particular libevent functions. save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LIBS="-levent $STATIC_LIBEVENT_FLAGS $TOR_LIB_WS32 $LIBS" LDFLAGS="$TOR_LDFLAGS_libevent $LDFLAGS" CPPFLAGS="$TOR_CPPFLAGS_libevent $CPPFLAGS" AC_CHECK_FUNCS(event_get_version event_get_version_number event_get_method event_set_log_callback evdns_set_outgoing_bind_address event_base_loopexit) AC_CHECK_MEMBERS([struct event.min_heap_idx], , , [#include ]) AC_CHECK_HEADERS(event2/event.h event2/dns.h event2/bufferevent_ssl.h) LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" CPPFLAGS="$save_CPPFLAGS" AM_CONDITIONAL(USE_EXTERNAL_EVDNS, test x$ac_cv_header_event2_dns_h = xyes) if test "$enable_static_libevent" = "yes"; then if test "$tor_cv_library_libevent_dir" = "(system)"; then AC_MSG_ERROR("You must specify an explicit --with-libevent-dir=x option when using --enable-static-libevent") else TOR_LIBEVENT_LIBS="$TOR_LIBDIR_libevent/libevent.a $STATIC_LIBEVENT_FLAGS" fi else TOR_LIBEVENT_LIBS="-levent" fi dnl This isn't the best test for Libevent 2.0.3-alpha. Once it's released, dnl we can do much better. if test "$enable_bufferevents" = "yes" ; then if test "$ac_cv_header_event2_bufferevent_ssl_h" != "yes" ; then AC_MSG_ERROR([You've asked for bufferevent support, but you're using a version of Libevent without SSL support. This won't work. We need Libevent 2.0.8-rc or later, and you don't seem to even have Libevent 2.0.3-alpha.]) else CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent" # Check for the right version. First see if version detection works. AC_MSG_CHECKING([whether we can detect the Libevent version]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #if !defined(LIBEVENT_VERSION_NUMBER) || LIBEVENT_VERSION_NUMBER < 10 #error int x = y(zz); #else int x = 1; #endif ])], [event_version_number_works=yes; AC_MSG_RESULT([yes]) ], [event_version_number_works=no; AC_MSG_RESULT([no])]) if test "$event_version_number_works" != 'yes'; then AC_MSG_WARN([Version detection on Libevent seems broken. Your Libevent installation is probably screwed up or very old.]) else AC_MSG_CHECKING([whether Libevent is new enough for bufferevents]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #if !defined(LIBEVENT_VERSION_NUMBER) || LIBEVENT_VERSION_NUMBER < 0x02000d00 #error int x = y(zz); #else int x = 1; #endif ])], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) AC_MSG_ERROR([Libevent does not seem new enough to support bufferevents. We require 2.0.13-stable or later]) ] ) fi fi fi LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" CPPFLAGS="$save_CPPFLAGS" AM_CONDITIONAL(USE_BUFFEREVENTS, test "$enable_bufferevents" = "yes") if test "$enable_bufferevents" = "yes"; then AC_DEFINE(USE_BUFFEREVENTS, 1, [Defined if we're going to use Libevent's buffered IO API]) if test "$enable_static_libevent" = "yes"; then TOR_LIBEVENT_LIBS="$TOR_LIBDIR_libevent/libevent_openssl.a $TOR_LIBEVENT_LIBS" else TOR_LIBEVENT_LIBS="-levent_openssl $TOR_LIBEVENT_LIBS" fi fi AC_SUBST(TOR_LIBEVENT_LIBS) dnl ------------------------------------------------------ dnl Where do you live, libm? dnl On some platforms (Haiku/BeOS) the math library is dnl part of libroot. In which case don't link against lm TOR_LIB_MATH="" save_LIBS="$LIBS" AC_SEARCH_LIBS(pow, [m], , AC_MSG_ERROR([Could not find pow in libm or libc.])) if test "$ac_cv_search_pow" != "none required"; then TOR_LIB_MATH="$ac_cv_search_pow" fi LIBS="$save_LIBS" AC_SUBST(TOR_LIB_MATH) dnl ------------------------------------------------------ dnl Where do you live, openssl? And how do we call you? tor_openssl_pkg_redhat="openssl" tor_openssl_pkg_debian="libssl" tor_openssl_devpkg_redhat="openssl-devel" tor_openssl_devpkg_debian="libssl-dev" ALT_openssl_WITHVAL="" AC_ARG_WITH(ssl-dir, [ --with-ssl-dir=PATH Obsolete alias for --with-openssl-dir ], [ if test "x$withval" != xno && test "x$withval" != "x" ; then ALT_openssl_WITHVAL="$withval" fi ]) TOR_SEARCH_LIBRARY(openssl, $tryssldir, [-lssl -lcrypto $TOR_LIB_GDI], [#include ], [void RAND_add(const void *buf, int num, double entropy);], [RAND_add((void*)0,0,0); exit(0);], [], [/usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/athena /opt/openssl]) dnl XXXX check for OPENSSL_VERSION_NUMBER == SSLeay() if test "$enable_static_openssl" = "yes"; then if test "$tor_cv_library_openssl_dir" = "(system)"; then AC_MSG_ERROR("You must specify an explicit --with-openssl-dir=x option when using --enable-static-openssl") else TOR_OPENSSL_LIBS="$TOR_LIBDIR_openssl/libssl.a $TOR_LIBDIR_openssl/libcrypto.a" fi else TOR_OPENSSL_LIBS="-lssl -lcrypto" fi AC_SUBST(TOR_OPENSSL_LIBS) dnl ------------------------------------------------------ dnl Where do you live, zlib? And how do we call you? tor_zlib_pkg_redhat="zlib" tor_zlib_pkg_debian="zlib1g" tor_zlib_devpkg_redhat="zlib-devel" tor_zlib_devpkg_debian="zlib1g-dev" TOR_SEARCH_LIBRARY(zlib, $tryzlibdir, [-lz], [#include ], [const char * zlibVersion(void);], [zlibVersion(); exit(0);], [--with-zlib-dir], [/opt/zlib]) if test "$enable_static_zlib" = "yes"; then if test "$tor_cv_library_zlib_dir" = "(system)"; then AC_MSG_ERROR("You must specify an explicit --with-zlib-dir=x option when using --enable-static-zlib") else TOR_ZLIB_LIBS="$TOR_LIBDIR_zlib/libz.a" fi else TOR_ZLIB_LIBS="-lz" fi AC_SUBST(TOR_ZLIB_LIBS) dnl --------------------------------------------------------------------- dnl Now that we know about our major libraries, we can check for compiler dnl and linker hardening options. We need to do this with the libraries known, dnl since sometimes the linker will like an option but not be willing to dnl use it with a build of a library. all_ldflags_for_check="$TOR_LDFLAGS_zlib $TOR_LDFLAGS_openssl $TOR_LDFLAGS_libevent" all_libs_for_check="$TOR_ZLIB_LIBS $TOR_LIB_MATH $TOR_LIBEVENT_LIBS $TOR_OPENSSL_LIBS $TOR_LIB_WS32 $TOR_LIB_GDI" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__clang__) #error #endif])], have_clang=yes, have_clang=no) if test x$enable_gcc_hardening != xno; then CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" if test x$have_clang = xyes; then TOR_CHECK_CFLAGS(-Qunused-arguments) fi TOR_CHECK_CFLAGS(-fstack-protector-all) TOR_CHECK_CFLAGS(-Wstack-protector) TOR_CHECK_CFLAGS(-fwrapv) TOR_CHECK_CFLAGS(--param ssp-buffer-size=1) if test "$bwin32" = "false"; then TOR_CHECK_CFLAGS(-fPIE) TOR_CHECK_LDFLAGS(-pie, "$all_ldflags_for_check", "$all_libs_for_check") fi fi if test x$enable_linker_hardening != xno; then TOR_CHECK_LDFLAGS(-z relro -z now, "$all_ldflags_for_check", "$all_libs_for_check") fi dnl ------------------------------------------------------ dnl Where do you live, libnatpmp? And how do we call you? dnl There are no packages for Debian or Redhat as of this patch if test "$natpmp" = "true"; then AC_DEFINE(NAT_PMP, 1, [Define to 1 if we are building with nat-pmp.]) TOR_SEARCH_LIBRARY(libnatpmp, $trylibnatpmpdir, [-lnatpmp $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI], [#include ], [#ifdef _WIN32 #define STATICLIB #endif #include ], [ int r; natpmp_t natpmp; natpmpresp_t response; r = initnatpmp(&natpmp, 0, 0);], [printf("initnatpmp() returned %d (%s)\n", r, r?"FAILED":"SUCCESS"); exit(0);], [--with-libnatpmp-dir], [/usr/lib/]) fi dnl ------------------------------------------------------ dnl Where do you live, libminiupnpc? And how do we call you? dnl There are no packages for Debian or Redhat as of this patch if test "$upnp" = "true"; then AC_DEFINE(MINIUPNPC, 1, [Define to 1 if we are building with UPnP.]) dnl Before we call TOR_SEARCH_LIBRARY we'll do a quick compile test dnl to see if we have miniupnpc-1.5 or -1.6 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], [upnpDiscover(1, 0, 0, 0);exit(0);])],[miniupnpc15="true"],[miniupnpc15="false"]) if test "$miniupnpc15" = "true" ; then AC_DEFINE([MINIUPNPC15],[1],[libminiupnpc version 1.5 found]) TOR_SEARCH_LIBRARY(libminiupnpc, $trylibminiupnpcdir, [-lminiupnpc $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI], [#include #include #include ], [void upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport);], [upnpDiscover(1, 0, 0, 0); exit(0);], [--with-libminiupnpc-dir], [/usr/lib/]) else TOR_SEARCH_LIBRARY(libminiupnpc, $trylibminiupnpcdir, [-lminiupnpc $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI], [#include #include #include ], [void upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error);], [upnpDiscover(1, 0, 0, 0, 0, 0); exit(0);], [--with-libminiupnpc-dir], [/usr/lib/]) fi fi dnl ============================================================ dnl We need an implementation of curve25519. dnl set these defaults. have_a_curve25519=no build_curve25519_donna=no build_curve25519_donna_c64=no use_curve25519_donna=no use_curve25519_nacl=no CURVE25519_LIBS= if test x$enable_curve25519 != xno; then dnl The best choice is using curve25519-donna-c64, but that requires dnl that we AC_CACHE_CHECK([whether we can use curve25519-donna-c64], tor_cv_can_use_curve25519_donna_c64, [AC_RUN_IFELSE( [AC_LANG_PROGRAM([dnl #include typedef unsigned uint128_t __attribute__((mode(TI))); int func(uint64_t a, uint64_t b) { uint128_t c = ((uint128_t)a) * b; int ok = ((uint64_t)(c>>96)) == 522859 && (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L && (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L && (((uint64_t)(c))&0xffffffffL) == 0; return ok; } ], [dnl int ok = func( ((uint64_t)2000000000) * 1000000000, ((uint64_t)1234567890) << 24); return !ok; ])], [tor_cv_can_use_curve25519_donna_c64=yes], [tor_cv_can_use_curve25519_donna_c64=no], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([dnl #include typedef unsigned uint128_t __attribute__((mode(TI))); int func(uint64_t a, uint64_t b) { uint128_t c = ((uint128_t)a) * b; int ok = ((uint64_t)(c>>96)) == 522859 && (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L && (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L && (((uint64_t)(c))&0xffffffffL) == 0; return ok; } ], [dnl int ok = func( ((uint64_t)2000000000) * 1000000000, ((uint64_t)1234567890) << 24); return !ok; ])], [tor_cv_can_use_curve25519_donna_c64=cross], [tor_cv_can_use_curve25519_donna_c64=no])])]) AC_CHECK_HEADERS([crypto_scalarmult_curve25519.h \ nacl/crypto_scalarmult_curve25519.h]) AC_CACHE_CHECK([for nacl compiled with a fast curve25519 implementation], tor_cv_can_use_curve25519_nacl, [tor_saved_LIBS="$LIBS" LIBS="$LIBS -lnacl" AC_LINK_IFELSE( [AC_LANG_PROGRAM([dnl #ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H #include #elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H) #include #endif #ifdef crypto_scalarmult_curve25519_ref_BYTES #error Hey, this is the reference implementation! That's not fast. #endif ], [ unsigned char *a, *b, *c; crypto_scalarmult_curve25519(a,b,c); ])], [tor_cv_can_use_curve25519_nacl=yes], [tor_cv_can_use_curve25519_nacl=no]) LIBS="$tor_saved_LIBS" ]) dnl Okay, now we need to figure out which one to actually use. Fall back dnl to curve25519-donna.c if test x$tor_cv_can_use_curve25519_donna_c64 != xno; then build_curve25519_donna_c64=yes use_curve25519_donna=yes elif test x$tor_cv_can_use_curve25519_nacl = xyes; then use_curve25519_nacl=yes CURVE25519_LIBS=-lnacl else build_curve25519_donna=yes use_curve25519_donna=yes fi have_a_curve25519=yes fi if test x$have_a_curve25519 = xyes; then AC_DEFINE(CURVE25519_ENABLED, 1, [Defined if we have a curve25519 implementation]) fi if test x$use_curve25519_donna = xyes; then AC_DEFINE(USE_CURVE25519_DONNA, 1, [Defined if we should use an internal curve25519_donna{,_c64} implementation]) fi if test x$use_curve25519_nacl = xyes; then AC_DEFINE(USE_CURVE25519_NACL, 1, [Defined if we should use a curve25519 from nacl]) fi AM_CONDITIONAL(BUILD_CURVE25519_DONNA, test x$build_curve25519_donna = xyes) AM_CONDITIONAL(BUILD_CURVE25519_DONNA_C64, test x$build_curve25519_donna_c64 = xyes) AM_CONDITIONAL(CURVE25519_ENABLED, test x$have_a_curve25519 = xyes) AC_SUBST(CURVE25519_LIBS) dnl Make sure to enable support for large off_t if available. AC_SYS_LARGEFILE AC_CHECK_HEADERS( assert.h \ errno.h \ fcntl.h \ signal.h \ string.h \ sys/fcntl.h \ sys/stat.h \ sys/time.h \ sys/types.h \ time.h \ unistd.h , , AC_MSG_WARN(Some headers were not found, compilation may fail. If compilation succeeds, please send your orconfig.h to the developers so we can fix this warning.)) dnl These headers are not essential AC_CHECK_HEADERS( arpa/inet.h \ crt_externs.h \ grp.h \ ifaddrs.h \ inttypes.h \ limits.h \ linux/types.h \ machine/limits.h \ malloc.h \ malloc/malloc.h \ malloc_np.h \ netdb.h \ netinet/in.h \ netinet/in6.h \ pwd.h \ stdint.h \ sys/file.h \ sys/ioctl.h \ sys/limits.h \ sys/mman.h \ sys/param.h \ sys/prctl.h \ sys/resource.h \ sys/socket.h \ sys/syslimits.h \ sys/time.h \ sys/types.h \ sys/un.h \ sys/utime.h \ sys/wait.h \ syslog.h \ utime.h ) AC_CHECK_HEADERS(sys/param.h) AC_CHECK_HEADERS(net/if.h, net_if_found=1, net_if_found=0, [#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif]) AC_CHECK_HEADERS(net/pfvar.h, net_pfvar_found=1, net_pfvar_found=0, [#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif]) AC_CHECK_HEADERS(linux/netfilter_ipv4.h, linux_netfilter_ipv4=1, linux_netfilter_ipv4=0, [#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_LIMITS_H #include #endif #ifdef HAVE_LINUX_TYPES_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif]) if test x$transparent = xtrue ; then transparent_ok=0 if test x$net_if_found = x1 && test x$net_pfvar_found = x1 ; then transparent_ok=1 fi if test x$linux_netfilter_ipv4 = x1 ; then transparent_ok=1 fi if test x$transparent_ok = x1 ; then AC_DEFINE(USE_TRANSPARENT, 1, "Define to enable transparent proxy support") case $host in *-*-openbsd* | *-*-bitrig*) AC_DEFINE(OPENBSD, 1, "Define to handle pf on OpenBSD properly") ;; esac else AC_MSG_NOTICE([Transparent proxy support enabled, but missing headers.]) fi fi AC_CHECK_MEMBERS([struct timeval.tv_sec], , , [#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif]) dnl In case we aren't given a working stdint.h, we'll need to grow our own. dnl Watch out. AC_CHECK_SIZEOF(int8_t) AC_CHECK_SIZEOF(int16_t) AC_CHECK_SIZEOF(int32_t) AC_CHECK_SIZEOF(int64_t) AC_CHECK_SIZEOF(uint8_t) AC_CHECK_SIZEOF(uint16_t) AC_CHECK_SIZEOF(uint32_t) AC_CHECK_SIZEOF(uint64_t) AC_CHECK_SIZEOF(intptr_t) AC_CHECK_SIZEOF(uintptr_t) dnl AC_CHECK_TYPES([int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, intptr_t, uintptr_t]) AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(__int64) AC_CHECK_SIZEOF(void *) AC_CHECK_SIZEOF(time_t) AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(pid_t) AC_CHECK_TYPES([uint, u_char, ssize_t]) dnl used to include sockaddr_storage, but everybody has that. AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t], , , [#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif ]) AC_CHECK_MEMBERS([struct in6_addr.s6_addr32, struct in6_addr.s6_addr16, struct sockaddr_in.sin_len, struct sockaddr_in6.sin6_len], , , [#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif ]) AC_CHECK_TYPES([rlim_t], , , [#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif ]) AX_CHECK_SIGN([time_t], [ AC_DEFINE(TIME_T_IS_SIGNED, 1, [Define if time_t is signed]) ], [ : ], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_TIME_H #include #endif ]) if test "$ax_cv_decl_time_t_signed" = no; then AC_MSG_WARN([You have an unsigned time_t; some things will probably break. Please tell the Tor developers about your interesting platform.]) fi AX_CHECK_SIGN([size_t], [ tor_cv_size_t_signed=yes ], [ tor_cv_size_t_signed=no ], [ #ifdef HAVE_SYS_TYPES_H #include #endif ]) if test "$ax_cv_decl_size_t_signed" = yes; then AC_MSG_ERROR([You have a signed size_t; that's grossly nonconformant.]) fi AX_CHECK_SIGN([enum always], [ AC_DEFINE(ENUM_VALS_ARE_SIGNED, 1, [Define if enum is always signed]) ], [ : ], [ enum always { AAA, BBB, CCC }; ]) AC_CHECK_SIZEOF(socklen_t, , [AC_INCLUDES_DEFAULT() #ifdef HAVE_SYS_SOCKET_H #include #endif ]) # We want to make sure that we _don't_ have a cell_t defined, like IRIX does. AC_CHECK_SIZEOF(cell_t) # Now make sure that NULL can be represented as zero bytes. AC_CACHE_CHECK([whether memset(0) sets pointers to NULL], tor_cv_null_is_zero, [AC_RUN_IFELSE([AC_LANG_SOURCE( [[#include #include #include #ifdef HAVE_STDDEF_H #include #endif int main () { char *p1,*p2; p1=NULL; memset(&p2,0,sizeof(p2)); return memcmp(&p1,&p2,sizeof(char*))?1:0; }]])], [tor_cv_null_is_zero=yes], [tor_cv_null_is_zero=no], [tor_cv_null_is_zero=cross])]) if test "$tor_cv_null_is_zero" = cross ; then # Cross-compiling; let's hope that the target isn't raving mad. AC_MSG_NOTICE([Cross-compiling: we'll assume that NULL is represented as a sequence of 0-valued bytes.]) fi if test "$tor_cv_null_is_zero" != no; then AC_DEFINE([NULL_REP_IS_ZERO_BYTES], 1, [Define to 1 iff memset(0) sets pointers to NULL]) fi AC_CACHE_CHECK([whether memset(0) sets doubles to 0.0], tor_cv_dbl0_is_zero, [AC_RUN_IFELSE([AC_LANG_SOURCE( [[#include #include #include #ifdef HAVE_STDDEF_H #include #endif int main () { double d1,d2; d1=0; memset(&d2,0,sizeof(d2)); return memcmp(&d1,&d2,sizeof(d1))?1:0; }]])], [tor_cv_dbl0_is_zero=yes], [tor_cv_dbl0_is_zero=no], [tor_cv_dbl0_is_zero=cross])]) if test "$tor_cv_dbl0_is_zero" = cross ; then # Cross-compiling; let's hope that the target isn't raving mad. AC_MSG_NOTICE([Cross-compiling: we'll assume that 0.0 can be represented as a sequence of 0-valued bytes.]) fi if test "$tor_cv_dbl0_is_zero" != no; then AC_DEFINE([DOUBLE_0_REP_IS_ZERO_BYTES], 1, [Define to 1 iff memset(0) sets doubles to 0.0]) fi # And what happens when we malloc zero? AC_CACHE_CHECK([whether we can malloc(0) safely.], tor_cv_malloc_zero_works, [AC_RUN_IFELSE([AC_LANG_SOURCE( [[#include #include #include #ifdef HAVE_STDDEF_H #include #endif int main () { return malloc(0)?0:1; }]])], [tor_cv_malloc_zero_works=yes], [tor_cv_malloc_zero_works=no], [tor_cv_malloc_zero_works=cross])]) if test "$tor_cv_malloc_zero_works" = cross; then # Cross-compiling; let's hope that the target isn't raving mad. AC_MSG_NOTICE([Cross-compiling: we'll assume that we need to check malloc() arguments for 0.]) fi if test "$tor_cv_malloc_zero_works" = yes; then AC_DEFINE([MALLOC_ZERO_WORKS], 1, [Define to 1 iff malloc(0) returns a pointer]) fi # whether we seem to be in a 2s-complement world. AC_CACHE_CHECK([whether we are using 2s-complement arithmetic], tor_cv_twos_complement, [AC_RUN_IFELSE([AC_LANG_SOURCE( [[int main () { int problem = ((-99) != (~99)+1); return problem ? 1 : 0; }]])], [tor_cv_twos_complement=yes], [tor_cv_twos_complement=no], [tor_cv_twos_complement=cross])]) if test "$tor_cv_twos_complement" = cross ; then # Cross-compiling; let's hope that the target isn't raving mad. AC_MSG_NOTICE([Cross-compiling: we'll assume that negative integers are represented with two's complement.]) fi if test "$tor_cv_twos_complement" != no ; then AC_DEFINE([USING_TWOS_COMPLEMENT], 1, [Define to 1 iff we represent negative integers with two's complement]) fi # What does shifting a negative value do? AC_CACHE_CHECK([whether right-shift on negative values does sign-extension], tor_cv_sign_extend, [AC_RUN_IFELSE([AC_LANG_SOURCE( [[int main () { int okay = (-60 >> 8) == -1; return okay ? 0 : 1; }]])], [tor_cv_sign_extend=yes], [tor_cv_sign_extend=no], [tor_cv_sign_extend=cross])]) if test "$tor_cv_sign_extend" = cross ; then # Cross-compiling; let's hope that the target isn't raving mad. AC_MSG_NOTICE([Cross-compiling: we'll assume that right-shifting negative integers causes sign-extension]) fi if test "$tor_cv_sign_extend" != no ; then AC_DEFINE([RSHIFT_DOES_SIGN_EXTEND], 1, [Define to 1 iff right-shifting a negative value performs sign-extension]) fi # Whether we should use the dmalloc memory allocation debugging library. AC_MSG_CHECKING(whether to use dmalloc (debug memory allocation library)) AC_ARG_WITH(dmalloc, [ --with-dmalloc Use debug memory allocation library. ], [if [[ "$withval" = "yes" ]]; then dmalloc=1 AC_MSG_RESULT(yes) else dmalloc=1 AC_MSG_RESULT(no) fi], [ dmalloc=0; AC_MSG_RESULT(no) ] ) if [[ $dmalloc -eq 1 ]]; then AC_CHECK_HEADERS(dmalloc.h, , AC_MSG_ERROR(dmalloc header file not found. Do you have the development files for dmalloc installed?)) AC_SEARCH_LIBS(dmalloc_malloc, [dmallocth dmalloc], , AC_MSG_ERROR(Libdmalloc library not found. If you enable it you better have it installed.)) AC_DEFINE(USE_DMALLOC, 1, [Debug memory allocation library]) AC_DEFINE(DMALLOC_FUNC_CHECK, 1, [Enable dmalloc's malloc function check]) AC_CHECK_FUNCS(dmalloc_strdup dmalloc_strndup) fi AC_ARG_WITH(tcmalloc, [ --with-tcmalloc Use tcmalloc memory allocation library. ], [ tcmalloc=yes ], [ tcmalloc=no ]) if test x$tcmalloc = xyes ; then LDFLAGS="-ltcmalloc $LDFLAGS" fi using_custom_malloc=no if test x$enable_openbsd_malloc = xyes ; then using_custom_malloc=yes fi if test x$tcmalloc = xyes ; then using_custom_malloc=yes fi if test $using_custom_malloc = no ; then AC_CHECK_FUNCS(mallinfo) fi # By default, we're going to assume we don't have mlockall() # bionic and other platforms have various broken mlockall subsystems. # Some systems don't have a working mlockall, some aren't linkable, # and some have it but don't declare it. AC_CHECK_FUNCS(mlockall) AC_CHECK_DECLS([mlockall], , , [ #ifdef HAVE_SYS_MMAN_H #include #endif]) # Allow user to specify an alternate syslog facility AC_ARG_WITH(syslog-facility, [ --with-syslog-facility=LOG syslog facility to use (default=LOG_DAEMON)], syslog_facility="$withval", syslog_facility="LOG_DAEMON") AC_DEFINE_UNQUOTED(LOGFACILITY,$syslog_facility,[name of the syslog facility]) AC_SUBST(LOGFACILITY) # Check if we have getresuid and getresgid AC_CHECK_FUNCS(getresuid getresgid) # Check for gethostbyname_r in all its glorious incompatible versions. # (This logic is based on that in Python's configure.in) AH_TEMPLATE(HAVE_GETHOSTBYNAME_R, [Define this if you have any gethostbyname_r()]) AC_CHECK_FUNC(gethostbyname_r, [ AC_MSG_CHECKING([how many arguments gethostbyname_r() wants]) OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [[ char *cp1, *cp2; struct hostent *h1, *h2; int i1, i2; (void)gethostbyname_r(cp1,h1,cp2,i1,&h2,&i2); ]])],[ AC_DEFINE(HAVE_GETHOSTBYNAME_R) AC_DEFINE(HAVE_GETHOSTBYNAME_R_6_ARG, 1, [Define this if gethostbyname_r takes 6 arguments]) AC_MSG_RESULT(6) ], [ AC_TRY_COMPILE([ #include ], [ char *cp1, *cp2; struct hostent *h1; int i1, i2; (void)gethostbyname_r(cp1,h1,cp2,i1,&i2); ], [ AC_DEFINE(HAVE_GETHOSTBYNAME_R) AC_DEFINE(HAVE_GETHOSTBYNAME_R_5_ARG, 1, [Define this if gethostbyname_r takes 5 arguments]) AC_MSG_RESULT(5) ], [ AC_TRY_COMPILE([ #include ], [ char *cp1; struct hostent *h1; struct hostent_data hd; (void) gethostbyname_r(cp1,h1,&hd); ], [ AC_DEFINE(HAVE_GETHOSTBYNAME_R) AC_DEFINE(HAVE_GETHOSTBYNAME_R_3_ARG, 1, [Define this if gethostbyname_r takes 3 arguments]) AC_MSG_RESULT(3) ], [ AC_MSG_RESULT(0) ]) ]) ]) CFLAGS=$OLD_CFLAGS ]) AC_CACHE_CHECK([whether the C compiler supports __func__], tor_cv_have_func_macro, AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include int main(int c, char **v) { puts(__func__); }])], tor_cv_have_func_macro=yes, tor_cv_have_func_macro=no)) AC_CACHE_CHECK([whether the C compiler supports __FUNC__], tor_cv_have_FUNC_macro, AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include int main(int c, char **v) { puts(__FUNC__); }])], tor_cv_have_FUNC_macro=yes, tor_cv_have_FUNC_macro=no)) AC_CACHE_CHECK([whether the C compiler supports __FUNCTION__], tor_cv_have_FUNCTION_macro, AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include int main(int c, char **v) { puts(__FUNCTION__); }])], tor_cv_have_FUNCTION_macro=yes, tor_cv_have_FUNCTION_macro=no)) AC_CACHE_CHECK([whether we have extern char **environ already declared], tor_cv_have_environ_declared, AC_COMPILE_IFELSE([AC_LANG_SOURCE([ /* We define _GNU_SOURCE here because it is also defined in compat.c. * Without it environ doesn't get declared. */ #define _GNU_SOURCE #ifdef HAVE_UNISTD_H #include #endif #include int main(int c, char **v) { char **t = environ; }])], tor_cv_have_environ_declared=yes, tor_cv_have_environ_declared=no)) if test "$tor_cv_have_func_macro" = 'yes'; then AC_DEFINE(HAVE_MACRO__func__, 1, [Defined if the compiler supports __func__]) fi if test "$tor_cv_have_FUNC_macro" = 'yes'; then AC_DEFINE(HAVE_MACRO__FUNC__, 1, [Defined if the compiler supports __FUNC__]) fi if test "$tor_cv_have_FUNCTION_macro" = 'yes'; then AC_DEFINE(HAVE_MACRO__FUNCTION__, 1, [Defined if the compiler supports __FUNCTION__]) fi if test "$tor_cv_have_environ_declared" = 'yes'; then AC_DEFINE(HAVE_EXTERN_ENVIRON_DECLARED, 1, [Defined if we have extern char **environ already declared]) fi # $prefix stores the value of the --prefix command line option, or # NONE if the option wasn't set. In the case that it wasn't set, make # it be the default, so that we can use it to expand directories now. if test "x$prefix" = "xNONE"; then prefix=$ac_default_prefix fi # and similarly for $exec_prefix if test "x$exec_prefix" = "xNONE"; then exec_prefix=$prefix fi if test "x$BUILDDIR" = "x"; then BUILDDIR=`pwd` fi AC_SUBST(BUILDDIR) AH_TEMPLATE([BUILDDIR],[tor's build directory]) AC_DEFINE_UNQUOTED(BUILDDIR,"$BUILDDIR") if test "x$CONFDIR" = "x"; then CONFDIR=`eval echo $sysconfdir/tor` fi AC_SUBST(CONFDIR) AH_TEMPLATE([CONFDIR],[tor's configuration directory]) AC_DEFINE_UNQUOTED(CONFDIR,"$CONFDIR") BINDIR=`eval echo $bindir` AC_SUBST(BINDIR) LOCALSTATEDIR=`eval echo $localstatedir` AC_SUBST(LOCALSTATEDIR) if test "$bwin32" = true; then # Test if the linker supports the --nxcompat and --dynamicbase options # for Windows save_LDFLAGS="$LDFLAGS" LDFLAGS="-Wl,--nxcompat -Wl,--dynamicbase" AC_MSG_CHECKING([whether the linker supports DllCharacteristics]) AC_LINK_IFELSE([AC_LANG_PROGRAM([])], [AC_MSG_RESULT([yes])] [save_LDFLAGS="$save_LDFLAGS $LDFLAGS"], [AC_MSG_RESULT([no])] ) LDFLAGS="$save_LDFLAGS" fi # Set CFLAGS _after_ all the above checks, since our warnings are stricter # than autoconf's macros like. if test "$GCC" = yes; then # Disable GCC's strict aliasing checks. They are an hours-to-debug # accident waiting to happen. CFLAGS="$CFLAGS -Wall -fno-strict-aliasing" else # Autoconf sets -g -O2 by default. Override optimization level # for non-gcc compilers CFLAGS="$CFLAGS -O" enable_gcc_warnings=no enable_gcc_warnings_advisory=no fi # OS X Lion started deprecating the system openssl. Let's just disable # all deprecation warnings on OS X. Also, to potentially make the binary # a little smaller, let's enable dead_strip. case "$host_os" in darwin*) CFLAGS="$CFLAGS -Wno-deprecated-declarations" LDFLAGS="$LDFLAGS -dead_strip" ;; esac # Add some more warnings which we use in development but not in the # released versions. (Some relevant gcc versions can't handle these.) if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xyes; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) #error #endif])], have_gcc4=yes, have_gcc4=no) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) #error #endif])], have_gcc42=yes, have_gcc42=no) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) #error #endif])], have_gcc43=yes, have_gcc43=no) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wshorten-64-to-32" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])], have_shorten64_flag=yes, have_shorten64_flag=no) CFLAGS="$save_CFLAGS" case $host in *-*-openbsd* | *-*-bitrig*) # Some OpenBSD versions (like 4.8) have -Wsystem-headers by default. # That's fine, except that the headers don't pass -Wredundant-decls. # Therefore, let's disable -Wsystem-headers when we're building # with maximal warnings on OpenBSD. CFLAGS="$CFLAGS -Wno-system-headers" ;; esac CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith" CFLAGS="$CFLAGS -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings" CFLAGS="$CFLAGS -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat=2" CFLAGS="$CFLAGS -Wwrite-strings -Wmissing-declarations -Wredundant-decls" CFLAGS="$CFLAGS -Wnested-externs -Wbad-function-cast -Wswitch-enum" if test x$enable_gcc_warnings = xyes; then CFLAGS="$CFLAGS -Werror" fi # Disabled, so we can use mallinfo(): -Waggregate-return if test x$have_gcc4 = xyes ; then # These warnings break gcc 3.3.5 and work on gcc 4.0.2 CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement -Wold-style-definition" fi if test x$have_gcc42 = xyes ; then # These warnings break gcc 4.0.2 and work on gcc 4.2 # XXXX020 See if any of these work with earlier versions. CFLAGS="$CFLAGS -Waddress -Wmissing-noreturn -Wstrict-overflow=1" # We used to use -Wstrict-overflow=5, but that breaks us heavily under 4.3. fi if test x$have_gcc42 = xyes && test x$have_clang = xno; then # These warnings break gcc 4.0.2 and clang, but work on gcc 4.2 CFLAGS="$CFLAGS -Wnormalized=id -Woverride-init" fi if test x$have_gcc43 = xyes ; then # These warnings break gcc 4.2 and work on gcc 4.3 # XXXX020 See if any of these work with earlier versions. CFLAGS="$CFLAGS -Wextra -Warray-bounds" fi if test x$have_shorten64_flag = xyes ; then CFLAGS="$CFLAGS -Wshorten-64-to-32" fi ##This will break the world on some 64-bit architectures # CFLAGS="$CFLAGS -Winline" fi CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib" AC_CONFIG_FILES([ Doxyfile Makefile contrib/suse/tor.sh contrib/tor.logrotate contrib/tor.sh contrib/torctl contrib/torify src/config/torrc.sample ]) AC_OUTPUT if test -x /usr/bin/perl && test -x ./contrib/updateVersions.pl ; then ./contrib/updateVersions.pl fi tor-0.2.4.20/config.sub0000755000175000017500000010532712255745723011471 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-04-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: tor-0.2.4.20/configure0000755000175000017500000135761412255745715011427 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for tor 0.2.4.20. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tor' PACKAGE_TARNAME='tor' PACKAGE_VERSION='0.2.4.20' PACKAGE_STRING='tor 0.2.4.20' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="src/or/main.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS LOCALSTATEDIR BINDIR CONFDIR BUILDDIR LOGFACILITY CURVE25519_LIBS CURVE25519_ENABLED_FALSE CURVE25519_ENABLED_TRUE BUILD_CURVE25519_DONNA_C64_FALSE BUILD_CURVE25519_DONNA_C64_TRUE BUILD_CURVE25519_DONNA_FALSE BUILD_CURVE25519_DONNA_TRUE TOR_LDFLAGS_libminiupnpc TOR_CPPFLAGS_libminiupnpc TOR_LDFLAGS_libnatpmp TOR_CPPFLAGS_libnatpmp TOR_ZLIB_LIBS TOR_LDFLAGS_zlib TOR_CPPFLAGS_zlib TOR_OPENSSL_LIBS TOR_LDFLAGS_openssl TOR_CPPFLAGS_openssl TOR_LIB_MATH TOR_LIBEVENT_LIBS USE_BUFFEREVENTS_FALSE USE_BUFFEREVENTS_TRUE USE_EXTERNAL_EVDNS_FALSE USE_EXTERNAL_EVDNS_TRUE TOR_LDFLAGS_libevent TOR_CPPFLAGS_libevent TOR_LIB_IPHLPAPI TOR_LIB_GDI TOR_LIB_WS32 EGREP GREP BUILD_NT_SERVICES_FALSE BUILD_NT_SERVICES_TRUE TORGROUP TORUSER OPENSSL SHA1SUM MINIUPNPC_FALSE MINIUPNPC_TRUE NAT_PMP_FALSE NAT_PMP_TRUE USE_FW_HELPER_FALSE USE_FW_HELPER_TRUE USE_ASCIIDOC_FALSE USE_ASCIIDOC_TRUE A2X ASCIIDOC SED RANLIB CPP am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AR USE_OPENBSD_MALLOC_FALSE USE_OPENBSD_MALLOC_TRUE host_os host_vendor host_cpu host build_os build_vendor build_cpu build AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_buf_freelists enable_openbsd_malloc enable_instrument_downloads enable_static_openssl enable_static_libevent enable_static_zlib enable_static_tor enable_curve25519 enable_transparent enable_asciidoc enable_nat_pmp enable_upnp enable_threads enable_gcc_warnings enable_gcc_warnings_advisory enable_gcc_hardening enable_linker_hardening enable_local_appdata enable_tor2web_mode enable_bufferevents enable_dependency_tracking with_tor_user with_tor_group with_libevent_dir with_ssl_dir with_openssl_dir with_zlib_dir with_libnatpmp_dir with_libminiupnpc_dir enable_largefile with_dmalloc with_tcmalloc with_syslog_facility ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures tor 0.2.4.20 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/tor] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of tor 0.2.4.20:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: `make V=1') --disable-silent-rules verbose build output (undo: `make V=0') --disable-buf-freelists disable freelists for buffer RAM --enable-openbsd-malloc Use malloc code from openbsd. Linux only --enable-instrument-downloads Instrument downloads of directory resources etc. --enable-static-openssl Link against a static openssl library. Requires --with-openssl-dir --enable-static-libevent Link against a static libevent library. Requires --with-libevent-dir --enable-static-zlib Link against a static zlib library. Requires --with-zlib-dir --enable-static-tor Create an entirely static Tor binary. Requires --with-openssl-dir and --with-libevent-dir and --with-zlib-dir --disable-curve25519 Build Tor with no curve25519 elliptic-curve crypto support --disable-transparent disable transparent proxy support --disable-asciidoc don't use asciidoc (disables building of manpages) --enable-nat-pmp enable NAT-PMP support --enable-upnp enable UPnP support --disable-threads disable multi-threading support --enable-gcc-warnings enable verbose warnings --enable-gcc-warnings-advisory enable verbose warnings, excluding -Werror --disable-gcc-hardening disable compiler security checks --disable-linker-hardening disable linker security fixups --enable-local-appdata default to host local application data paths on Windows --enable-tor2web-mode support tor2web non-anonymous mode --enable-bufferevents use Libevent's buffered IO. --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --disable-largefile omit support for large files Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-tor-user=NAME Specify username for tor daemon --with-tor-group=NAME Specify group name for tor daemon --with-libevent-dir=PATH Specify path to libevent installation --with-ssl-dir=PATH Obsolete alias for --with-openssl-dir --with-openssl-dir=PATH Specify path to openssl installation --with-zlib-dir=PATH Specify path to zlib installation --with-libnatpmp-dir=PATH Specify path to libnatpmp installation --with-libminiupnpc-dir=PATH Specify path to libminiupnpc installation --with-dmalloc Use debug memory allocation library. --with-tcmalloc Use tcmalloc memory allocation library. --with-syslog-facility=LOG syslog facility to use (default=LOG_DAEMON) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF tor configure 0.2.4.20 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_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_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" 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=\$$4 { $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_member # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 &5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by tor $as_me 0.2.4.20, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.11' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='tor' VERSION='0.2.4.20' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=0;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' ac_config_headers="$ac_config_headers orconfig.h" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac if test -f /etc/redhat-release ; then if test -f /usr/kerberos/include ; then CPPFLAGS="$CPPFLAGS -I/usr/kerberos/include" fi fi # Not a no-op; we want to make sure that CPPFLAGS is set before we use # the += operator on it in src/or/Makefile.am CPPFLAGS="$CPPFLAGS -I\${top_srcdir}/src/common" #XXXX020 We should make these enabled or not, before 0.2.0.x-final # Check whether --enable-buf-freelists was given. if test "${enable_buf_freelists+set}" = set; then : enableval=$enable_buf_freelists; fi # Check whether --enable-openbsd-malloc was given. if test "${enable_openbsd_malloc+set}" = set; then : enableval=$enable_openbsd_malloc; fi # Check whether --enable-instrument-downloads was given. if test "${enable_instrument_downloads+set}" = set; then : enableval=$enable_instrument_downloads; fi # Check whether --enable-static-openssl was given. if test "${enable_static_openssl+set}" = set; then : enableval=$enable_static_openssl; fi # Check whether --enable-static-libevent was given. if test "${enable_static_libevent+set}" = set; then : enableval=$enable_static_libevent; fi # Check whether --enable-static-zlib was given. if test "${enable_static_zlib+set}" = set; then : enableval=$enable_static_zlib; fi # Check whether --enable-static-tor was given. if test "${enable_static_tor+set}" = set; then : enableval=$enable_static_tor; fi # Check whether --enable-curve25519 was given. if test "${enable_curve25519+set}" = set; then : enableval=$enable_curve25519; fi if test "$enable_static_tor" = "yes"; then enable_static_libevent="yes"; enable_static_openssl="yes"; enable_static_zlib="yes"; CFLAGS="$CFLAGS -static" fi if test x$enable_buf_freelists != xno; then $as_echo "#define ENABLE_BUF_FREELISTS 1" >>confdefs.h fi if test x$enable_openbsd_malloc = xyes; then USE_OPENBSD_MALLOC_TRUE= USE_OPENBSD_MALLOC_FALSE='#' else USE_OPENBSD_MALLOC_TRUE='#' USE_OPENBSD_MALLOC_FALSE= fi if test x$enable_instrument_downloads = xyes; then $as_echo "#define INSTRUMENT_DOWNLOADS 1" >>confdefs.h fi # Check whether --enable-transparent was given. if test "${enable_transparent+set}" = set; then : enableval=$enable_transparent; case "${enableval}" in yes) transparent=true ;; no) transparent=false ;; *) as_fn_error $? "bad value for --enable-transparent" "$LINENO" 5 ;; esac else transparent=true fi # Check whether --enable-asciidoc was given. if test "${enable_asciidoc+set}" = set; then : enableval=$enable_asciidoc; case "${enableval}" in yes) asciidoc=true ;; no) asciidoc=false ;; *) as_fn_error $? "bad value for --disable-asciidoc" "$LINENO" 5 ;; esac else asciidoc=true fi # By default, we're not ready to ship a NAT-PMP aware Tor # Check whether --enable-nat-pmp was given. if test "${enable_nat_pmp+set}" = set; then : enableval=$enable_nat_pmp; case "${enableval}" in yes) natpmp=true ;; no) natpmp=false ;; * ) as_fn_error $? "bad value for --enable-nat-pmp" "$LINENO" 5 ;; esac else natpmp=false fi # By default, we're not ready to ship a UPnP aware Tor # Check whether --enable-upnp was given. if test "${enable_upnp+set}" = set; then : enableval=$enable_upnp; case "${enableval}" in yes) upnp=true ;; no) upnp=false ;; * ) as_fn_error $? "bad value for --enable-upnp" "$LINENO" 5 ;; esac else upnp=false fi # Check whether --enable-threads was given. if test "${enable_threads+set}" = set; then : enableval=$enable_threads; fi if test x$enable_threads = x; then case $host in *-*-solaris* ) # Don't try multithreading on solaris -- cpuworkers seem to lock. { $as_echo "$as_me:${as_lineno-$LINENO}: You are running Solaris; Sometimes threading makes cpu workers lock up here, so I will disable threads." >&5 $as_echo "$as_me: You are running Solaris; Sometimes threading makes cpu workers lock up here, so I will disable threads." >&6;} enable_threads="no";; *) enable_threads="yes";; esac fi if test "$enable_threads" = "yes"; then $as_echo "#define ENABLE_THREADS 1" >>confdefs.h fi case $host in *-*-solaris* ) $as_echo "#define _REENTRANT 1" >>confdefs.h ;; esac # Check whether --enable-gcc-warnings was given. if test "${enable_gcc_warnings+set}" = set; then : enableval=$enable_gcc_warnings; fi # Check whether --enable-gcc-warnings-advisory was given. if test "${enable_gcc_warnings_advisory+set}" = set; then : enableval=$enable_gcc_warnings_advisory; fi # Check whether --enable-gcc-hardening was given. if test "${enable_gcc_hardening+set}" = set; then : enableval=$enable_gcc_hardening; fi # Check whether --enable-linker-hardening was given. if test "${enable_linker_hardening+set}" = set; then : enableval=$enable_linker_hardening; fi # Check whether --enable-local-appdata was given. if test "${enable_local_appdata+set}" = set; then : enableval=$enable_local_appdata; fi if test "$enable_local_appdata" = "yes"; then $as_echo "#define ENABLE_LOCAL_APPDATA 1" >>confdefs.h fi # Tor2web mode flag # Check whether --enable-tor2web-mode was given. if test "${enable_tor2web_mode+set}" = set; then : enableval=$enable_tor2web_mode; if test x$enableval = xyes; then CFLAGS="$CFLAGS -D ENABLE_TOR2WEB_MODE=1" fi fi # Check whether --enable-bufferevents was given. if test "${enable_bufferevents+set}" = set; then : enableval=$enable_bufferevents; fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="ar" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_SED+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$SED"; then ac_cv_prog_SED="$SED" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_SED="sed" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_SED" && ac_cv_prog_SED="/bin/false" fi fi SED=$ac_cv_prog_SED if test -n "$SED"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 $as_echo "$SED" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "asciidoc", so it can be a program name with args. set dummy asciidoc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ASCIIDOC+:} false; then : $as_echo_n "(cached) " >&6 else case $ASCIIDOC in [\\/]* | ?:[\\/]*) ac_cv_path_ASCIIDOC="$ASCIIDOC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ASCIIDOC="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_ASCIIDOC" && ac_cv_path_ASCIIDOC="none" ;; esac fi ASCIIDOC=$ac_cv_path_ASCIIDOC if test -n "$ASCIIDOC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ASCIIDOC" >&5 $as_echo "$ASCIIDOC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "a2x", so it can be a program name with args. set dummy a2x; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_A2X+:} false; then : $as_echo_n "(cached) " >&6 else case $A2X in [\\/]* | ?:[\\/]*) ac_cv_path_A2X="$A2X" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_A2X="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_A2X" && ac_cv_path_A2X="none" ;; esac fi A2X=$ac_cv_path_A2X if test -n "$A2X"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $A2X" >&5 $as_echo "$A2X" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x$asciidoc = xtrue; then USE_ASCIIDOC_TRUE= USE_ASCIIDOC_FALSE='#' else USE_ASCIIDOC_TRUE='#' USE_ASCIIDOC_FALSE= fi if test x$natpmp = xtrue || test x$upnp = xtrue; then USE_FW_HELPER_TRUE= USE_FW_HELPER_FALSE='#' else USE_FW_HELPER_TRUE='#' USE_FW_HELPER_FALSE= fi if test x$natpmp = xtrue; then NAT_PMP_TRUE= NAT_PMP_FALSE='#' else NAT_PMP_TRUE='#' NAT_PMP_FALSE= fi if test x$upnp = xtrue; then MINIUPNPC_TRUE= MINIUPNPC_FALSE='#' else MINIUPNPC_TRUE='#' MINIUPNPC_FALSE= fi if test "x$CC" != xcc; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 $as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 $as_echo_n "checking whether cc understands -c and -o together... " >&6; } fi set dummy $CC; ac_cc=`$as_echo "$2" | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` if eval \${ac_cv_prog_cc_${ac_cc}_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # We do the test twice because some compilers refuse to overwrite an # existing .o file with -o, though they will create one. ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -f conftest2.$ac_objext && { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then eval ac_cv_prog_cc_${ac_cc}_c_o=yes if test "x$CC" != xcc; then # Test first that cc exists at all. if { ac_try='cc -c conftest.$ac_ext >&5' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -f conftest2.$ac_objext && { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # cc works too. : else # cc exists but doesn't like -o. eval ac_cv_prog_cc_${ac_cc}_c_o=no fi fi fi else eval ac_cv_prog_cc_${ac_cc}_c_o=no fi rm -f core conftest* fi if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then { $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; } $as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h fi # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flexible array members" >&5 $as_echo_n "checking for flexible array members... " >&6; } if ${ac_cv_c_flexmember+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include struct s { int n; double d[]; }; int main () { int m = getchar (); struct s *p = malloc (offsetof (struct s, d) + m * sizeof (double)); p->d[0] = 0.0; return p->d != (double *) NULL; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flexmember=yes else ac_cv_c_flexmember=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flexmember" >&5 $as_echo "$ac_cv_c_flexmember" >&6; } if test $ac_cv_c_flexmember = yes; then $as_echo "#define FLEXIBLE_ARRAY_MEMBER /**/" >>confdefs.h else $as_echo "#define FLEXIBLE_ARRAY_MEMBER 1" >>confdefs.h fi # Extract the first word of "sha1sum", so it can be a program name with args. set dummy sha1sum; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SHA1SUM+:} false; then : $as_echo_n "(cached) " >&6 else case $SHA1SUM in [\\/]* | ?:[\\/]*) ac_cv_path_SHA1SUM="$SHA1SUM" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SHA1SUM="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_SHA1SUM" && ac_cv_path_SHA1SUM="none" ;; esac fi SHA1SUM=$ac_cv_path_SHA1SUM if test -n "$SHA1SUM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHA1SUM" >&5 $as_echo "$SHA1SUM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "openssl", so it can be a program name with args. set dummy openssl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_OPENSSL+:} false; then : $as_echo_n "(cached) " >&6 else case $OPENSSL in [\\/]* | ?:[\\/]*) ac_cv_path_OPENSSL="$OPENSSL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_OPENSSL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_OPENSSL" && ac_cv_path_OPENSSL="none" ;; esac fi OPENSSL=$ac_cv_path_OPENSSL if test -n "$OPENSSL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENSSL" >&5 $as_echo "$OPENSSL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi TORUSER=_tor # Check whether --with-tor-user was given. if test "${with_tor_user+set}" = set; then : withval=$with_tor_user; TORUSER=$withval fi TORGROUP=_tor # Check whether --with-tor-group was given. if test "${with_tor_group+set}" = set; then : withval=$with_tor_group; TORGROUP=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for win32" >&5 $as_echo_n "checking for win32... " >&6; } if test "$cross_compiling" = yes; then : bwin32=cross; { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross" >&5 $as_echo "cross" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(int c, char **v) { #ifdef _WIN32 #if _WIN32 return 0; #else return 1; #endif #else return 2; #endif } _ACEOF if ac_fn_c_try_run "$LINENO"; then : bwin32=true; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else bwin32=false; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$bwin32" = cross; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for win32 (cross)" >&5 $as_echo_n "checking for win32 (cross)... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef _WIN32 int main(int c, char **v) {return 0;} #else #error int main(int c, char **v) {return x(y);} #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : bwin32=true; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else bwin32=false; { $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$bwin32 = xtrue; then BUILD_NT_SERVICES_TRUE= BUILD_NT_SERVICES_FALSE='#' else BUILD_NT_SERVICES_TRUE='#' BUILD_NT_SERVICES_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MIPSpro compiler" >&5 $as_echo_n "checking for MIPSpro compiler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #if (defined(__sgi) && defined(_COMPILER_VERSION)) #error return x(y); #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : bmipspro=false; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else bmipspro=true; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$bmipspro" = true; then CFLAGS="$CFLAGS -c99" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no 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 if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no 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 if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 $as_echo_n "checking for library containing socket... " >&6; } if ${ac_cv_search_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF for ac_lib in '' socket network; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_socket=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_socket+:} false; then : break fi done if ${ac_cv_search_socket+:} false; then : else ac_cv_search_socket=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 $as_echo "$ac_cv_search_socket" >&6; } ac_res=$ac_cv_search_socket if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5 $as_echo_n "checking for library containing gethostbyname... " >&6; } if ${ac_cv_search_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_gethostbyname=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_gethostbyname+:} false; then : break fi done if ${ac_cv_search_gethostbyname+:} false; then : else ac_cv_search_gethostbyname=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5 $as_echo "$ac_cv_search_gethostbyname" >&6; } ac_res=$ac_cv_search_gethostbyname if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 $as_echo_n "checking for library containing dlopen... " >&6; } if ${ac_cv_search_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF for ac_lib in '' dl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_dlopen=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_dlopen+:} false; then : break fi done if ${ac_cv_search_dlopen+:} false; then : else ac_cv_search_dlopen=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 $as_echo "$ac_cv_search_dlopen" >&6; } ac_res=$ac_cv_search_dlopen if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_aton" >&5 $as_echo_n "checking for library containing inet_aton... " >&6; } if ${ac_cv_search_inet_aton+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_aton (); int main () { return inet_aton (); ; return 0; } _ACEOF for ac_lib in '' resolv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_inet_aton=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_inet_aton+:} false; then : break fi done if ${ac_cv_search_inet_aton+:} false; then : else ac_cv_search_inet_aton=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5 $as_echo "$ac_cv_search_inet_aton" >&6; } ac_res=$ac_cv_search_inet_aton if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi saved_LIBS="$LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 $as_echo_n "checking for library containing clock_gettime... " >&6; } if ${ac_cv_search_clock_gettime+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_clock_gettime+:} false; then : break fi done if ${ac_cv_search_clock_gettime+:} false; then : else ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 $as_echo "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi if test "$LIBS" != "$saved_LIBS"; then # Looks like we need -lrt for clock_gettime(). have_rt=yes fi if test "$enable_threads" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 $as_echo_n "checking for library containing pthread_create... " >&6; } if ${ac_cv_search_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF for ac_lib in '' pthread; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_pthread_create=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_pthread_create+:} false; then : break fi done if ${ac_cv_search_pthread_create+:} false; then : else ac_cv_search_pthread_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 $as_echo "$ac_cv_search_pthread_create" >&6; } ac_res=$ac_cv_search_pthread_create if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_detach" >&5 $as_echo_n "checking for library containing pthread_detach... " >&6; } if ${ac_cv_search_pthread_detach+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_detach (); int main () { return pthread_detach (); ; return 0; } _ACEOF for ac_lib in '' pthread; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_pthread_detach=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_pthread_detach+:} false; then : break fi done if ${ac_cv_search_pthread_detach+:} false; then : else ac_cv_search_pthread_detach=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_detach" >&5 $as_echo "$ac_cv_search_pthread_detach" >&6; } ac_res=$ac_cv_search_pthread_detach if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi for ac_func in _NSGetEnviron \ accept4 \ clock_gettime \ flock \ ftime \ getaddrinfo \ getifaddrs \ getrlimit \ gettimeofday \ gmtime_r \ inet_aton \ ioctl \ issetugid \ llround \ localtime_r \ lround \ memmem \ prctl \ rint \ socketpair \ strlcat \ strlcpy \ strptime \ strtok_r \ strtoull \ sysconf \ uname \ vasprintf \ _vscprintf 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 if test "$enable_threads" = "yes"; then 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 fi done for ac_func in pthread_create do : ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" if test "x$ac_cv_func_pthread_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_CREATE 1 _ACEOF fi done fi if test "$bwin32" = true; then TOR_LIB_WS32=-lws2_32 TOR_LIB_IPHLPAPI=-liphlpapi # Some of the cargo-cults recommend -lwsock32 as well, but I don't # think it's actually necessary. TOR_LIB_GDI=-lgdi32 else TOR_LIB_WS32= TOR_LIB_GDI= fi for ac_header in sys/types.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" if test "x$ac_cv_header_sys_types_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_TYPES_H 1 _ACEOF fi done ac_fn_c_check_type "$LINENO" "u_int64_t" "ac_cv_type_u_int64_t" "$ac_includes_default" if test "x$ac_cv_type_u_int64_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define u_int64_t unsigned long long _ACEOF fi ac_fn_c_check_type "$LINENO" "u_int32_t" "ac_cv_type_u_int32_t" "$ac_includes_default" if test "x$ac_cv_type_u_int32_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define u_int32_t unsigned long _ACEOF fi ac_fn_c_check_type "$LINENO" "u_int16_t" "ac_cv_type_u_int16_t" "$ac_includes_default" if test "x$ac_cv_type_u_int16_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define u_int16_t unsigned short _ACEOF fi ac_fn_c_check_type "$LINENO" "u_int8_t" "ac_cv_type_u_int8_t" "$ac_includes_default" if test "x$ac_cv_type_u_int8_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define u_int8_t unsigned char _ACEOF fi tor_libevent_pkg_redhat="libevent" tor_libevent_pkg_debian="libevent-dev" tor_libevent_devpkg_redhat="libevent-devel" tor_libevent_devpkg_debian="libevent-dev" STATIC_LIBEVENT_FLAGS="" if test "$enable_static_libevent" = "yes"; then if test "$have_rt" = yes; then STATIC_LIBEVENT_FLAGS=" -lrt " fi fi trylibeventdir="" # Check whether --with-libevent-dir was given. if test "${with_libevent_dir+set}" = set; then : withval=$with_libevent_dir; if test x$withval != xno ; then trylibeventdir="$withval" fi fi if test "x$trylibeventdir" = x && test "x$ALT_libevent_WITHVAL" != x ; then trylibeventdir="$ALT_libevent_WITHVAL" fi tor_saved_LIBS="$LIBS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_CPPFLAGS="$CPPFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libevent directory" >&5 $as_echo_n "checking for libevent directory... " >&6; } if ${tor_cv_library_libevent_dir+:} false; then : $as_echo_n "(cached) " >&6 else tor_libevent_dir_found=no tor_libevent_any_linkable=no for tor_trydir in "$trylibeventdir" "(system)" "$prefix" /usr/local /usr/pkg /opt/libevent; do LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS -levent $STATIC_LIBEVENT_FLAGS $TOR_LIB_WS32" CPPFLAGS="$tor_saved_CPPFLAGS" if test -z "$tor_trydir" ; then continue; fi # Skip the directory if it isn't there. if test ! -d "$tor_trydir" && test "$tor_trydir" != "(system)"; then continue; fi # If this isn't blank, try adding the directory (or appropriate # include/libs subdirectories) to the command line. if test "$tor_trydir" != "(system)"; then if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi if test -d "$tor_trydir/include"; then CPPFLAGS="-I$tor_trydir/include $CPPFLAGS" else CPPFLAGS="-I$tor_trydir $CPPFLAGS" fi fi # Can we link against (but not necessarily run, or find the headers for) # the binary? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef _WIN32 #include #endif void exit(int); void *event_init(void); int main () { #ifdef _WIN32 {WSADATA d; WSAStartup(0x101,&d); } #endif event_init(); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : linkable=yes else linkable=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$linkable" = yes; then tor_libevent_any_linkable=yes # Okay, we can link against it. Can we find the headers? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef _WIN32 #include #endif #include #include #include #include int main () { #ifdef _WIN32 {WSADATA d; WSAStartup(0x101,&d); } #endif event_init(); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : buildable=yes else buildable=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$buildable" = yes; then tor_cv_library_libevent_dir=$tor_trydir tor_libevent_dir_found=yes break fi fi done if test "$tor_libevent_dir_found" = no; then if test "$tor_libevent_any_linkable" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find a linkable libevent. If you have it installed somewhere unusual, you can specify an explicit path using --with-libevent-dir" >&5 $as_echo "$as_me: WARNING: Could not find a linkable libevent. If you have it installed somewhere unusual, you can specify an explicit path using --with-libevent-dir" >&2;} h="" if test xpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_libevent_pkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h libevent using \"apt-get install $tor_libevent_pkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h libevent using \"apt-get install $tor_libevent_pkg_debian\"" >&2;} if test x"$tor_libevent_pkg_debian" != x"$tor_libevent_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_libevent_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_libevent_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_libevent_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h libevent using \"yum install $tor_libevent_pkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h libevent using \"yum install $tor_libevent_pkg_redhat\"" >&2;} if test x"$tor_libevent_pkg_redhat" != x"$tor_libevent_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libevent_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libevent_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_libevent_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h libevent by installing the $tor_libevent_pkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h libevent by installing the $tor_libevent_pkg_redhat\" RPM package" >&2;} if test x"$tor_libevent_pkg_redhat" != x"$tor_libevent_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libevent_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libevent_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing libraries; unable to proceed." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: We found the libraries for libevent, but we could not find the C header files. You may need to install a devel package." >&5 $as_echo "$as_me: WARNING: We found the libraries for libevent, but we could not find the C header files. You may need to install a devel package." >&2;} h="" if test xdevpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_libevent_devpkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h libevent using \"apt-get install $tor_libevent_devpkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h libevent using \"apt-get install $tor_libevent_devpkg_debian\"" >&2;} if test x"$tor_libevent_devpkg_debian" != x"$tor_libevent_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_libevent_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_libevent_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_libevent_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h libevent using \"yum install $tor_libevent_devpkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h libevent using \"yum install $tor_libevent_devpkg_redhat\"" >&2;} if test x"$tor_libevent_devpkg_redhat" != x"$tor_libevent_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libevent_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libevent_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_libevent_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h libevent by installing the $tor_libevent_devpkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h libevent by installing the $tor_libevent_devpkg_redhat\" RPM package" >&2;} if test x"$tor_libevent_devpkg_redhat" != x"$tor_libevent_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libevent_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libevent_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing headers; unable to proceed." "$LINENO" 5 fi fi LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" CPPFLAGS="$tor_saved_CPPFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_libevent_dir" >&5 $as_echo "$tor_cv_library_libevent_dir" >&6; } LIBS="$LIBS -levent $STATIC_LIBEVENT_FLAGS $TOR_LIB_WS32" if test "$tor_cv_library_libevent_dir" != "(system)"; then if test -d "$tor_cv_library_libevent_dir/lib"; then LDFLAGS="-L$tor_cv_library_libevent_dir/lib $LDFLAGS" else LDFLAGS="-L$tor_cv_library_libevent_dir $LDFLAGS" fi if test -d "$tor_cv_library_libevent_dir/include"; then CPPFLAGS="-I$tor_cv_library_libevent_dir/include $CPPFLAGS" else CPPFLAGS="-I$tor_cv_library_libevent_dir $CPPFLAGS" fi fi if test x$tor_cv_library_libevent_dir = "x(system)"; then TOR_LDFLAGS_libevent="" TOR_CPPFLAGS_libevent="" else if test -d "$tor_cv_library_libevent_dir/lib"; then TOR_LDFLAGS_libevent="-L$tor_cv_library_libevent_dir/lib" TOR_LIBDIR_libevent="$tor_cv_library_libevent_dir/lib" else TOR_LDFLAGS_libevent="-L$tor_cv_library_libevent_dir" TOR_LIBDIR_libevent="$tor_cv_library_libevent_dir" fi if test -d "$tor_cv_library_libevent_dir/include"; then TOR_CPPFLAGS_libevent="-I$tor_cv_library_libevent_dir/include" else TOR_CPPFLAGS_libevent="-I$tor_cv_library_libevent_dir" fi fi if test "$cross_compiling" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need extra options to link libevent" >&5 $as_echo_n "checking whether we need extra options to link libevent... " >&6; } if ${tor_cv_library_libevent_linker_option+:} false; then : $as_echo_n "(cached) " >&6 else orig_LDFLAGS="$LDFLAGS" runs=no linked_with=nothing if test -d "$tor_cv_library_libevent_dir/lib"; then tor_trydir="$tor_cv_library_libevent_dir/lib" else tor_trydir="$tor_cv_library_libevent_dir" fi for tor_tryextra in "(none)" "-Wl,-R$tor_trydir" "-R$tor_trydir" \ "-Wl,-rpath,$tor_trydir" ; do if test "$tor_tryextra" = "(none)"; then LDFLAGS="$orig_LDFLAGS" else LDFLAGS="$tor_tryextra $orig_LDFLAGS" fi 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. */ #ifdef _WIN32 #include #endif void exit(int); void *event_init(void); int main () { #ifdef _WIN32 {WSADATA d; WSAStartup(0x101,&d); } #endif event_init(); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : runnable=yes else runnable=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$runnable" = yes; then tor_cv_library_libevent_linker_option=$tor_tryextra break fi done if test "$runnable" = no; then as_fn_error $? "Found linkable libevent in $tor_cv_library_libevent_dir, but it does not seem to run, even with -R. Maybe specify another using --with-libevent-dir}" "$LINENO" 5 fi LDFLAGS="$orig_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_libevent_linker_option" >&5 $as_echo "$tor_cv_library_libevent_linker_option" >&6; } if test "$tor_cv_library_libevent_linker_option" != "(none)" ; then TOR_LDFLAGS_libevent="$TOR_LDFLAGS_libevent $tor_cv_library_libevent_linker_option" fi fi # cross-compile LIBS="$tor_saved_LIBS" LDFLAGS="$tor_saved_LDFLAGS" CPPFLAGS="$tor_saved_CPPFLAGS" save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LIBS="-levent $STATIC_LIBEVENT_FLAGS $TOR_LIB_WS32 $LIBS" LDFLAGS="$TOR_LDFLAGS_libevent $LDFLAGS" CPPFLAGS="$TOR_CPPFLAGS_libevent $CPPFLAGS" for ac_func in event_get_version event_get_version_number event_get_method event_set_log_callback evdns_set_outgoing_bind_address event_base_loopexit 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 ac_fn_c_check_member "$LINENO" "struct event" "min_heap_idx" "ac_cv_member_struct_event_min_heap_idx" "#include " if test "x$ac_cv_member_struct_event_min_heap_idx" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_EVENT_MIN_HEAP_IDX 1 _ACEOF fi for ac_header in event2/event.h event2/dns.h event2/bufferevent_ssl.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" CPPFLAGS="$save_CPPFLAGS" if test x$ac_cv_header_event2_dns_h = xyes; then USE_EXTERNAL_EVDNS_TRUE= USE_EXTERNAL_EVDNS_FALSE='#' else USE_EXTERNAL_EVDNS_TRUE='#' USE_EXTERNAL_EVDNS_FALSE= fi if test "$enable_static_libevent" = "yes"; then if test "$tor_cv_library_libevent_dir" = "(system)"; then as_fn_error $? "\"You must specify an explicit --with-libevent-dir=x option when using --enable-static-libevent\"" "$LINENO" 5 else TOR_LIBEVENT_LIBS="$TOR_LIBDIR_libevent/libevent.a $STATIC_LIBEVENT_FLAGS" fi else TOR_LIBEVENT_LIBS="-levent" fi if test "$enable_bufferevents" = "yes" ; then if test "$ac_cv_header_event2_bufferevent_ssl_h" != "yes" ; then as_fn_error $? "You've asked for bufferevent support, but you're using a version of Libevent without SSL support. This won't work. We need Libevent 2.0.8-rc or later, and you don't seem to even have Libevent 2.0.3-alpha." "$LINENO" 5 else CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent" # Check for the right version. First see if version detection works. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can detect the Libevent version" >&5 $as_echo_n "checking whether we can detect the Libevent version... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if !defined(LIBEVENT_VERSION_NUMBER) || LIBEVENT_VERSION_NUMBER < 10 #error int x = y(zz); #else int x = 1; #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : event_version_number_works=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else event_version_number_works=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_ext if test "$event_version_number_works" != 'yes'; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Version detection on Libevent seems broken. Your Libevent installation is probably screwed up or very old." >&5 $as_echo "$as_me: WARNING: Version detection on Libevent seems broken. Your Libevent installation is probably screwed up or very old." >&2;} else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Libevent is new enough for bufferevents" >&5 $as_echo_n "checking whether Libevent is new enough for bufferevents... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if !defined(LIBEVENT_VERSION_NUMBER) || LIBEVENT_VERSION_NUMBER < 0x02000d00 #error int x = y(zz); #else int x = 1; #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $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; } as_fn_error $? "Libevent does not seem new enough to support bufferevents. We require 2.0.13-stable or later" "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi fi fi LIBS="$save_LIBS" LDFLAGS="$save_LDFLAGS" CPPFLAGS="$save_CPPFLAGS" if test "$enable_bufferevents" = "yes"; then USE_BUFFEREVENTS_TRUE= USE_BUFFEREVENTS_FALSE='#' else USE_BUFFEREVENTS_TRUE='#' USE_BUFFEREVENTS_FALSE= fi if test "$enable_bufferevents" = "yes"; then $as_echo "#define USE_BUFFEREVENTS 1" >>confdefs.h if test "$enable_static_libevent" = "yes"; then TOR_LIBEVENT_LIBS="$TOR_LIBDIR_libevent/libevent_openssl.a $TOR_LIBEVENT_LIBS" else TOR_LIBEVENT_LIBS="-levent_openssl $TOR_LIBEVENT_LIBS" fi fi TOR_LIB_MATH="" save_LIBS="$LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pow" >&5 $as_echo_n "checking for library containing pow... " >&6; } if ${ac_cv_search_pow+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF for ac_lib in '' m; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_pow=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_pow+:} false; then : break fi done if ${ac_cv_search_pow+:} false; then : else ac_cv_search_pow=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pow" >&5 $as_echo "$ac_cv_search_pow" >&6; } ac_res=$ac_cv_search_pow if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else as_fn_error $? "Could not find pow in libm or libc." "$LINENO" 5 fi if test "$ac_cv_search_pow" != "none required"; then TOR_LIB_MATH="$ac_cv_search_pow" fi LIBS="$save_LIBS" tor_openssl_pkg_redhat="openssl" tor_openssl_pkg_debian="libssl" tor_openssl_devpkg_redhat="openssl-devel" tor_openssl_devpkg_debian="libssl-dev" ALT_openssl_WITHVAL="" # Check whether --with-ssl-dir was given. if test "${with_ssl_dir+set}" = set; then : withval=$with_ssl_dir; if test "x$withval" != xno && test "x$withval" != "x" ; then ALT_openssl_WITHVAL="$withval" fi fi tryopenssldir="" # Check whether --with-openssl-dir was given. if test "${with_openssl_dir+set}" = set; then : withval=$with_openssl_dir; if test x$withval != xno ; then tryopenssldir="$withval" fi fi if test "x$tryopenssldir" = x && test "x$ALT_openssl_WITHVAL" != x ; then tryopenssldir="$ALT_openssl_WITHVAL" fi tor_saved_LIBS="$LIBS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_CPPFLAGS="$CPPFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl directory" >&5 $as_echo_n "checking for openssl directory... " >&6; } if ${tor_cv_library_openssl_dir+:} false; then : $as_echo_n "(cached) " >&6 else tor_openssl_dir_found=no tor_openssl_any_linkable=no for tor_trydir in "$tryopenssldir" "(system)" "$prefix" /usr/local /usr/pkg /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/athena /opt/openssl; do LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS -lssl -lcrypto $TOR_LIB_GDI" CPPFLAGS="$tor_saved_CPPFLAGS" if test -z "$tor_trydir" ; then continue; fi # Skip the directory if it isn't there. if test ! -d "$tor_trydir" && test "$tor_trydir" != "(system)"; then continue; fi # If this isn't blank, try adding the directory (or appropriate # include/libs subdirectories) to the command line. if test "$tor_trydir" != "(system)"; then if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi if test -d "$tor_trydir/include"; then CPPFLAGS="-I$tor_trydir/include $CPPFLAGS" else CPPFLAGS="-I$tor_trydir $CPPFLAGS" fi fi # Can we link against (but not necessarily run, or find the headers for) # the binary? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ void RAND_add(const void *buf, int num, double entropy); int main () { RAND_add((void*)0,0,0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : linkable=yes else linkable=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$linkable" = yes; then tor_openssl_any_linkable=yes # Okay, we can link against it. Can we find the headers? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { RAND_add((void*)0,0,0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : buildable=yes else buildable=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$buildable" = yes; then tor_cv_library_openssl_dir=$tor_trydir tor_openssl_dir_found=yes break fi fi done if test "$tor_openssl_dir_found" = no; then if test "$tor_openssl_any_linkable" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find a linkable openssl. If you have it installed somewhere unusual, you can specify an explicit path using --with-openssl-dir" >&5 $as_echo "$as_me: WARNING: Could not find a linkable openssl. If you have it installed somewhere unusual, you can specify an explicit path using --with-openssl-dir" >&2;} h="" if test xpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_openssl_pkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h openssl using \"apt-get install $tor_openssl_pkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h openssl using \"apt-get install $tor_openssl_pkg_debian\"" >&2;} if test x"$tor_openssl_pkg_debian" != x"$tor_openssl_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_openssl_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_openssl_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_openssl_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h openssl using \"yum install $tor_openssl_pkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h openssl using \"yum install $tor_openssl_pkg_redhat\"" >&2;} if test x"$tor_openssl_pkg_redhat" != x"$tor_openssl_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_openssl_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_openssl_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_openssl_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h openssl by installing the $tor_openssl_pkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h openssl by installing the $tor_openssl_pkg_redhat\" RPM package" >&2;} if test x"$tor_openssl_pkg_redhat" != x"$tor_openssl_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_openssl_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_openssl_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing libraries; unable to proceed." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: We found the libraries for openssl, but we could not find the C header files. You may need to install a devel package." >&5 $as_echo "$as_me: WARNING: We found the libraries for openssl, but we could not find the C header files. You may need to install a devel package." >&2;} h="" if test xdevpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_openssl_devpkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h openssl using \"apt-get install $tor_openssl_devpkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h openssl using \"apt-get install $tor_openssl_devpkg_debian\"" >&2;} if test x"$tor_openssl_devpkg_debian" != x"$tor_openssl_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_openssl_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_openssl_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_openssl_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h openssl using \"yum install $tor_openssl_devpkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h openssl using \"yum install $tor_openssl_devpkg_redhat\"" >&2;} if test x"$tor_openssl_devpkg_redhat" != x"$tor_openssl_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_openssl_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_openssl_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_openssl_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h openssl by installing the $tor_openssl_devpkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h openssl by installing the $tor_openssl_devpkg_redhat\" RPM package" >&2;} if test x"$tor_openssl_devpkg_redhat" != x"$tor_openssl_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_openssl_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_openssl_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing headers; unable to proceed." "$LINENO" 5 fi fi LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" CPPFLAGS="$tor_saved_CPPFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_openssl_dir" >&5 $as_echo "$tor_cv_library_openssl_dir" >&6; } LIBS="$LIBS -lssl -lcrypto $TOR_LIB_GDI" if test "$tor_cv_library_openssl_dir" != "(system)"; then if test -d "$tor_cv_library_openssl_dir/lib"; then LDFLAGS="-L$tor_cv_library_openssl_dir/lib $LDFLAGS" else LDFLAGS="-L$tor_cv_library_openssl_dir $LDFLAGS" fi if test -d "$tor_cv_library_openssl_dir/include"; then CPPFLAGS="-I$tor_cv_library_openssl_dir/include $CPPFLAGS" else CPPFLAGS="-I$tor_cv_library_openssl_dir $CPPFLAGS" fi fi if test x$tor_cv_library_openssl_dir = "x(system)"; then TOR_LDFLAGS_openssl="" TOR_CPPFLAGS_openssl="" else if test -d "$tor_cv_library_openssl_dir/lib"; then TOR_LDFLAGS_openssl="-L$tor_cv_library_openssl_dir/lib" TOR_LIBDIR_openssl="$tor_cv_library_openssl_dir/lib" else TOR_LDFLAGS_openssl="-L$tor_cv_library_openssl_dir" TOR_LIBDIR_openssl="$tor_cv_library_openssl_dir" fi if test -d "$tor_cv_library_openssl_dir/include"; then TOR_CPPFLAGS_openssl="-I$tor_cv_library_openssl_dir/include" else TOR_CPPFLAGS_openssl="-I$tor_cv_library_openssl_dir" fi fi if test "$cross_compiling" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need extra options to link openssl" >&5 $as_echo_n "checking whether we need extra options to link openssl... " >&6; } if ${tor_cv_library_openssl_linker_option+:} false; then : $as_echo_n "(cached) " >&6 else orig_LDFLAGS="$LDFLAGS" runs=no linked_with=nothing if test -d "$tor_cv_library_openssl_dir/lib"; then tor_trydir="$tor_cv_library_openssl_dir/lib" else tor_trydir="$tor_cv_library_openssl_dir" fi for tor_tryextra in "(none)" "-Wl,-R$tor_trydir" "-R$tor_trydir" \ "-Wl,-rpath,$tor_trydir" ; do if test "$tor_tryextra" = "(none)"; then LDFLAGS="$orig_LDFLAGS" else LDFLAGS="$tor_tryextra $orig_LDFLAGS" fi 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. */ void RAND_add(const void *buf, int num, double entropy); int main () { RAND_add((void*)0,0,0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : runnable=yes else runnable=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$runnable" = yes; then tor_cv_library_openssl_linker_option=$tor_tryextra break fi done if test "$runnable" = no; then as_fn_error $? "Found linkable openssl in $tor_cv_library_openssl_dir, but it does not seem to run, even with -R. Maybe specify another using --with-openssl-dir}" "$LINENO" 5 fi LDFLAGS="$orig_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_openssl_linker_option" >&5 $as_echo "$tor_cv_library_openssl_linker_option" >&6; } if test "$tor_cv_library_openssl_linker_option" != "(none)" ; then TOR_LDFLAGS_openssl="$TOR_LDFLAGS_openssl $tor_cv_library_openssl_linker_option" fi fi # cross-compile LIBS="$tor_saved_LIBS" LDFLAGS="$tor_saved_LDFLAGS" CPPFLAGS="$tor_saved_CPPFLAGS" if test "$enable_static_openssl" = "yes"; then if test "$tor_cv_library_openssl_dir" = "(system)"; then as_fn_error $? "\"You must specify an explicit --with-openssl-dir=x option when using --enable-static-openssl\"" "$LINENO" 5 else TOR_OPENSSL_LIBS="$TOR_LIBDIR_openssl/libssl.a $TOR_LIBDIR_openssl/libcrypto.a" fi else TOR_OPENSSL_LIBS="-lssl -lcrypto" fi tor_zlib_pkg_redhat="zlib" tor_zlib_pkg_debian="zlib1g" tor_zlib_devpkg_redhat="zlib-devel" tor_zlib_devpkg_debian="zlib1g-dev" tryzlibdir="" # Check whether --with-zlib-dir was given. if test "${with_zlib_dir+set}" = set; then : withval=$with_zlib_dir; if test x$withval != xno ; then tryzlibdir="$withval" fi fi if test "x$tryzlibdir" = x && test "x$ALT_zlib_WITHVAL" != x ; then tryzlibdir="$ALT_zlib_WITHVAL" fi tor_saved_LIBS="$LIBS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_CPPFLAGS="$CPPFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for zlib directory" >&5 $as_echo_n "checking for zlib directory... " >&6; } if ${tor_cv_library_zlib_dir+:} false; then : $as_echo_n "(cached) " >&6 else tor_zlib_dir_found=no tor_zlib_any_linkable=no for tor_trydir in "$tryzlibdir" "(system)" "$prefix" /usr/local /usr/pkg /opt/zlib; do LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS -lz" CPPFLAGS="$tor_saved_CPPFLAGS" if test -z "$tor_trydir" ; then continue; fi # Skip the directory if it isn't there. if test ! -d "$tor_trydir" && test "$tor_trydir" != "(system)"; then continue; fi # If this isn't blank, try adding the directory (or appropriate # include/libs subdirectories) to the command line. if test "$tor_trydir" != "(system)"; then if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi if test -d "$tor_trydir/include"; then CPPFLAGS="-I$tor_trydir/include $CPPFLAGS" else CPPFLAGS="-I$tor_trydir $CPPFLAGS" fi fi # Can we link against (but not necessarily run, or find the headers for) # the binary? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ const char * zlibVersion(void); int main () { zlibVersion(); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : linkable=yes else linkable=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$linkable" = yes; then tor_zlib_any_linkable=yes # Okay, we can link against it. Can we find the headers? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { zlibVersion(); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : buildable=yes else buildable=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$buildable" = yes; then tor_cv_library_zlib_dir=$tor_trydir tor_zlib_dir_found=yes break fi fi done if test "$tor_zlib_dir_found" = no; then if test "$tor_zlib_any_linkable" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find a linkable zlib. If you have it installed somewhere unusual, you can specify an explicit path using --with-zlib-dir" >&5 $as_echo "$as_me: WARNING: Could not find a linkable zlib. If you have it installed somewhere unusual, you can specify an explicit path using --with-zlib-dir" >&2;} h="" if test xpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_zlib_pkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h zlib using \"apt-get install $tor_zlib_pkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h zlib using \"apt-get install $tor_zlib_pkg_debian\"" >&2;} if test x"$tor_zlib_pkg_debian" != x"$tor_zlib_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_zlib_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_zlib_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_zlib_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h zlib using \"yum install $tor_zlib_pkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h zlib using \"yum install $tor_zlib_pkg_redhat\"" >&2;} if test x"$tor_zlib_pkg_redhat" != x"$tor_zlib_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_zlib_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_zlib_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_zlib_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h zlib by installing the $tor_zlib_pkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h zlib by installing the $tor_zlib_pkg_redhat\" RPM package" >&2;} if test x"$tor_zlib_pkg_redhat" != x"$tor_zlib_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_zlib_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_zlib_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing libraries; unable to proceed." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: We found the libraries for zlib, but we could not find the C header files. You may need to install a devel package." >&5 $as_echo "$as_me: WARNING: We found the libraries for zlib, but we could not find the C header files. You may need to install a devel package." >&2;} h="" if test xdevpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_zlib_devpkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h zlib using \"apt-get install $tor_zlib_devpkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h zlib using \"apt-get install $tor_zlib_devpkg_debian\"" >&2;} if test x"$tor_zlib_devpkg_debian" != x"$tor_zlib_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_zlib_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_zlib_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_zlib_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h zlib using \"yum install $tor_zlib_devpkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h zlib using \"yum install $tor_zlib_devpkg_redhat\"" >&2;} if test x"$tor_zlib_devpkg_redhat" != x"$tor_zlib_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_zlib_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_zlib_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_zlib_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h zlib by installing the $tor_zlib_devpkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h zlib by installing the $tor_zlib_devpkg_redhat\" RPM package" >&2;} if test x"$tor_zlib_devpkg_redhat" != x"$tor_zlib_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_zlib_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_zlib_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing headers; unable to proceed." "$LINENO" 5 fi fi LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" CPPFLAGS="$tor_saved_CPPFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_zlib_dir" >&5 $as_echo "$tor_cv_library_zlib_dir" >&6; } LIBS="$LIBS -lz" if test "$tor_cv_library_zlib_dir" != "(system)"; then if test -d "$tor_cv_library_zlib_dir/lib"; then LDFLAGS="-L$tor_cv_library_zlib_dir/lib $LDFLAGS" else LDFLAGS="-L$tor_cv_library_zlib_dir $LDFLAGS" fi if test -d "$tor_cv_library_zlib_dir/include"; then CPPFLAGS="-I$tor_cv_library_zlib_dir/include $CPPFLAGS" else CPPFLAGS="-I$tor_cv_library_zlib_dir $CPPFLAGS" fi fi if test x$tor_cv_library_zlib_dir = "x(system)"; then TOR_LDFLAGS_zlib="" TOR_CPPFLAGS_zlib="" else if test -d "$tor_cv_library_zlib_dir/lib"; then TOR_LDFLAGS_zlib="-L$tor_cv_library_zlib_dir/lib" TOR_LIBDIR_zlib="$tor_cv_library_zlib_dir/lib" else TOR_LDFLAGS_zlib="-L$tor_cv_library_zlib_dir" TOR_LIBDIR_zlib="$tor_cv_library_zlib_dir" fi if test -d "$tor_cv_library_zlib_dir/include"; then TOR_CPPFLAGS_zlib="-I$tor_cv_library_zlib_dir/include" else TOR_CPPFLAGS_zlib="-I$tor_cv_library_zlib_dir" fi fi if test "$cross_compiling" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need extra options to link zlib" >&5 $as_echo_n "checking whether we need extra options to link zlib... " >&6; } if ${tor_cv_library_zlib_linker_option+:} false; then : $as_echo_n "(cached) " >&6 else orig_LDFLAGS="$LDFLAGS" runs=no linked_with=nothing if test -d "$tor_cv_library_zlib_dir/lib"; then tor_trydir="$tor_cv_library_zlib_dir/lib" else tor_trydir="$tor_cv_library_zlib_dir" fi for tor_tryextra in "(none)" "-Wl,-R$tor_trydir" "-R$tor_trydir" \ "-Wl,-rpath,$tor_trydir" ; do if test "$tor_tryextra" = "(none)"; then LDFLAGS="$orig_LDFLAGS" else LDFLAGS="$tor_tryextra $orig_LDFLAGS" fi 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. */ const char * zlibVersion(void); int main () { zlibVersion(); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : runnable=yes else runnable=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$runnable" = yes; then tor_cv_library_zlib_linker_option=$tor_tryextra break fi done if test "$runnable" = no; then as_fn_error $? "Found linkable zlib in $tor_cv_library_zlib_dir, but it does not seem to run, even with -R. Maybe specify another using --with-zlib-dir}" "$LINENO" 5 fi LDFLAGS="$orig_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_zlib_linker_option" >&5 $as_echo "$tor_cv_library_zlib_linker_option" >&6; } if test "$tor_cv_library_zlib_linker_option" != "(none)" ; then TOR_LDFLAGS_zlib="$TOR_LDFLAGS_zlib $tor_cv_library_zlib_linker_option" fi fi # cross-compile LIBS="$tor_saved_LIBS" LDFLAGS="$tor_saved_LDFLAGS" CPPFLAGS="$tor_saved_CPPFLAGS" if test "$enable_static_zlib" = "yes"; then if test "$tor_cv_library_zlib_dir" = "(system)"; then as_fn_error $? "\"You must specify an explicit --with-zlib-dir=x option when using --enable-static-zlib\"" "$LINENO" 5 else TOR_ZLIB_LIBS="$TOR_LIBDIR_zlib/libz.a" fi else TOR_ZLIB_LIBS="-lz" fi all_ldflags_for_check="$TOR_LDFLAGS_zlib $TOR_LDFLAGS_openssl $TOR_LDFLAGS_libevent" all_libs_for_check="$TOR_ZLIB_LIBS $TOR_LIB_MATH $TOR_LIBEVENT_LIBS $TOR_OPENSSL_LIBS $TOR_LIB_WS32 $TOR_LIB_GDI" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #if !defined(__clang__) #error #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_clang=yes else have_clang=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test x$enable_gcc_hardening != xno; then CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" if test x$have_clang = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Qunused-arguments" >&5 $as_echo_n "checking whether the compiler accepts -Qunused-arguments... " >&6; } if ${tor_cv_cflags__Qunused_arguments+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pedantic -Werror -Qunused-arguments" 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 : tor_cv_cflags__Qunused_arguments=yes else tor_cv_cflags__Qunused_arguments=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$tor_saved_CFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags__Qunused_arguments" >&5 $as_echo "$tor_cv_cflags__Qunused_arguments" >&6; } if test x$tor_cv_cflags__Qunused_arguments = xyes; then CFLAGS="$CFLAGS -Qunused-arguments" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fstack-protector-all" >&5 $as_echo_n "checking whether the compiler accepts -fstack-protector-all... " >&6; } if ${tor_cv_cflags__fstack_protector_all+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pedantic -Werror -fstack-protector-all" 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 : tor_cv_cflags__fstack_protector_all=yes else tor_cv_cflags__fstack_protector_all=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$tor_saved_CFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags__fstack_protector_all" >&5 $as_echo "$tor_cv_cflags__fstack_protector_all" >&6; } if test x$tor_cv_cflags__fstack_protector_all = xyes; then CFLAGS="$CFLAGS -fstack-protector-all" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Wstack-protector" >&5 $as_echo_n "checking whether the compiler accepts -Wstack-protector... " >&6; } if ${tor_cv_cflags__Wstack_protector+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pedantic -Werror -Wstack-protector" 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 : tor_cv_cflags__Wstack_protector=yes else tor_cv_cflags__Wstack_protector=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$tor_saved_CFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags__Wstack_protector" >&5 $as_echo "$tor_cv_cflags__Wstack_protector" >&6; } if test x$tor_cv_cflags__Wstack_protector = xyes; then CFLAGS="$CFLAGS -Wstack-protector" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fwrapv" >&5 $as_echo_n "checking whether the compiler accepts -fwrapv... " >&6; } if ${tor_cv_cflags__fwrapv+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pedantic -Werror -fwrapv" 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 : tor_cv_cflags__fwrapv=yes else tor_cv_cflags__fwrapv=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$tor_saved_CFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags__fwrapv" >&5 $as_echo "$tor_cv_cflags__fwrapv" >&6; } if test x$tor_cv_cflags__fwrapv = xyes; then CFLAGS="$CFLAGS -fwrapv" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts --param ssp-buffer-size=1" >&5 $as_echo_n "checking whether the compiler accepts --param ssp-buffer-size=1... " >&6; } if ${tor_cv_cflags___param_ssp_buffer_size_1+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pedantic -Werror --param ssp-buffer-size=1" 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 : tor_cv_cflags___param_ssp_buffer_size_1=yes else tor_cv_cflags___param_ssp_buffer_size_1=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$tor_saved_CFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags___param_ssp_buffer_size_1" >&5 $as_echo "$tor_cv_cflags___param_ssp_buffer_size_1" >&6; } if test x$tor_cv_cflags___param_ssp_buffer_size_1 = xyes; then CFLAGS="$CFLAGS --param ssp-buffer-size=1" fi if test "$bwin32" = "false"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fPIE" >&5 $as_echo_n "checking whether the compiler accepts -fPIE... " >&6; } if ${tor_cv_cflags__fPIE+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pedantic -Werror -fPIE" 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 : tor_cv_cflags__fPIE=yes else tor_cv_cflags__fPIE=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$tor_saved_CFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_cflags__fPIE" >&5 $as_echo "$tor_cv_cflags__fPIE" >&6; } if test x$tor_cv_cflags__fPIE = xyes; then CFLAGS="$CFLAGS -fPIE" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -pie" >&5 $as_echo_n "checking whether the linker accepts -pie... " >&6; } if ${tor_cv_ldflags__pie+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_CFLAGS="$CFLAGS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_LIBS="$LIBS" CFLAGS="$CFLAGS -pedantic -Werror" LDFLAGS="$LDFLAGS "$all_ldflags_for_check" -pie" LIBS="$LIBS "$all_libs_for_check"" if test "$cross_compiling" = yes; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tor_cv_ldflags__pie=yes else tor_cv_ldflags__pie=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { fputs("", stdout) ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : tor_cv_ldflags__pie=yes else tor_cv_ldflags__pie=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$tor_saved_CFLAGS" LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_ldflags__pie" >&5 $as_echo "$tor_cv_ldflags__pie" >&6; } if test x$tor_cv_ldflags__pie = xyes; then LDFLAGS="$LDFLAGS -pie" fi fi fi if test x$enable_linker_hardening != xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -z relro -z now" >&5 $as_echo_n "checking whether the linker accepts -z relro -z now... " >&6; } if ${tor_cv_ldflags__z_relro__z_now+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_CFLAGS="$CFLAGS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_LIBS="$LIBS" CFLAGS="$CFLAGS -pedantic -Werror" LDFLAGS="$LDFLAGS "$all_ldflags_for_check" -z relro -z now" LIBS="$LIBS "$all_libs_for_check"" if test "$cross_compiling" = yes; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tor_cv_ldflags__z_relro__z_now=yes else tor_cv_ldflags__z_relro__z_now=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { fputs("", stdout) ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : tor_cv_ldflags__z_relro__z_now=yes else tor_cv_ldflags__z_relro__z_now=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$tor_saved_CFLAGS" LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_ldflags__z_relro__z_now" >&5 $as_echo "$tor_cv_ldflags__z_relro__z_now" >&6; } if test x$tor_cv_ldflags__z_relro__z_now = xyes; then LDFLAGS="$LDFLAGS -z relro -z now" fi fi if test "$natpmp" = "true"; then $as_echo "#define NAT_PMP 1" >>confdefs.h trylibnatpmpdir="" # Check whether --with-libnatpmp-dir was given. if test "${with_libnatpmp_dir+set}" = set; then : withval=$with_libnatpmp_dir; if test x$withval != xno ; then trylibnatpmpdir="$withval" fi fi if test "x$trylibnatpmpdir" = x && test "x$ALT_libnatpmp_WITHVAL" != x ; then trylibnatpmpdir="$ALT_libnatpmp_WITHVAL" fi tor_saved_LIBS="$LIBS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_CPPFLAGS="$CPPFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnatpmp directory" >&5 $as_echo_n "checking for libnatpmp directory... " >&6; } if ${tor_cv_library_libnatpmp_dir+:} false; then : $as_echo_n "(cached) " >&6 else tor_libnatpmp_dir_found=no tor_libnatpmp_any_linkable=no for tor_trydir in "$trylibnatpmpdir" "(system)" "$prefix" /usr/local /usr/pkg --with-libnatpmp-dir; do LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS -lnatpmp $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI" CPPFLAGS="$tor_saved_CPPFLAGS" if test -z "$tor_trydir" ; then continue; fi # Skip the directory if it isn't there. if test ! -d "$tor_trydir" && test "$tor_trydir" != "(system)"; then continue; fi # If this isn't blank, try adding the directory (or appropriate # include/libs subdirectories) to the command line. if test "$tor_trydir" != "(system)"; then if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi if test -d "$tor_trydir/include"; then CPPFLAGS="-I$tor_trydir/include $CPPFLAGS" else CPPFLAGS="-I$tor_trydir $CPPFLAGS" fi fi # Can we link against (but not necessarily run, or find the headers for) # the binary? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef _WIN32 #define STATICLIB #endif #include int main () { int r; natpmp_t natpmp; natpmpresp_t response; r = initnatpmp(&natpmp, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : linkable=yes else linkable=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$linkable" = yes; then tor_libnatpmp_any_linkable=yes # Okay, we can link against it. Can we find the headers? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int r; natpmp_t natpmp; natpmpresp_t response; r = initnatpmp(&natpmp, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : buildable=yes else buildable=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$buildable" = yes; then tor_cv_library_libnatpmp_dir=$tor_trydir tor_libnatpmp_dir_found=yes break fi fi done if test "$tor_libnatpmp_dir_found" = no; then if test "$tor_libnatpmp_any_linkable" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find a linkable libnatpmp. If you have it installed somewhere unusual, you can specify an explicit path using --with-libnatpmp-dir" >&5 $as_echo "$as_me: WARNING: Could not find a linkable libnatpmp. If you have it installed somewhere unusual, you can specify an explicit path using --with-libnatpmp-dir" >&2;} h="" if test xpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_libnatpmp_pkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h libnatpmp using \"apt-get install $tor_libnatpmp_pkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h libnatpmp using \"apt-get install $tor_libnatpmp_pkg_debian\"" >&2;} if test x"$tor_libnatpmp_pkg_debian" != x"$tor_libnatpmp_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_libnatpmp_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_libnatpmp_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_libnatpmp_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h libnatpmp using \"yum install $tor_libnatpmp_pkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h libnatpmp using \"yum install $tor_libnatpmp_pkg_redhat\"" >&2;} if test x"$tor_libnatpmp_pkg_redhat" != x"$tor_libnatpmp_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libnatpmp_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libnatpmp_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_libnatpmp_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h libnatpmp by installing the $tor_libnatpmp_pkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h libnatpmp by installing the $tor_libnatpmp_pkg_redhat\" RPM package" >&2;} if test x"$tor_libnatpmp_pkg_redhat" != x"$tor_libnatpmp_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libnatpmp_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libnatpmp_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing libraries; unable to proceed." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: We found the libraries for libnatpmp, but we could not find the C header files. You may need to install a devel package." >&5 $as_echo "$as_me: WARNING: We found the libraries for libnatpmp, but we could not find the C header files. You may need to install a devel package." >&2;} h="" if test xdevpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_libnatpmp_devpkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h libnatpmp using \"apt-get install $tor_libnatpmp_devpkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h libnatpmp using \"apt-get install $tor_libnatpmp_devpkg_debian\"" >&2;} if test x"$tor_libnatpmp_devpkg_debian" != x"$tor_libnatpmp_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_libnatpmp_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_libnatpmp_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_libnatpmp_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h libnatpmp using \"yum install $tor_libnatpmp_devpkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h libnatpmp using \"yum install $tor_libnatpmp_devpkg_redhat\"" >&2;} if test x"$tor_libnatpmp_devpkg_redhat" != x"$tor_libnatpmp_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libnatpmp_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libnatpmp_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_libnatpmp_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h libnatpmp by installing the $tor_libnatpmp_devpkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h libnatpmp by installing the $tor_libnatpmp_devpkg_redhat\" RPM package" >&2;} if test x"$tor_libnatpmp_devpkg_redhat" != x"$tor_libnatpmp_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libnatpmp_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libnatpmp_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing headers; unable to proceed." "$LINENO" 5 fi fi LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" CPPFLAGS="$tor_saved_CPPFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_libnatpmp_dir" >&5 $as_echo "$tor_cv_library_libnatpmp_dir" >&6; } LIBS="$LIBS -lnatpmp $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI" if test "$tor_cv_library_libnatpmp_dir" != "(system)"; then if test -d "$tor_cv_library_libnatpmp_dir/lib"; then LDFLAGS="-L$tor_cv_library_libnatpmp_dir/lib $LDFLAGS" else LDFLAGS="-L$tor_cv_library_libnatpmp_dir $LDFLAGS" fi if test -d "$tor_cv_library_libnatpmp_dir/include"; then CPPFLAGS="-I$tor_cv_library_libnatpmp_dir/include $CPPFLAGS" else CPPFLAGS="-I$tor_cv_library_libnatpmp_dir $CPPFLAGS" fi fi if test x$tor_cv_library_libnatpmp_dir = "x(system)"; then TOR_LDFLAGS_libnatpmp="" TOR_CPPFLAGS_libnatpmp="" else if test -d "$tor_cv_library_libnatpmp_dir/lib"; then TOR_LDFLAGS_libnatpmp="-L$tor_cv_library_libnatpmp_dir/lib" TOR_LIBDIR_libnatpmp="$tor_cv_library_libnatpmp_dir/lib" else TOR_LDFLAGS_libnatpmp="-L$tor_cv_library_libnatpmp_dir" TOR_LIBDIR_libnatpmp="$tor_cv_library_libnatpmp_dir" fi if test -d "$tor_cv_library_libnatpmp_dir/include"; then TOR_CPPFLAGS_libnatpmp="-I$tor_cv_library_libnatpmp_dir/include" else TOR_CPPFLAGS_libnatpmp="-I$tor_cv_library_libnatpmp_dir" fi fi if test "$cross_compiling" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need extra options to link libnatpmp" >&5 $as_echo_n "checking whether we need extra options to link libnatpmp... " >&6; } if ${tor_cv_library_libnatpmp_linker_option+:} false; then : $as_echo_n "(cached) " >&6 else orig_LDFLAGS="$LDFLAGS" runs=no linked_with=nothing if test -d "$tor_cv_library_libnatpmp_dir/lib"; then tor_trydir="$tor_cv_library_libnatpmp_dir/lib" else tor_trydir="$tor_cv_library_libnatpmp_dir" fi for tor_tryextra in "(none)" "-Wl,-R$tor_trydir" "-R$tor_trydir" \ "-Wl,-rpath,$tor_trydir" ; do if test "$tor_tryextra" = "(none)"; then LDFLAGS="$orig_LDFLAGS" else LDFLAGS="$tor_tryextra $orig_LDFLAGS" fi 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. */ #ifdef _WIN32 #define STATICLIB #endif #include int main () { int r; natpmp_t natpmp; natpmpresp_t response; r = initnatpmp(&natpmp, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : runnable=yes else runnable=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$runnable" = yes; then tor_cv_library_libnatpmp_linker_option=$tor_tryextra break fi done if test "$runnable" = no; then as_fn_error $? "Found linkable libnatpmp in $tor_cv_library_libnatpmp_dir, but it does not seem to run, even with -R. Maybe specify another using --with-libnatpmp-dir}" "$LINENO" 5 fi LDFLAGS="$orig_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_libnatpmp_linker_option" >&5 $as_echo "$tor_cv_library_libnatpmp_linker_option" >&6; } if test "$tor_cv_library_libnatpmp_linker_option" != "(none)" ; then TOR_LDFLAGS_libnatpmp="$TOR_LDFLAGS_libnatpmp $tor_cv_library_libnatpmp_linker_option" fi fi # cross-compile LIBS="$tor_saved_LIBS" LDFLAGS="$tor_saved_LDFLAGS" CPPFLAGS="$tor_saved_CPPFLAGS" fi if test "$upnp" = "true"; then $as_echo "#define MINIUPNPC 1" >>confdefs.h cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { upnpDiscover(1, 0, 0, 0);exit(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : miniupnpc15="true" else miniupnpc15="false" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$miniupnpc15" = "true" ; then $as_echo "#define MINIUPNPC15 1" >>confdefs.h trylibminiupnpcdir="" # Check whether --with-libminiupnpc-dir was given. if test "${with_libminiupnpc_dir+set}" = set; then : withval=$with_libminiupnpc_dir; if test x$withval != xno ; then trylibminiupnpcdir="$withval" fi fi if test "x$trylibminiupnpcdir" = x && test "x$ALT_libminiupnpc_WITHVAL" != x ; then trylibminiupnpcdir="$ALT_libminiupnpc_WITHVAL" fi tor_saved_LIBS="$LIBS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_CPPFLAGS="$CPPFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libminiupnpc directory" >&5 $as_echo_n "checking for libminiupnpc directory... " >&6; } if ${tor_cv_library_libminiupnpc_dir+:} false; then : $as_echo_n "(cached) " >&6 else tor_libminiupnpc_dir_found=no tor_libminiupnpc_any_linkable=no for tor_trydir in "$trylibminiupnpcdir" "(system)" "$prefix" /usr/local /usr/pkg /usr/lib/; do LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS -lminiupnpc $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI" CPPFLAGS="$tor_saved_CPPFLAGS" if test -z "$tor_trydir" ; then continue; fi # Skip the directory if it isn't there. if test ! -d "$tor_trydir" && test "$tor_trydir" != "(system)"; then continue; fi # If this isn't blank, try adding the directory (or appropriate # include/libs subdirectories) to the command line. if test "$tor_trydir" != "(system)"; then if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi if test -d "$tor_trydir/include"; then CPPFLAGS="-I$tor_trydir/include $CPPFLAGS" else CPPFLAGS="-I$tor_trydir $CPPFLAGS" fi fi # Can we link against (but not necessarily run, or find the headers for) # the binary? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ void upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport); int main () { upnpDiscover(1, 0, 0, 0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : linkable=yes else linkable=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$linkable" = yes; then tor_libminiupnpc_any_linkable=yes # Okay, we can link against it. Can we find the headers? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { upnpDiscover(1, 0, 0, 0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : buildable=yes else buildable=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$buildable" = yes; then tor_cv_library_libminiupnpc_dir=$tor_trydir tor_libminiupnpc_dir_found=yes break fi fi done if test "$tor_libminiupnpc_dir_found" = no; then if test "$tor_libminiupnpc_any_linkable" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find a linkable libminiupnpc. If you have it installed somewhere unusual, you can specify an explicit path using --with-libminiupnpc-dir" >&5 $as_echo "$as_me: WARNING: Could not find a linkable libminiupnpc. If you have it installed somewhere unusual, you can specify an explicit path using --with-libminiupnpc-dir" >&2;} h="" if test xpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_libminiupnpc_pkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h libminiupnpc using \"apt-get install $tor_libminiupnpc_pkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h libminiupnpc using \"apt-get install $tor_libminiupnpc_pkg_debian\"" >&2;} if test x"$tor_libminiupnpc_pkg_debian" != x"$tor_libminiupnpc_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_libminiupnpc_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_libminiupnpc_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_libminiupnpc_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h libminiupnpc using \"yum install $tor_libminiupnpc_pkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h libminiupnpc using \"yum install $tor_libminiupnpc_pkg_redhat\"" >&2;} if test x"$tor_libminiupnpc_pkg_redhat" != x"$tor_libminiupnpc_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_libminiupnpc_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h libminiupnpc by installing the $tor_libminiupnpc_pkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h libminiupnpc by installing the $tor_libminiupnpc_pkg_redhat\" RPM package" >&2;} if test x"$tor_libminiupnpc_pkg_redhat" != x"$tor_libminiupnpc_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing libraries; unable to proceed." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: We found the libraries for libminiupnpc, but we could not find the C header files. You may need to install a devel package." >&5 $as_echo "$as_me: WARNING: We found the libraries for libminiupnpc, but we could not find the C header files. You may need to install a devel package." >&2;} h="" if test xdevpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_libminiupnpc_devpkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h libminiupnpc using \"apt-get install $tor_libminiupnpc_devpkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h libminiupnpc using \"apt-get install $tor_libminiupnpc_devpkg_debian\"" >&2;} if test x"$tor_libminiupnpc_devpkg_debian" != x"$tor_libminiupnpc_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_libminiupnpc_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_libminiupnpc_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_libminiupnpc_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h libminiupnpc using \"yum install $tor_libminiupnpc_devpkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h libminiupnpc using \"yum install $tor_libminiupnpc_devpkg_redhat\"" >&2;} if test x"$tor_libminiupnpc_devpkg_redhat" != x"$tor_libminiupnpc_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_libminiupnpc_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h libminiupnpc by installing the $tor_libminiupnpc_devpkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h libminiupnpc by installing the $tor_libminiupnpc_devpkg_redhat\" RPM package" >&2;} if test x"$tor_libminiupnpc_devpkg_redhat" != x"$tor_libminiupnpc_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing headers; unable to proceed." "$LINENO" 5 fi fi LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" CPPFLAGS="$tor_saved_CPPFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_libminiupnpc_dir" >&5 $as_echo "$tor_cv_library_libminiupnpc_dir" >&6; } LIBS="$LIBS -lminiupnpc $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI" if test "$tor_cv_library_libminiupnpc_dir" != "(system)"; then if test -d "$tor_cv_library_libminiupnpc_dir/lib"; then LDFLAGS="-L$tor_cv_library_libminiupnpc_dir/lib $LDFLAGS" else LDFLAGS="-L$tor_cv_library_libminiupnpc_dir $LDFLAGS" fi if test -d "$tor_cv_library_libminiupnpc_dir/include"; then CPPFLAGS="-I$tor_cv_library_libminiupnpc_dir/include $CPPFLAGS" else CPPFLAGS="-I$tor_cv_library_libminiupnpc_dir $CPPFLAGS" fi fi if test x$tor_cv_library_libminiupnpc_dir = "x(system)"; then TOR_LDFLAGS_libminiupnpc="" TOR_CPPFLAGS_libminiupnpc="" else if test -d "$tor_cv_library_libminiupnpc_dir/lib"; then TOR_LDFLAGS_libminiupnpc="-L$tor_cv_library_libminiupnpc_dir/lib" TOR_LIBDIR_libminiupnpc="$tor_cv_library_libminiupnpc_dir/lib" else TOR_LDFLAGS_libminiupnpc="-L$tor_cv_library_libminiupnpc_dir" TOR_LIBDIR_libminiupnpc="$tor_cv_library_libminiupnpc_dir" fi if test -d "$tor_cv_library_libminiupnpc_dir/include"; then TOR_CPPFLAGS_libminiupnpc="-I$tor_cv_library_libminiupnpc_dir/include" else TOR_CPPFLAGS_libminiupnpc="-I$tor_cv_library_libminiupnpc_dir" fi fi if test "$cross_compiling" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need extra options to link libminiupnpc" >&5 $as_echo_n "checking whether we need extra options to link libminiupnpc... " >&6; } if ${tor_cv_library_libminiupnpc_linker_option+:} false; then : $as_echo_n "(cached) " >&6 else orig_LDFLAGS="$LDFLAGS" runs=no linked_with=nothing if test -d "$tor_cv_library_libminiupnpc_dir/lib"; then tor_trydir="$tor_cv_library_libminiupnpc_dir/lib" else tor_trydir="$tor_cv_library_libminiupnpc_dir" fi for tor_tryextra in "(none)" "-Wl,-R$tor_trydir" "-R$tor_trydir" \ "-Wl,-rpath,$tor_trydir" ; do if test "$tor_tryextra" = "(none)"; then LDFLAGS="$orig_LDFLAGS" else LDFLAGS="$tor_tryextra $orig_LDFLAGS" fi 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. */ void upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport); int main () { upnpDiscover(1, 0, 0, 0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : runnable=yes else runnable=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$runnable" = yes; then tor_cv_library_libminiupnpc_linker_option=$tor_tryextra break fi done if test "$runnable" = no; then as_fn_error $? "Found linkable libminiupnpc in $tor_cv_library_libminiupnpc_dir, but it does not seem to run, even with -R. Maybe specify another using --with-libminiupnpc-dir}" "$LINENO" 5 fi LDFLAGS="$orig_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_libminiupnpc_linker_option" >&5 $as_echo "$tor_cv_library_libminiupnpc_linker_option" >&6; } if test "$tor_cv_library_libminiupnpc_linker_option" != "(none)" ; then TOR_LDFLAGS_libminiupnpc="$TOR_LDFLAGS_libminiupnpc $tor_cv_library_libminiupnpc_linker_option" fi fi # cross-compile LIBS="$tor_saved_LIBS" LDFLAGS="$tor_saved_LDFLAGS" CPPFLAGS="$tor_saved_CPPFLAGS" else trylibminiupnpcdir="" # Check whether --with-libminiupnpc-dir was given. if test "${with_libminiupnpc_dir+set}" = set; then : withval=$with_libminiupnpc_dir; if test x$withval != xno ; then trylibminiupnpcdir="$withval" fi fi if test "x$trylibminiupnpcdir" = x && test "x$ALT_libminiupnpc_WITHVAL" != x ; then trylibminiupnpcdir="$ALT_libminiupnpc_WITHVAL" fi tor_saved_LIBS="$LIBS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_CPPFLAGS="$CPPFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libminiupnpc directory" >&5 $as_echo_n "checking for libminiupnpc directory... " >&6; } if ${tor_cv_library_libminiupnpc_dir+:} false; then : $as_echo_n "(cached) " >&6 else tor_libminiupnpc_dir_found=no tor_libminiupnpc_any_linkable=no for tor_trydir in "$trylibminiupnpcdir" "(system)" "$prefix" /usr/local /usr/pkg /usr/lib/; do LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS -lminiupnpc $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI" CPPFLAGS="$tor_saved_CPPFLAGS" if test -z "$tor_trydir" ; then continue; fi # Skip the directory if it isn't there. if test ! -d "$tor_trydir" && test "$tor_trydir" != "(system)"; then continue; fi # If this isn't blank, try adding the directory (or appropriate # include/libs subdirectories) to the command line. if test "$tor_trydir" != "(system)"; then if test -d "$tor_trydir/lib"; then LDFLAGS="-L$tor_trydir/lib $LDFLAGS" else LDFLAGS="-L$tor_trydir $LDFLAGS" fi if test -d "$tor_trydir/include"; then CPPFLAGS="-I$tor_trydir/include $CPPFLAGS" else CPPFLAGS="-I$tor_trydir $CPPFLAGS" fi fi # Can we link against (but not necessarily run, or find the headers for) # the binary? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ void upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error); int main () { upnpDiscover(1, 0, 0, 0, 0, 0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : linkable=yes else linkable=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$linkable" = yes; then tor_libminiupnpc_any_linkable=yes # Okay, we can link against it. Can we find the headers? cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { upnpDiscover(1, 0, 0, 0, 0, 0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : buildable=yes else buildable=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$buildable" = yes; then tor_cv_library_libminiupnpc_dir=$tor_trydir tor_libminiupnpc_dir_found=yes break fi fi done if test "$tor_libminiupnpc_dir_found" = no; then if test "$tor_libminiupnpc_any_linkable" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find a linkable libminiupnpc. If you have it installed somewhere unusual, you can specify an explicit path using --with-libminiupnpc-dir" >&5 $as_echo "$as_me: WARNING: Could not find a linkable libminiupnpc. If you have it installed somewhere unusual, you can specify an explicit path using --with-libminiupnpc-dir" >&2;} h="" if test xpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_libminiupnpc_pkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h libminiupnpc using \"apt-get install $tor_libminiupnpc_pkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h libminiupnpc using \"apt-get install $tor_libminiupnpc_pkg_debian\"" >&2;} if test x"$tor_libminiupnpc_pkg_debian" != x"$tor_libminiupnpc_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_libminiupnpc_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_libminiupnpc_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_libminiupnpc_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h libminiupnpc using \"yum install $tor_libminiupnpc_pkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h libminiupnpc using \"yum install $tor_libminiupnpc_pkg_redhat\"" >&2;} if test x"$tor_libminiupnpc_pkg_redhat" != x"$tor_libminiupnpc_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_libminiupnpc_pkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h libminiupnpc by installing the $tor_libminiupnpc_pkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h libminiupnpc by installing the $tor_libminiupnpc_pkg_redhat\" RPM package" >&2;} if test x"$tor_libminiupnpc_pkg_redhat" != x"$tor_libminiupnpc_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing libraries; unable to proceed." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: We found the libraries for libminiupnpc, but we could not find the C header files. You may need to install a devel package." >&5 $as_echo "$as_me: WARNING: We found the libraries for libminiupnpc, but we could not find the C header files. You may need to install a devel package." >&2;} h="" if test xdevpkg = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_libminiupnpc_devpkg_debian" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Debian, you can install$h libminiupnpc using \"apt-get install $tor_libminiupnpc_devpkg_debian\"" >&5 $as_echo "$as_me: WARNING: On Debian, you can install$h libminiupnpc using \"apt-get install $tor_libminiupnpc_devpkg_debian\"" >&2;} if test x"$tor_libminiupnpc_devpkg_debian" != x"$tor_libminiupnpc_devpkg_debian"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need $tor_libminiupnpc_devpkg_debian too." >&5 $as_echo "$as_me: WARNING: You will probably need $tor_libminiupnpc_devpkg_debian too." >&2;} fi fi if test -f /etc/fedora-release && test x"$tor_libminiupnpc_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On Fedora Core, you can install$h libminiupnpc using \"yum install $tor_libminiupnpc_devpkg_redhat\"" >&5 $as_echo "$as_me: WARNING: On Fedora Core, you can install$h libminiupnpc using \"yum install $tor_libminiupnpc_devpkg_redhat\"" >&2;} if test x"$tor_libminiupnpc_devpkg_redhat" != x"$tor_libminiupnpc_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&2;} fi else if test -f /etc/redhat-release && test x"$tor_libminiupnpc_devpkg_redhat" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: On most Redhat-based systems, you can get$h libminiupnpc by installing the $tor_libminiupnpc_devpkg_redhat\" RPM package" >&5 $as_echo "$as_me: WARNING: On most Redhat-based systems, you can get$h libminiupnpc by installing the $tor_libminiupnpc_devpkg_redhat\" RPM package" >&2;} if test x"$tor_libminiupnpc_devpkg_redhat" != x"$tor_libminiupnpc_devpkg_redhat"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&5 $as_echo "$as_me: WARNING: You will probably need to install $tor_libminiupnpc_devpkg_redhat too." >&2;} fi fi fi as_fn_error $? "Missing headers; unable to proceed." "$LINENO" 5 fi fi LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" CPPFLAGS="$tor_saved_CPPFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_libminiupnpc_dir" >&5 $as_echo "$tor_cv_library_libminiupnpc_dir" >&6; } LIBS="$LIBS -lminiupnpc $TOR_LIB_WS32 $TOR_LIB_IPHLPAPI" if test "$tor_cv_library_libminiupnpc_dir" != "(system)"; then if test -d "$tor_cv_library_libminiupnpc_dir/lib"; then LDFLAGS="-L$tor_cv_library_libminiupnpc_dir/lib $LDFLAGS" else LDFLAGS="-L$tor_cv_library_libminiupnpc_dir $LDFLAGS" fi if test -d "$tor_cv_library_libminiupnpc_dir/include"; then CPPFLAGS="-I$tor_cv_library_libminiupnpc_dir/include $CPPFLAGS" else CPPFLAGS="-I$tor_cv_library_libminiupnpc_dir $CPPFLAGS" fi fi if test x$tor_cv_library_libminiupnpc_dir = "x(system)"; then TOR_LDFLAGS_libminiupnpc="" TOR_CPPFLAGS_libminiupnpc="" else if test -d "$tor_cv_library_libminiupnpc_dir/lib"; then TOR_LDFLAGS_libminiupnpc="-L$tor_cv_library_libminiupnpc_dir/lib" TOR_LIBDIR_libminiupnpc="$tor_cv_library_libminiupnpc_dir/lib" else TOR_LDFLAGS_libminiupnpc="-L$tor_cv_library_libminiupnpc_dir" TOR_LIBDIR_libminiupnpc="$tor_cv_library_libminiupnpc_dir" fi if test -d "$tor_cv_library_libminiupnpc_dir/include"; then TOR_CPPFLAGS_libminiupnpc="-I$tor_cv_library_libminiupnpc_dir/include" else TOR_CPPFLAGS_libminiupnpc="-I$tor_cv_library_libminiupnpc_dir" fi fi if test "$cross_compiling" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need extra options to link libminiupnpc" >&5 $as_echo_n "checking whether we need extra options to link libminiupnpc... " >&6; } if ${tor_cv_library_libminiupnpc_linker_option+:} false; then : $as_echo_n "(cached) " >&6 else orig_LDFLAGS="$LDFLAGS" runs=no linked_with=nothing if test -d "$tor_cv_library_libminiupnpc_dir/lib"; then tor_trydir="$tor_cv_library_libminiupnpc_dir/lib" else tor_trydir="$tor_cv_library_libminiupnpc_dir" fi for tor_tryextra in "(none)" "-Wl,-R$tor_trydir" "-R$tor_trydir" \ "-Wl,-rpath,$tor_trydir" ; do if test "$tor_tryextra" = "(none)"; then LDFLAGS="$orig_LDFLAGS" else LDFLAGS="$tor_tryextra $orig_LDFLAGS" fi 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. */ void upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error); int main () { upnpDiscover(1, 0, 0, 0, 0, 0); exit(0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : runnable=yes else runnable=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$runnable" = yes; then tor_cv_library_libminiupnpc_linker_option=$tor_tryextra break fi done if test "$runnable" = no; then as_fn_error $? "Found linkable libminiupnpc in $tor_cv_library_libminiupnpc_dir, but it does not seem to run, even with -R. Maybe specify another using --with-libminiupnpc-dir}" "$LINENO" 5 fi LDFLAGS="$orig_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_library_libminiupnpc_linker_option" >&5 $as_echo "$tor_cv_library_libminiupnpc_linker_option" >&6; } if test "$tor_cv_library_libminiupnpc_linker_option" != "(none)" ; then TOR_LDFLAGS_libminiupnpc="$TOR_LDFLAGS_libminiupnpc $tor_cv_library_libminiupnpc_linker_option" fi fi # cross-compile LIBS="$tor_saved_LIBS" LDFLAGS="$tor_saved_LDFLAGS" CPPFLAGS="$tor_saved_CPPFLAGS" fi fi have_a_curve25519=no build_curve25519_donna=no build_curve25519_donna_c64=no use_curve25519_donna=no use_curve25519_nacl=no CURVE25519_LIBS= if test x$enable_curve25519 != xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can use curve25519-donna-c64" >&5 $as_echo_n "checking whether we can use curve25519-donna-c64... " >&6; } if ${tor_cv_can_use_curve25519_donna_c64+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include typedef unsigned uint128_t __attribute__((mode(TI))); int func(uint64_t a, uint64_t b) { uint128_t c = ((uint128_t)a) * b; int ok = ((uint64_t)(c>>96)) == 522859 && (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L && (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L && (((uint64_t)(c))&0xffffffffL) == 0; return ok; } int main () { int ok = func( ((uint64_t)2000000000) * 1000000000, ((uint64_t)1234567890) << 24); return !ok; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tor_cv_can_use_curve25519_donna_c64=cross else tor_cv_can_use_curve25519_donna_c64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include typedef unsigned uint128_t __attribute__((mode(TI))); int func(uint64_t a, uint64_t b) { uint128_t c = ((uint128_t)a) * b; int ok = ((uint64_t)(c>>96)) == 522859 && (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L && (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L && (((uint64_t)(c))&0xffffffffL) == 0; return ok; } int main () { int ok = func( ((uint64_t)2000000000) * 1000000000, ((uint64_t)1234567890) << 24); return !ok; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : tor_cv_can_use_curve25519_donna_c64=yes else tor_cv_can_use_curve25519_donna_c64=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_can_use_curve25519_donna_c64" >&5 $as_echo "$tor_cv_can_use_curve25519_donna_c64" >&6; } for ac_header in crypto_scalarmult_curve25519.h \ nacl/crypto_scalarmult_curve25519.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nacl compiled with a fast curve25519 implementation" >&5 $as_echo_n "checking for nacl compiled with a fast curve25519 implementation... " >&6; } if ${tor_cv_can_use_curve25519_nacl+:} false; then : $as_echo_n "(cached) " >&6 else tor_saved_LIBS="$LIBS" LIBS="$LIBS -lnacl" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H #include #elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H) #include #endif #ifdef crypto_scalarmult_curve25519_ref_BYTES #error Hey, this is the reference implementation! That's not fast. #endif int main () { unsigned char *a, *b, *c; crypto_scalarmult_curve25519(a,b,c); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tor_cv_can_use_curve25519_nacl=yes else tor_cv_can_use_curve25519_nacl=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$tor_saved_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_can_use_curve25519_nacl" >&5 $as_echo "$tor_cv_can_use_curve25519_nacl" >&6; } if test x$tor_cv_can_use_curve25519_donna_c64 != xno; then build_curve25519_donna_c64=yes use_curve25519_donna=yes elif test x$tor_cv_can_use_curve25519_nacl = xyes; then use_curve25519_nacl=yes CURVE25519_LIBS=-lnacl else build_curve25519_donna=yes use_curve25519_donna=yes fi have_a_curve25519=yes fi if test x$have_a_curve25519 = xyes; then $as_echo "#define CURVE25519_ENABLED 1" >>confdefs.h fi if test x$use_curve25519_donna = xyes; then $as_echo "#define USE_CURVE25519_DONNA 1" >>confdefs.h fi if test x$use_curve25519_nacl = xyes; then $as_echo "#define USE_CURVE25519_NACL 1" >>confdefs.h fi if test x$build_curve25519_donna = xyes; then BUILD_CURVE25519_DONNA_TRUE= BUILD_CURVE25519_DONNA_FALSE='#' else BUILD_CURVE25519_DONNA_TRUE='#' BUILD_CURVE25519_DONNA_FALSE= fi if test x$build_curve25519_donna_c64 = xyes; then BUILD_CURVE25519_DONNA_C64_TRUE= BUILD_CURVE25519_DONNA_C64_FALSE='#' else BUILD_CURVE25519_DONNA_C64_TRUE='#' BUILD_CURVE25519_DONNA_C64_FALSE= fi if test x$have_a_curve25519 = xyes; then CURVE25519_ENABLED_TRUE= CURVE25519_ENABLED_FALSE='#' else CURVE25519_ENABLED_TRUE='#' CURVE25519_ENABLED_FALSE= fi # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi for ac_header in assert.h \ errno.h \ fcntl.h \ signal.h \ string.h \ sys/fcntl.h \ sys/stat.h \ sys/time.h \ sys/types.h \ time.h \ unistd.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 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Some headers were not found" >&5 $as_echo "$as_me: WARNING: Some headers were not found" >&2;} fi done for ac_header in arpa/inet.h \ crt_externs.h \ grp.h \ ifaddrs.h \ inttypes.h \ limits.h \ linux/types.h \ machine/limits.h \ malloc.h \ malloc/malloc.h \ malloc_np.h \ netdb.h \ netinet/in.h \ netinet/in6.h \ pwd.h \ stdint.h \ sys/file.h \ sys/ioctl.h \ sys/limits.h \ sys/mman.h \ sys/param.h \ sys/prctl.h \ sys/resource.h \ sys/socket.h \ sys/syslimits.h \ sys/time.h \ sys/types.h \ sys/un.h \ sys/utime.h \ sys/wait.h \ syslog.h \ utime.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/param.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PARAM_H 1 _ACEOF fi done 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_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_header_net_if_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_IF_H 1 _ACEOF net_if_found=1 else net_if_found=0 fi done for ac_header in net/pfvar.h do : ac_fn_c_check_header_compile "$LINENO" "net/pfvar.h" "ac_cv_header_net_pfvar_h" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif " if test "x$ac_cv_header_net_pfvar_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_PFVAR_H 1 _ACEOF net_pfvar_found=1 else net_pfvar_found=0 fi done for ac_header in linux/netfilter_ipv4.h do : ac_fn_c_check_header_compile "$LINENO" "linux/netfilter_ipv4.h" "ac_cv_header_linux_netfilter_ipv4_h" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_LIMITS_H #include #endif #ifdef HAVE_LINUX_TYPES_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif " if test "x$ac_cv_header_linux_netfilter_ipv4_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_NETFILTER_IPV4_H 1 _ACEOF linux_netfilter_ipv4=1 else linux_netfilter_ipv4=0 fi done if test x$transparent = xtrue ; then transparent_ok=0 if test x$net_if_found = x1 && test x$net_pfvar_found = x1 ; then transparent_ok=1 fi if test x$linux_netfilter_ipv4 = x1 ; then transparent_ok=1 fi if test x$transparent_ok = x1 ; then $as_echo "#define USE_TRANSPARENT 1" >>confdefs.h case $host in *-*-openbsd* | *-*-bitrig*) $as_echo "#define OPENBSD 1" >>confdefs.h ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: Transparent proxy support enabled, but missing headers." >&5 $as_echo "$as_me: Transparent proxy support enabled, but missing headers." >&6;} fi fi ac_fn_c_check_member "$LINENO" "struct timeval" "tv_sec" "ac_cv_member_struct_timeval_tv_sec" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif " if test "x$ac_cv_member_struct_timeval_tv_sec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TIMEVAL_TV_SEC 1 _ACEOF fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int8_t" >&5 $as_echo_n "checking size of int8_t... " >&6; } if ${ac_cv_sizeof_int8_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int8_t))" "ac_cv_sizeof_int8_t" "$ac_includes_default"; then : else if test "$ac_cv_type_int8_t" = 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 77 "cannot compute sizeof (int8_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int8_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int8_t" >&5 $as_echo "$ac_cv_sizeof_int8_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT8_T $ac_cv_sizeof_int8_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int16_t" >&5 $as_echo_n "checking size of int16_t... " >&6; } if ${ac_cv_sizeof_int16_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int16_t))" "ac_cv_sizeof_int16_t" "$ac_includes_default"; then : else if test "$ac_cv_type_int16_t" = 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 77 "cannot compute sizeof (int16_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int16_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int16_t" >&5 $as_echo "$ac_cv_sizeof_int16_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT16_T $ac_cv_sizeof_int16_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int32_t" >&5 $as_echo_n "checking size of int32_t... " >&6; } if ${ac_cv_sizeof_int32_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int32_t))" "ac_cv_sizeof_int32_t" "$ac_includes_default"; then : else if test "$ac_cv_type_int32_t" = 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 77 "cannot compute sizeof (int32_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int32_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int32_t" >&5 $as_echo "$ac_cv_sizeof_int32_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT32_T $ac_cv_sizeof_int32_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int64_t" >&5 $as_echo_n "checking size of int64_t... " >&6; } if ${ac_cv_sizeof_int64_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int64_t))" "ac_cv_sizeof_int64_t" "$ac_includes_default"; then : else if test "$ac_cv_type_int64_t" = 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 77 "cannot compute sizeof (int64_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int64_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int64_t" >&5 $as_echo "$ac_cv_sizeof_int64_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT64_T $ac_cv_sizeof_int64_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uint8_t" >&5 $as_echo_n "checking size of uint8_t... " >&6; } if ${ac_cv_sizeof_uint8_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uint8_t))" "ac_cv_sizeof_uint8_t" "$ac_includes_default"; then : else if test "$ac_cv_type_uint8_t" = 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 77 "cannot compute sizeof (uint8_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uint8_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uint8_t" >&5 $as_echo "$ac_cv_sizeof_uint8_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UINT8_T $ac_cv_sizeof_uint8_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uint16_t" >&5 $as_echo_n "checking size of uint16_t... " >&6; } if ${ac_cv_sizeof_uint16_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uint16_t))" "ac_cv_sizeof_uint16_t" "$ac_includes_default"; then : else if test "$ac_cv_type_uint16_t" = 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 77 "cannot compute sizeof (uint16_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uint16_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uint16_t" >&5 $as_echo "$ac_cv_sizeof_uint16_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UINT16_T $ac_cv_sizeof_uint16_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uint32_t" >&5 $as_echo_n "checking size of uint32_t... " >&6; } if ${ac_cv_sizeof_uint32_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uint32_t))" "ac_cv_sizeof_uint32_t" "$ac_includes_default"; then : else if test "$ac_cv_type_uint32_t" = 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 77 "cannot compute sizeof (uint32_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uint32_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uint32_t" >&5 $as_echo "$ac_cv_sizeof_uint32_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UINT32_T $ac_cv_sizeof_uint32_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uint64_t" >&5 $as_echo_n "checking size of uint64_t... " >&6; } if ${ac_cv_sizeof_uint64_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uint64_t))" "ac_cv_sizeof_uint64_t" "$ac_includes_default"; then : else if test "$ac_cv_type_uint64_t" = 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 77 "cannot compute sizeof (uint64_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uint64_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uint64_t" >&5 $as_echo "$ac_cv_sizeof_uint64_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UINT64_T $ac_cv_sizeof_uint64_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of intptr_t" >&5 $as_echo_n "checking size of intptr_t... " >&6; } if ${ac_cv_sizeof_intptr_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (intptr_t))" "ac_cv_sizeof_intptr_t" "$ac_includes_default"; then : else if test "$ac_cv_type_intptr_t" = 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 77 "cannot compute sizeof (intptr_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_intptr_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_intptr_t" >&5 $as_echo "$ac_cv_sizeof_intptr_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INTPTR_T $ac_cv_sizeof_intptr_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 $as_echo_n "checking size of uintptr_t... " >&6; } if ${ac_cv_sizeof_uintptr_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default"; then : else if test "$ac_cv_type_uintptr_t" = 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 77 "cannot compute sizeof (uintptr_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uintptr_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uintptr_t" >&5 $as_echo "$ac_cv_sizeof_uintptr_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UINTPTR_T $ac_cv_sizeof_uintptr_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 $as_echo_n "checking size of char... " >&6; } if ${ac_cv_sizeof_char+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default"; then : else if test "$ac_cv_type_char" = 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 77 "cannot compute sizeof (char) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_char=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 $as_echo "$ac_cv_sizeof_char" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_CHAR $ac_cv_sizeof_char _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 $as_echo_n "checking size of short... " >&6; } if ${ac_cv_sizeof_short+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : else if test "$ac_cv_type_short" = 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 77 "cannot compute sizeof (short) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_short=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 $as_echo "$ac_cv_sizeof_short" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_SHORT $ac_cv_sizeof_short _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } if ${ac_cv_sizeof_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : else if test "$ac_cv_type_int" = 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 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 $as_echo "$ac_cv_sizeof_int" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT $ac_cv_sizeof_int _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } if ${ac_cv_sizeof_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : else if test "$ac_cv_type_long" = 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 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 $as_echo "$ac_cv_sizeof_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 $as_echo_n "checking size of long long... " >&6; } if ${ac_cv_sizeof_long_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : else if test "$ac_cv_type_long_long" = 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 77 "cannot compute sizeof (long long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_long=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 $as_echo "$ac_cv_sizeof_long_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of __int64" >&5 $as_echo_n "checking size of __int64... " >&6; } if ${ac_cv_sizeof___int64+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (__int64))" "ac_cv_sizeof___int64" "$ac_includes_default"; then : else if test "$ac_cv_type___int64" = 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 77 "cannot compute sizeof (__int64) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof___int64=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof___int64" >&5 $as_echo "$ac_cv_sizeof___int64" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF___INT64 $ac_cv_sizeof___int64 _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 $as_echo_n "checking size of void *... " >&6; } if ${ac_cv_sizeof_void_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : else if test "$ac_cv_type_void_p" = 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 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_void_p=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 $as_echo "$ac_cv_sizeof_void_p" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_VOID_P $ac_cv_sizeof_void_p _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 $as_echo_n "checking size of time_t... " >&6; } if ${ac_cv_sizeof_time_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default"; then : else if test "$ac_cv_type_time_t" = 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 77 "cannot compute sizeof (time_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_time_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 $as_echo "$ac_cv_sizeof_time_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_TIME_T $ac_cv_sizeof_time_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 $as_echo_n "checking size of size_t... " >&6; } if ${ac_cv_sizeof_size_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : else if test "$ac_cv_type_size_t" = 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 77 "cannot compute sizeof (size_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_size_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 $as_echo "$ac_cv_sizeof_size_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_SIZE_T $ac_cv_sizeof_size_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 $as_echo_n "checking size of pid_t... " >&6; } if ${ac_cv_sizeof_pid_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default"; then : else if test "$ac_cv_type_pid_t" = 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 77 "cannot compute sizeof (pid_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_pid_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pid_t" >&5 $as_echo "$ac_cv_sizeof_pid_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_PID_T $ac_cv_sizeof_pid_t _ACEOF ac_fn_c_check_type "$LINENO" "uint" "ac_cv_type_uint" "$ac_includes_default" if test "x$ac_cv_type_uint" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINT 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "u_char" "ac_cv_type_u_char" "$ac_includes_default" if test "x$ac_cv_type_u_char" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_U_CHAR 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SSIZE_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct in6_addr" "ac_cv_type_struct_in6_addr" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif " if test "x$ac_cv_type_struct_in6_addr" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IN6_ADDR 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct sockaddr_in6" "ac_cv_type_struct_sockaddr_in6" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif " if test "x$ac_cv_type_struct_sockaddr_in6" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_IN6 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "sa_family_t" "ac_cv_type_sa_family_t" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif " if test "x$ac_cv_type_sa_family_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SA_FAMILY_T 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct in6_addr" "s6_addr32" "ac_cv_member_struct_in6_addr_s6_addr32" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif " if test "x$ac_cv_member_struct_in6_addr_s6_addr32" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IN6_ADDR_S6_ADDR32 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct in6_addr" "s6_addr16" "ac_cv_member_struct_in6_addr_s6_addr16" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif " if test "x$ac_cv_member_struct_in6_addr_s6_addr16" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IN6_ADDR_S6_ADDR16 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct sockaddr_in" "sin_len" "ac_cv_member_struct_sockaddr_in_sin_len" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif " if test "x$ac_cv_member_struct_sockaddr_in_sin_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct sockaddr_in6" "sin6_len" "ac_cv_member_struct_sockaddr_in6_sin6_len" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif " if test "x$ac_cv_member_struct_sockaddr_in6_sin6_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "rlim_t" "ac_cv_type_rlim_t" "#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif " if test "x$ac_cv_type_rlim_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_RLIM_T 1 _ACEOF fi typename=`echo time_t | sed "s/[^a-zA-Z0-9_]/_/g"` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time_t is signed" >&5 $as_echo_n "checking whether time_t is signed... " >&6; } if eval \${ax_cv_decl_${typename}_signed+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_TIME_H #include #endif int main () { int foo [ 1 - 2 * !(((time_t) -1) < 0) ] ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "ax_cv_decl_${typename}_signed=\"yes\"" else eval "ax_cv_decl_${typename}_signed=\"no\"" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$ax_cv_decl_${typename}_signed { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } symbolname=`echo time_t | sed "s/[^a-zA-Z0-9_]/_/g" | tr "a-z" "A-Z"` if eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"yes\""; then $as_echo "#define TIME_T_IS_SIGNED 1" >>confdefs.h elif eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"no\""; then : fi if test "$ax_cv_decl_time_t_signed" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You have an unsigned time_t; some things will probably break. Please tell the Tor developers about your interesting platform." >&5 $as_echo "$as_me: WARNING: You have an unsigned time_t; some things will probably break. Please tell the Tor developers about your interesting platform." >&2;} fi typename=`echo size_t | sed "s/[^a-zA-Z0-9_]/_/g"` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether size_t is signed" >&5 $as_echo_n "checking whether size_t is signed... " >&6; } if eval \${ax_cv_decl_${typename}_signed+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif int main () { int foo [ 1 - 2 * !(((size_t) -1) < 0) ] ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "ax_cv_decl_${typename}_signed=\"yes\"" else eval "ax_cv_decl_${typename}_signed=\"no\"" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$ax_cv_decl_${typename}_signed { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } symbolname=`echo size_t | sed "s/[^a-zA-Z0-9_]/_/g" | tr "a-z" "A-Z"` if eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"yes\""; then tor_cv_size_t_signed=yes elif eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"no\""; then tor_cv_size_t_signed=no fi if test "$ax_cv_decl_size_t_signed" = yes; then as_fn_error $? "You have a signed size_t; that's grossly nonconformant." "$LINENO" 5 fi typename=`echo enum always | sed "s/[^a-zA-Z0-9_]/_/g"` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether enum always is signed" >&5 $as_echo_n "checking whether enum always is signed... " >&6; } if eval \${ax_cv_decl_${typename}_signed+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ enum always { AAA, BBB, CCC }; int main () { int foo [ 1 - 2 * !(((enum always) -1) < 0) ] ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "ax_cv_decl_${typename}_signed=\"yes\"" else eval "ax_cv_decl_${typename}_signed=\"no\"" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$ax_cv_decl_${typename}_signed { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } symbolname=`echo enum always | sed "s/[^a-zA-Z0-9_]/_/g" | tr "a-z" "A-Z"` if eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"yes\""; then $as_echo "#define ENUM_VALS_ARE_SIGNED 1" >>confdefs.h elif eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"no\""; then : fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of socklen_t" >&5 $as_echo_n "checking size of socklen_t... " >&6; } if ${ac_cv_sizeof_socklen_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (socklen_t))" "ac_cv_sizeof_socklen_t" "$ac_includes_default #ifdef HAVE_SYS_SOCKET_H #include #endif "; then : else if test "$ac_cv_type_socklen_t" = 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 77 "cannot compute sizeof (socklen_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_socklen_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_socklen_t" >&5 $as_echo "$ac_cv_sizeof_socklen_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_SOCKLEN_T $ac_cv_sizeof_socklen_t _ACEOF # We want to make sure that we _don't_ have a cell_t defined, like IRIX does. # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of cell_t" >&5 $as_echo_n "checking size of cell_t... " >&6; } if ${ac_cv_sizeof_cell_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (cell_t))" "ac_cv_sizeof_cell_t" "$ac_includes_default"; then : else if test "$ac_cv_type_cell_t" = 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 77 "cannot compute sizeof (cell_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_cell_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_cell_t" >&5 $as_echo "$ac_cv_sizeof_cell_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_CELL_T $ac_cv_sizeof_cell_t _ACEOF # Now make sure that NULL can be represented as zero bytes. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether memset(0) sets pointers to NULL" >&5 $as_echo_n "checking whether memset(0) sets pointers to NULL... " >&6; } if ${tor_cv_null_is_zero+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : tor_cv_null_is_zero=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDDEF_H #include #endif int main () { char *p1,*p2; p1=NULL; memset(&p2,0,sizeof(p2)); return memcmp(&p1,&p2,sizeof(char*))?1:0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : tor_cv_null_is_zero=yes else tor_cv_null_is_zero=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_null_is_zero" >&5 $as_echo "$tor_cv_null_is_zero" >&6; } if test "$tor_cv_null_is_zero" = cross ; then # Cross-compiling; let's hope that the target isn't raving mad. { $as_echo "$as_me:${as_lineno-$LINENO}: Cross-compiling: we'll assume that NULL is represented as a sequence of 0-valued bytes." >&5 $as_echo "$as_me: Cross-compiling: we'll assume that NULL is represented as a sequence of 0-valued bytes." >&6;} fi if test "$tor_cv_null_is_zero" != no; then $as_echo "#define NULL_REP_IS_ZERO_BYTES 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether memset(0) sets doubles to 0.0" >&5 $as_echo_n "checking whether memset(0) sets doubles to 0.0... " >&6; } if ${tor_cv_dbl0_is_zero+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : tor_cv_dbl0_is_zero=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDDEF_H #include #endif int main () { double d1,d2; d1=0; memset(&d2,0,sizeof(d2)); return memcmp(&d1,&d2,sizeof(d1))?1:0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : tor_cv_dbl0_is_zero=yes else tor_cv_dbl0_is_zero=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_dbl0_is_zero" >&5 $as_echo "$tor_cv_dbl0_is_zero" >&6; } if test "$tor_cv_dbl0_is_zero" = cross ; then # Cross-compiling; let's hope that the target isn't raving mad. { $as_echo "$as_me:${as_lineno-$LINENO}: Cross-compiling: we'll assume that 0.0 can be represented as a sequence of 0-valued bytes." >&5 $as_echo "$as_me: Cross-compiling: we'll assume that 0.0 can be represented as a sequence of 0-valued bytes." >&6;} fi if test "$tor_cv_dbl0_is_zero" != no; then $as_echo "#define DOUBLE_0_REP_IS_ZERO_BYTES 1" >>confdefs.h fi # And what happens when we malloc zero? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can malloc(0) safely." >&5 $as_echo_n "checking whether we can malloc(0) safely.... " >&6; } if ${tor_cv_malloc_zero_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : tor_cv_malloc_zero_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_STDDEF_H #include #endif int main () { return malloc(0)?0:1; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : tor_cv_malloc_zero_works=yes else tor_cv_malloc_zero_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_malloc_zero_works" >&5 $as_echo "$tor_cv_malloc_zero_works" >&6; } if test "$tor_cv_malloc_zero_works" = cross; then # Cross-compiling; let's hope that the target isn't raving mad. { $as_echo "$as_me:${as_lineno-$LINENO}: Cross-compiling: we'll assume that we need to check malloc() arguments for 0." >&5 $as_echo "$as_me: Cross-compiling: we'll assume that we need to check malloc() arguments for 0." >&6;} fi if test "$tor_cv_malloc_zero_works" = yes; then $as_echo "#define MALLOC_ZERO_WORKS 1" >>confdefs.h fi # whether we seem to be in a 2s-complement world. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using 2s-complement arithmetic" >&5 $as_echo_n "checking whether we are using 2s-complement arithmetic... " >&6; } if ${tor_cv_twos_complement+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : tor_cv_twos_complement=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int problem = ((-99) != (~99)+1); return problem ? 1 : 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : tor_cv_twos_complement=yes else tor_cv_twos_complement=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_twos_complement" >&5 $as_echo "$tor_cv_twos_complement" >&6; } if test "$tor_cv_twos_complement" = cross ; then # Cross-compiling; let's hope that the target isn't raving mad. { $as_echo "$as_me:${as_lineno-$LINENO}: Cross-compiling: we'll assume that negative integers are represented with two's complement." >&5 $as_echo "$as_me: Cross-compiling: we'll assume that negative integers are represented with two's complement." >&6;} fi if test "$tor_cv_twos_complement" != no ; then $as_echo "#define USING_TWOS_COMPLEMENT 1" >>confdefs.h fi # What does shifting a negative value do? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether right-shift on negative values does sign-extension" >&5 $as_echo_n "checking whether right-shift on negative values does sign-extension... " >&6; } if ${tor_cv_sign_extend+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : tor_cv_sign_extend=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int okay = (-60 >> 8) == -1; return okay ? 0 : 1; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : tor_cv_sign_extend=yes else tor_cv_sign_extend=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_sign_extend" >&5 $as_echo "$tor_cv_sign_extend" >&6; } if test "$tor_cv_sign_extend" = cross ; then # Cross-compiling; let's hope that the target isn't raving mad. { $as_echo "$as_me:${as_lineno-$LINENO}: Cross-compiling: we'll assume that right-shifting negative integers causes sign-extension" >&5 $as_echo "$as_me: Cross-compiling: we'll assume that right-shifting negative integers causes sign-extension" >&6;} fi if test "$tor_cv_sign_extend" != no ; then $as_echo "#define RSHIFT_DOES_SIGN_EXTEND 1" >>confdefs.h fi # Whether we should use the dmalloc memory allocation debugging library. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use dmalloc (debug memory allocation library)" >&5 $as_echo_n "checking whether to use dmalloc (debug memory allocation library)... " >&6; } # Check whether --with-dmalloc was given. if test "${with_dmalloc+set}" = set; then : withval=$with_dmalloc; if [ "$withval" = "yes" ]; then dmalloc=1 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else dmalloc=1 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else dmalloc=0; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if [ $dmalloc -eq 1 ]; then for ac_header in dmalloc.h do : ac_fn_c_check_header_mongrel "$LINENO" "dmalloc.h" "ac_cv_header_dmalloc_h" "$ac_includes_default" if test "x$ac_cv_header_dmalloc_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DMALLOC_H 1 _ACEOF else as_fn_error $? "dmalloc header file not found. Do you have the development files for dmalloc installed?" "$LINENO" 5 fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dmalloc_malloc" >&5 $as_echo_n "checking for library containing dmalloc_malloc... " >&6; } if ${ac_cv_search_dmalloc_malloc+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dmalloc_malloc (); int main () { return dmalloc_malloc (); ; return 0; } _ACEOF for ac_lib in '' dmallocth dmalloc; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_dmalloc_malloc=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_dmalloc_malloc+:} false; then : break fi done if ${ac_cv_search_dmalloc_malloc+:} false; then : else ac_cv_search_dmalloc_malloc=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dmalloc_malloc" >&5 $as_echo "$ac_cv_search_dmalloc_malloc" >&6; } ac_res=$ac_cv_search_dmalloc_malloc if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else as_fn_error $? "Libdmalloc library not found. If you enable it you better have it installed." "$LINENO" 5 fi $as_echo "#define USE_DMALLOC 1" >>confdefs.h $as_echo "#define DMALLOC_FUNC_CHECK 1" >>confdefs.h for ac_func in dmalloc_strdup dmalloc_strndup 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 fi # Check whether --with-tcmalloc was given. if test "${with_tcmalloc+set}" = set; then : withval=$with_tcmalloc; tcmalloc=yes else tcmalloc=no fi if test x$tcmalloc = xyes ; then LDFLAGS="-ltcmalloc $LDFLAGS" fi using_custom_malloc=no if test x$enable_openbsd_malloc = xyes ; then using_custom_malloc=yes fi if test x$tcmalloc = xyes ; then using_custom_malloc=yes fi if test $using_custom_malloc = no ; then for ac_func in mallinfo do : ac_fn_c_check_func "$LINENO" "mallinfo" "ac_cv_func_mallinfo" if test "x$ac_cv_func_mallinfo" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MALLINFO 1 _ACEOF fi done fi # By default, we're going to assume we don't have mlockall() # bionic and other platforms have various broken mlockall subsystems. # Some systems don't have a working mlockall, some aren't linkable, # and some have it but don't declare it. for ac_func in mlockall do : ac_fn_c_check_func "$LINENO" "mlockall" "ac_cv_func_mlockall" if test "x$ac_cv_func_mlockall" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MLOCKALL 1 _ACEOF fi done ac_fn_c_check_decl "$LINENO" "mlockall" "ac_cv_have_decl_mlockall" " #ifdef HAVE_SYS_MMAN_H #include #endif " if test "x$ac_cv_have_decl_mlockall" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_MLOCKALL $ac_have_decl _ACEOF # Allow user to specify an alternate syslog facility # Check whether --with-syslog-facility was given. if test "${with_syslog_facility+set}" = set; then : withval=$with_syslog_facility; syslog_facility="$withval" else syslog_facility="LOG_DAEMON" fi cat >>confdefs.h <<_ACEOF #define LOGFACILITY $syslog_facility _ACEOF # Check if we have getresuid and getresgid for ac_func in getresuid getresgid 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 # Check for gethostbyname_r in all its glorious incompatible versions. # (This logic is based on that in Python's configure.in) ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" if test "x$ac_cv_func_gethostbyname_r" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking how many arguments gethostbyname_r() wants" >&5 $as_echo_n "checking how many arguments gethostbyname_r() wants... " >&6; } OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *cp1, *cp2; struct hostent *h1, *h2; int i1, i2; (void)gethostbyname_r(cp1,h1,cp2,i1,&h2,&i2); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h $as_echo "#define HAVE_GETHOSTBYNAME_R_6_ARG 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: 6" >&5 $as_echo "6" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *cp1, *cp2; struct hostent *h1; int i1, i2; (void)gethostbyname_r(cp1,h1,cp2,i1,&i2); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h $as_echo "#define HAVE_GETHOSTBYNAME_R_5_ARG 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: 5" >&5 $as_echo "5" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *cp1; struct hostent *h1; struct hostent_data hd; (void) gethostbyname_r(cp1,h1,&hd); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h $as_echo "#define HAVE_GETHOSTBYNAME_R_3_ARG 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: 3" >&5 $as_echo "3" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: 0" >&5 $as_echo "0" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$OLD_CFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler supports __func__" >&5 $as_echo_n "checking whether the C compiler supports __func__... " >&6; } if ${tor_cv_have_func_macro+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main(int c, char **v) { puts(__func__); } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tor_cv_have_func_macro=yes else tor_cv_have_func_macro=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_have_func_macro" >&5 $as_echo "$tor_cv_have_func_macro" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler supports __FUNC__" >&5 $as_echo_n "checking whether the C compiler supports __FUNC__... " >&6; } if ${tor_cv_have_FUNC_macro+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main(int c, char **v) { puts(__FUNC__); } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tor_cv_have_FUNC_macro=yes else tor_cv_have_FUNC_macro=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_have_FUNC_macro" >&5 $as_echo "$tor_cv_have_FUNC_macro" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler supports __FUNCTION__" >&5 $as_echo_n "checking whether the C compiler supports __FUNCTION__... " >&6; } if ${tor_cv_have_FUNCTION_macro+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main(int c, char **v) { puts(__FUNCTION__); } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tor_cv_have_FUNCTION_macro=yes else tor_cv_have_FUNCTION_macro=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_have_FUNCTION_macro" >&5 $as_echo "$tor_cv_have_FUNCTION_macro" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have extern char **environ already declared" >&5 $as_echo_n "checking whether we have extern char **environ already declared... " >&6; } if ${tor_cv_have_environ_declared+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* We define _GNU_SOURCE here because it is also defined in compat.c. * Without it environ doesn't get declared. */ #define _GNU_SOURCE #ifdef HAVE_UNISTD_H #include #endif #include int main(int c, char **v) { char **t = environ; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tor_cv_have_environ_declared=yes else tor_cv_have_environ_declared=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tor_cv_have_environ_declared" >&5 $as_echo "$tor_cv_have_environ_declared" >&6; } if test "$tor_cv_have_func_macro" = 'yes'; then $as_echo "#define HAVE_MACRO__func__ 1" >>confdefs.h fi if test "$tor_cv_have_FUNC_macro" = 'yes'; then $as_echo "#define HAVE_MACRO__FUNC__ 1" >>confdefs.h fi if test "$tor_cv_have_FUNCTION_macro" = 'yes'; then $as_echo "#define HAVE_MACRO__FUNCTION__ 1" >>confdefs.h fi if test "$tor_cv_have_environ_declared" = 'yes'; then $as_echo "#define HAVE_EXTERN_ENVIRON_DECLARED 1" >>confdefs.h fi # $prefix stores the value of the --prefix command line option, or # NONE if the option wasn't set. In the case that it wasn't set, make # it be the default, so that we can use it to expand directories now. if test "x$prefix" = "xNONE"; then prefix=$ac_default_prefix fi # and similarly for $exec_prefix if test "x$exec_prefix" = "xNONE"; then exec_prefix=$prefix fi if test "x$BUILDDIR" = "x"; then BUILDDIR=`pwd` fi cat >>confdefs.h <<_ACEOF #define BUILDDIR "$BUILDDIR" _ACEOF if test "x$CONFDIR" = "x"; then CONFDIR=`eval echo $sysconfdir/tor` fi cat >>confdefs.h <<_ACEOF #define CONFDIR "$CONFDIR" _ACEOF BINDIR=`eval echo $bindir` LOCALSTATEDIR=`eval echo $localstatedir` if test "$bwin32" = true; then # Test if the linker supports the --nxcompat and --dynamicbase options # for Windows save_LDFLAGS="$LDFLAGS" LDFLAGS="-Wl,--nxcompat -Wl,--dynamicbase" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker supports DllCharacteristics" >&5 $as_echo_n "checking whether the linker supports DllCharacteristics... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } save_LDFLAGS="$save_LDFLAGS $LDFLAGS" 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 LDFLAGS="$save_LDFLAGS" fi # Set CFLAGS _after_ all the above checks, since our warnings are stricter # than autoconf's macros like. if test "$GCC" = yes; then # Disable GCC's strict aliasing checks. They are an hours-to-debug # accident waiting to happen. CFLAGS="$CFLAGS -Wall -fno-strict-aliasing" else # Autoconf sets -g -O2 by default. Override optimization level # for non-gcc compilers CFLAGS="$CFLAGS -O" enable_gcc_warnings=no enable_gcc_warnings_advisory=no fi # OS X Lion started deprecating the system openssl. Let's just disable # all deprecation warnings on OS X. Also, to potentially make the binary # a little smaller, let's enable dead_strip. case "$host_os" in darwin*) CFLAGS="$CFLAGS -Wno-deprecated-declarations" LDFLAGS="$LDFLAGS -dead_strip" ;; esac # Add some more warnings which we use in development but not in the # released versions. (Some relevant gcc versions can't handle these.) if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xyes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #if !defined(__GNUC__) || (__GNUC__ < 4) #error #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_gcc4=yes else have_gcc4=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) #error #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_gcc42=yes else have_gcc42=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) #error #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_gcc43=yes else have_gcc43=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wshorten-64-to-32" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_shorten64_flag=yes else have_shorten64_flag=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$save_CFLAGS" case $host in *-*-openbsd* | *-*-bitrig*) # Some OpenBSD versions (like 4.8) have -Wsystem-headers by default. # That's fine, except that the headers don't pass -Wredundant-decls. # Therefore, let's disable -Wsystem-headers when we're building # with maximal warnings on OpenBSD. CFLAGS="$CFLAGS -Wno-system-headers" ;; esac CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith" CFLAGS="$CFLAGS -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings" CFLAGS="$CFLAGS -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat=2" CFLAGS="$CFLAGS -Wwrite-strings -Wmissing-declarations -Wredundant-decls" CFLAGS="$CFLAGS -Wnested-externs -Wbad-function-cast -Wswitch-enum" if test x$enable_gcc_warnings = xyes; then CFLAGS="$CFLAGS -Werror" fi # Disabled, so we can use mallinfo(): -Waggregate-return if test x$have_gcc4 = xyes ; then # These warnings break gcc 3.3.5 and work on gcc 4.0.2 CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement -Wold-style-definition" fi if test x$have_gcc42 = xyes ; then # These warnings break gcc 4.0.2 and work on gcc 4.2 # XXXX020 See if any of these work with earlier versions. CFLAGS="$CFLAGS -Waddress -Wmissing-noreturn -Wstrict-overflow=1" # We used to use -Wstrict-overflow=5, but that breaks us heavily under 4.3. fi if test x$have_gcc42 = xyes && test x$have_clang = xno; then # These warnings break gcc 4.0.2 and clang, but work on gcc 4.2 CFLAGS="$CFLAGS -Wnormalized=id -Woverride-init" fi if test x$have_gcc43 = xyes ; then # These warnings break gcc 4.2 and work on gcc 4.3 # XXXX020 See if any of these work with earlier versions. CFLAGS="$CFLAGS -Wextra -Warray-bounds" fi if test x$have_shorten64_flag = xyes ; then CFLAGS="$CFLAGS -Wshorten-64-to-32" fi ##This will break the world on some 64-bit architectures # CFLAGS="$CFLAGS -Winline" fi CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib" ac_config_files="$ac_config_files Doxyfile Makefile contrib/suse/tor.sh contrib/tor.logrotate contrib/tor.sh contrib/torctl contrib/torify src/config/torrc.sample" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${USE_OPENBSD_MALLOC_TRUE}" && test -z "${USE_OPENBSD_MALLOC_FALSE}"; then as_fn_error $? "conditional \"USE_OPENBSD_MALLOC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_ASCIIDOC_TRUE}" && test -z "${USE_ASCIIDOC_FALSE}"; then as_fn_error $? "conditional \"USE_ASCIIDOC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_FW_HELPER_TRUE}" && test -z "${USE_FW_HELPER_FALSE}"; then as_fn_error $? "conditional \"USE_FW_HELPER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${NAT_PMP_TRUE}" && test -z "${NAT_PMP_FALSE}"; then as_fn_error $? "conditional \"NAT_PMP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${MINIUPNPC_TRUE}" && test -z "${MINIUPNPC_FALSE}"; then as_fn_error $? "conditional \"MINIUPNPC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_NT_SERVICES_TRUE}" && test -z "${BUILD_NT_SERVICES_FALSE}"; then as_fn_error $? "conditional \"BUILD_NT_SERVICES\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_EXTERNAL_EVDNS_TRUE}" && test -z "${USE_EXTERNAL_EVDNS_FALSE}"; then as_fn_error $? "conditional \"USE_EXTERNAL_EVDNS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_BUFFEREVENTS_TRUE}" && test -z "${USE_BUFFEREVENTS_FALSE}"; then as_fn_error $? "conditional \"USE_BUFFEREVENTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_CURVE25519_DONNA_TRUE}" && test -z "${BUILD_CURVE25519_DONNA_FALSE}"; then as_fn_error $? "conditional \"BUILD_CURVE25519_DONNA\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_CURVE25519_DONNA_C64_TRUE}" && test -z "${BUILD_CURVE25519_DONNA_C64_FALSE}"; then as_fn_error $? "conditional \"BUILD_CURVE25519_DONNA_C64\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${CURVE25519_ENABLED_TRUE}" && test -z "${CURVE25519_ENABLED_FALSE}"; then as_fn_error $? "conditional \"CURVE25519_ENABLED\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by tor $as_me 0.2.4.20, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ tor config.status 0.2.4.20 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "orconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS orconfig.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Doxyfile") CONFIG_FILES="$CONFIG_FILES Doxyfile" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "contrib/suse/tor.sh") CONFIG_FILES="$CONFIG_FILES contrib/suse/tor.sh" ;; "contrib/tor.logrotate") CONFIG_FILES="$CONFIG_FILES contrib/tor.logrotate" ;; "contrib/tor.sh") CONFIG_FILES="$CONFIG_FILES contrib/tor.sh" ;; "contrib/torctl") CONFIG_FILES="$CONFIG_FILES contrib/torctl" ;; "contrib/torify") CONFIG_FILES="$CONFIG_FILES contrib/torify" ;; "src/config/torrc.sample") CONFIG_FILES="$CONFIG_FILES src/config/torrc.sample" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi if test -x /usr/bin/perl && test -x ./contrib/updateVersions.pl ; then ./contrib/updateVersions.pl fi tor-0.2.4.20/Makefile.in0000644000175000017500000043656412255745724011566 00000000000000# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Copyright (c) 2001-2004, Roger Dingledine # Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson # Copyright (c) 2007-2011, The Tor Project, Inc. # See LICENSE for licensing information # We use a two-step process to generate documentation from asciidoc files. # # First, we use asciidoc/a2x to process the asciidoc files into .1.in and # .html.in files (see the asciidoc-helper.sh script). These are the same as # the regular .1 and .html files, except that they still have some autoconf # variables set in them. # # Second, we use config.status to turn .1.in files into .1 files and # .html.in files into .html files. # # We do the steps in this order so that we can ship the .*.in files as # part of the source distribution, so that people without asciidoc can # just use the .1 and .html files. VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = src/or/tor$(EXEEXT) src/tools/tor-resolve$(EXEEXT) \ src/tools/tor-gencert$(EXEEXT) $(am__EXEEXT_1) TESTS = src/test/test$(EXEEXT) noinst_PROGRAMS = src/test/test$(EXEEXT) src/test/test-child$(EXEEXT) \ src/test/bench$(EXEEXT) $(am__EXEEXT_2) \ src/tools/tor-checkkey$(EXEEXT) DIST_COMMON = README $(am__configure_deps) $(noinst_HEADERS) \ $(srcdir)/Doxyfile.in $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/contrib/include.am \ $(srcdir)/contrib/suse/include.am $(srcdir)/doc/include.am \ $(srcdir)/orconfig.h.in $(srcdir)/src/common/include.am \ $(srcdir)/src/config/include.am $(srcdir)/src/ext/include.am \ $(srcdir)/src/include.am $(srcdir)/src/or/include.am \ $(srcdir)/src/test/include.am $(srcdir)/src/tools/include.am \ $(srcdir)/src/tools/tor-fw-helper/include.am \ $(srcdir)/src/win32/include.am $(top_srcdir)/configure \ $(top_srcdir)/contrib/suse/tor.sh.in \ $(top_srcdir)/contrib/tor.logrotate.in \ $(top_srcdir)/contrib/tor.sh.in \ $(top_srcdir)/contrib/torctl.in \ $(top_srcdir)/contrib/torify.in \ $(top_srcdir)/src/config/torrc.sample.in ChangeLog INSTALL \ compile config.guess config.sub depcomp install-sh missing @BUILD_CURVE25519_DONNA_TRUE@am__append_1 = src/common/libcurve25519_donna.a @BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@am__append_2 = src/common/libcurve25519_donna.a @CURVE25519_ENABLED_TRUE@am__append_3 = src/test/test-ntor-cl @USE_FW_HELPER_TRUE@am__append_4 = src/tools/tor-fw-helper/tor-fw-helper subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_sign.m4 \ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = orconfig.h CONFIG_CLEAN_FILES = Doxyfile contrib/suse/tor.sh \ contrib/tor.logrotate contrib/tor.sh contrib/torctl \ contrib/torify src/config/torrc.sample CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ src_common_libcurve25519_donna_a_AR = $(AR) $(ARFLAGS) src_common_libcurve25519_donna_a_LIBADD = am__src_common_libcurve25519_donna_a_SOURCES_DIST = \ src/ext/curve25519_donna/curve25519-donna-c64.c \ src/ext/curve25519_donna/curve25519-donna.c am__dirstamp = $(am__leading_dot)dirstamp @BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@am_src_common_libcurve25519_donna_a_OBJECTS = src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.$(OBJEXT) @BUILD_CURVE25519_DONNA_TRUE@am_src_common_libcurve25519_donna_a_OBJECTS = src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.$(OBJEXT) src_common_libcurve25519_donna_a_OBJECTS = \ $(am_src_common_libcurve25519_donna_a_OBJECTS) src_common_libor_crypto_a_AR = $(AR) $(ARFLAGS) src_common_libor_crypto_a_LIBADD = am__src_common_libor_crypto_a_SOURCES_DIST = src/common/aes.c \ src/common/crypto.c src/common/crypto_format.c \ src/common/torgzip.c src/common/tortls.c \ src/common/crypto_curve25519.c @CURVE25519_ENABLED_TRUE@am__objects_1 = src/common/crypto_curve25519.$(OBJEXT) am_src_common_libor_crypto_a_OBJECTS = src/common/aes.$(OBJEXT) \ src/common/crypto.$(OBJEXT) src/common/crypto_format.$(OBJEXT) \ src/common/torgzip.$(OBJEXT) src/common/tortls.$(OBJEXT) \ $(am__objects_1) src_common_libor_crypto_a_OBJECTS = \ $(am_src_common_libor_crypto_a_OBJECTS) src_common_libor_event_a_AR = $(AR) $(ARFLAGS) src_common_libor_event_a_LIBADD = am_src_common_libor_event_a_OBJECTS = \ src/common/compat_libevent.$(OBJEXT) src_common_libor_event_a_OBJECTS = \ $(am_src_common_libor_event_a_OBJECTS) src_common_libor_a_AR = $(AR) $(ARFLAGS) src_common_libor_a_LIBADD = am__src_common_libor_a_SOURCES_DIST = src/common/address.c \ src/common/compat.c src/common/container.c src/common/di_ops.c \ src/common/log.c src/common/memarea.c src/common/mempool.c \ src/common/procmon.c src/common/util.c \ src/common/util_codedigest.c src/ext/OpenBSD_malloc_Linux.c @USE_OPENBSD_MALLOC_TRUE@am__objects_2 = src/ext/OpenBSD_malloc_Linux.$(OBJEXT) am_src_common_libor_a_OBJECTS = src/common/address.$(OBJEXT) \ src/common/compat.$(OBJEXT) src/common/container.$(OBJEXT) \ src/common/di_ops.$(OBJEXT) src/common/log.$(OBJEXT) \ src/common/memarea.$(OBJEXT) src/common/mempool.$(OBJEXT) \ src/common/procmon.$(OBJEXT) src/common/util.$(OBJEXT) \ src/common/util_codedigest.$(OBJEXT) $(am__objects_2) src_common_libor_a_OBJECTS = $(am_src_common_libor_a_OBJECTS) src_or_libtor_a_AR = $(AR) $(ARFLAGS) src_or_libtor_a_LIBADD = am__src_or_libtor_a_SOURCES_DIST = src/or/addressmap.c \ src/or/buffers.c src/or/channel.c src/or/channeltls.c \ src/or/circuitbuild.c src/or/circuitlist.c src/or/circuitmux.c \ src/or/circuitmux_ewma.c src/or/circuitstats.c \ src/or/circuituse.c src/or/command.c src/or/config.c \ src/or/confparse.c src/or/connection.c \ src/or/connection_edge.c src/or/connection_or.c \ src/or/control.c src/or/cpuworker.c src/or/directory.c \ src/or/dirserv.c src/or/dirvote.c src/or/dns.c \ src/or/dnsserv.c src/or/fp_pair.c src/or/geoip.c \ src/or/entrynodes.c src/or/hibernate.c src/or/main.c \ src/or/microdesc.c src/or/networkstatus.c src/or/nodelist.c \ src/or/onion.c src/or/onion_fast.c src/or/onion_tap.c \ src/or/transports.c src/or/policies.c src/or/reasons.c \ src/or/relay.c src/or/rendclient.c src/or/rendcommon.c \ src/or/rendmid.c src/or/rendservice.c src/or/rephist.c \ src/or/replaycache.c src/or/router.c src/or/routerlist.c \ src/or/routerparse.c src/or/routerset.c src/or/statefile.c \ src/or/status.c src/ext/eventdns.c src/or/ntmain.c \ src/or/onion_ntor.c src/or/config_codedigest.c @USE_EXTERNAL_EVDNS_FALSE@am__objects_3 = src/ext/eventdns.$(OBJEXT) @BUILD_NT_SERVICES_TRUE@am__objects_4 = src/or/ntmain.$(OBJEXT) @CURVE25519_ENABLED_TRUE@am__objects_5 = src/or/onion_ntor.$(OBJEXT) am_src_or_libtor_a_OBJECTS = src/or/addressmap.$(OBJEXT) \ src/or/buffers.$(OBJEXT) src/or/channel.$(OBJEXT) \ src/or/channeltls.$(OBJEXT) src/or/circuitbuild.$(OBJEXT) \ src/or/circuitlist.$(OBJEXT) src/or/circuitmux.$(OBJEXT) \ src/or/circuitmux_ewma.$(OBJEXT) src/or/circuitstats.$(OBJEXT) \ src/or/circuituse.$(OBJEXT) src/or/command.$(OBJEXT) \ src/or/config.$(OBJEXT) src/or/confparse.$(OBJEXT) \ src/or/connection.$(OBJEXT) src/or/connection_edge.$(OBJEXT) \ src/or/connection_or.$(OBJEXT) src/or/control.$(OBJEXT) \ src/or/cpuworker.$(OBJEXT) src/or/directory.$(OBJEXT) \ src/or/dirserv.$(OBJEXT) src/or/dirvote.$(OBJEXT) \ src/or/dns.$(OBJEXT) src/or/dnsserv.$(OBJEXT) \ src/or/fp_pair.$(OBJEXT) src/or/geoip.$(OBJEXT) \ src/or/entrynodes.$(OBJEXT) src/or/hibernate.$(OBJEXT) \ src/or/main.$(OBJEXT) src/or/microdesc.$(OBJEXT) \ src/or/networkstatus.$(OBJEXT) src/or/nodelist.$(OBJEXT) \ src/or/onion.$(OBJEXT) src/or/onion_fast.$(OBJEXT) \ src/or/onion_tap.$(OBJEXT) src/or/transports.$(OBJEXT) \ src/or/policies.$(OBJEXT) src/or/reasons.$(OBJEXT) \ src/or/relay.$(OBJEXT) src/or/rendclient.$(OBJEXT) \ src/or/rendcommon.$(OBJEXT) src/or/rendmid.$(OBJEXT) \ src/or/rendservice.$(OBJEXT) src/or/rephist.$(OBJEXT) \ src/or/replaycache.$(OBJEXT) src/or/router.$(OBJEXT) \ src/or/routerlist.$(OBJEXT) src/or/routerparse.$(OBJEXT) \ src/or/routerset.$(OBJEXT) src/or/statefile.$(OBJEXT) \ src/or/status.$(OBJEXT) $(am__objects_3) $(am__objects_4) \ $(am__objects_5) src/or/config_codedigest.$(OBJEXT) src_or_libtor_a_OBJECTS = $(am_src_or_libtor_a_OBJECTS) @USE_FW_HELPER_TRUE@am__EXEEXT_1 = src/tools/tor-fw-helper/tor-fw-helper$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(confdir)" \ "$(DESTDIR)$(docdir)" "$(DESTDIR)$(tordatadir)" @CURVE25519_ENABLED_TRUE@am__EXEEXT_2 = \ @CURVE25519_ENABLED_TRUE@ src/test/test-ntor-cl$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_src_or_tor_OBJECTS = src/or/tor_main.$(OBJEXT) src_or_tor_OBJECTS = $(am_src_or_tor_OBJECTS) @BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@am__DEPENDENCIES_1 = src/common/libcurve25519_donna.a @BUILD_CURVE25519_DONNA_TRUE@am__DEPENDENCIES_1 = \ @BUILD_CURVE25519_DONNA_TRUE@ src/common/libcurve25519_donna.a src_or_tor_DEPENDENCIES = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(am__DEPENDENCIES_1) \ src/common/libor-event.a src_or_tor_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(src_or_tor_LDFLAGS) \ $(LDFLAGS) -o $@ am_src_test_bench_OBJECTS = src/test/src_test_bench-bench.$(OBJEXT) src_test_bench_OBJECTS = $(am_src_test_bench_OBJECTS) src_test_bench_DEPENDENCIES = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(am__DEPENDENCIES_1) \ src/common/libor-event.a src_test_bench_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(src_test_bench_LDFLAGS) $(LDFLAGS) -o $@ am_src_test_test_OBJECTS = src/test/src_test_test-test.$(OBJEXT) \ src/test/src_test_test-test_addr.$(OBJEXT) \ src/test/src_test_test-test_cell_formats.$(OBJEXT) \ src/test/src_test_test-test_containers.$(OBJEXT) \ src/test/src_test_test-test_crypto.$(OBJEXT) \ src/test/src_test_test-test_data.$(OBJEXT) \ src/test/src_test_test-test_dir.$(OBJEXT) \ src/test/src_test_test-test_introduce.$(OBJEXT) \ src/test/src_test_test-test_microdesc.$(OBJEXT) \ src/test/src_test_test-test_pt.$(OBJEXT) \ src/test/src_test_test-test_replay.$(OBJEXT) \ src/test/src_test_test-test_util.$(OBJEXT) \ src/test/src_test_test-test_config.$(OBJEXT) \ src/ext/src_test_test-tinytest.$(OBJEXT) src_test_test_OBJECTS = $(am_src_test_test_OBJECTS) src_test_test_DEPENDENCIES = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(am__DEPENDENCIES_1) \ src/common/libor-event.a src_test_test_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(src_test_test_LDFLAGS) $(LDFLAGS) -o $@ src_test_test_child_SOURCES = src/test/test-child.c src_test_test_child_OBJECTS = src/test/test-child.$(OBJEXT) src_test_test_child_LDADD = $(LDADD) am__src_test_test_ntor_cl_SOURCES_DIST = src/test/test_ntor_cl.c @CURVE25519_ENABLED_TRUE@am_src_test_test_ntor_cl_OBJECTS = \ @CURVE25519_ENABLED_TRUE@ src/test/test_ntor_cl.$(OBJEXT) src_test_test_ntor_cl_OBJECTS = $(am_src_test_test_ntor_cl_OBJECTS) @CURVE25519_ENABLED_TRUE@src_test_test_ntor_cl_DEPENDENCIES = \ @CURVE25519_ENABLED_TRUE@ src/or/libtor.a src/common/libor.a \ @CURVE25519_ENABLED_TRUE@ src/common/libor-crypto.a \ @CURVE25519_ENABLED_TRUE@ $(am__DEPENDENCIES_1) src_test_test_ntor_cl_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(src_test_test_ntor_cl_LDFLAGS) $(LDFLAGS) -o $@ am_src_tools_tor_checkkey_OBJECTS = src/tools/tor-checkkey.$(OBJEXT) src_tools_tor_checkkey_OBJECTS = $(am_src_tools_tor_checkkey_OBJECTS) src_tools_tor_checkkey_DEPENDENCIES = src/common/libor.a \ src/common/libor-crypto.a $(am__DEPENDENCIES_1) src_tools_tor_checkkey_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(src_tools_tor_checkkey_LDFLAGS) $(LDFLAGS) -o $@ am_src_tools_tor_fw_helper_tor_fw_helper_OBJECTS = src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.$(OBJEXT) \ src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.$(OBJEXT) \ src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.$(OBJEXT) src_tools_tor_fw_helper_tor_fw_helper_OBJECTS = \ $(am_src_tools_tor_fw_helper_tor_fw_helper_OBJECTS) am__DEPENDENCIES_2 = src_tools_tor_fw_helper_tor_fw_helper_DEPENDENCIES = \ src/common/libor.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) src_tools_tor_fw_helper_tor_fw_helper_LINK = $(CCLD) $(AM_CFLAGS) \ $(CFLAGS) $(src_tools_tor_fw_helper_tor_fw_helper_LDFLAGS) \ $(LDFLAGS) -o $@ am_src_tools_tor_gencert_OBJECTS = src/tools/tor-gencert.$(OBJEXT) src_tools_tor_gencert_OBJECTS = $(am_src_tools_tor_gencert_OBJECTS) src_tools_tor_gencert_DEPENDENCIES = src/common/libor.a \ src/common/libor-crypto.a $(am__DEPENDENCIES_1) src_tools_tor_gencert_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(src_tools_tor_gencert_LDFLAGS) $(LDFLAGS) -o $@ am_src_tools_tor_resolve_OBJECTS = src/tools/tor-resolve.$(OBJEXT) src_tools_tor_resolve_OBJECTS = $(am_src_tools_tor_resolve_OBJECTS) src_tools_tor_resolve_DEPENDENCIES = src/common/libor.a src_tools_tor_resolve_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(src_tools_tor_resolve_LDFLAGS) $(LDFLAGS) -o $@ am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } SCRIPTS = $(bin_SCRIPTS) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(src_common_libcurve25519_donna_a_SOURCES) \ $(src_common_libor_crypto_a_SOURCES) \ $(src_common_libor_event_a_SOURCES) \ $(src_common_libor_a_SOURCES) $(src_or_libtor_a_SOURCES) \ $(src_or_tor_SOURCES) $(src_test_bench_SOURCES) \ $(src_test_test_SOURCES) src/test/test-child.c \ $(src_test_test_ntor_cl_SOURCES) \ $(src_tools_tor_checkkey_SOURCES) \ $(src_tools_tor_fw_helper_tor_fw_helper_SOURCES) \ $(src_tools_tor_gencert_SOURCES) \ $(src_tools_tor_resolve_SOURCES) DIST_SOURCES = $(am__src_common_libcurve25519_donna_a_SOURCES_DIST) \ $(am__src_common_libor_crypto_a_SOURCES_DIST) \ $(src_common_libor_event_a_SOURCES) \ $(am__src_common_libor_a_SOURCES_DIST) \ $(am__src_or_libtor_a_SOURCES_DIST) $(src_or_tor_SOURCES) \ $(src_test_bench_SOURCES) $(src_test_test_SOURCES) \ src/test/test-child.c \ $(am__src_test_test_ntor_cl_SOURCES_DIST) \ $(src_tools_tor_checkkey_SOURCES) \ $(src_tools_tor_fw_helper_tor_fw_helper_SOURCES) \ $(src_tools_tor_gencert_SOURCES) \ $(src_tools_tor_resolve_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac man1dir = $(mandir)/man1 NROFF = nroff MANS = $(nodist_man1_MANS) DATA = $(conf_DATA) $(doc_DATA) $(tordata_DATA) HEADERS = $(noinst_HEADERS) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print A2X = @A2X@ ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BUILDDIR = @BUILDDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDIR = @CONFDIR@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURVE25519_LIBS = @CURVE25519_LIBS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LOCALSTATEDIR = @LOCALSTATEDIR@ LOGFACILITY = @LOGFACILITY@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ OPENSSL = @OPENSSL@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHA1SUM = @SHA1SUM@ SHELL = @SHELL@ STRIP = @STRIP@ TORGROUP = @TORGROUP@ TORUSER = @TORUSER@ TOR_CPPFLAGS_libevent = @TOR_CPPFLAGS_libevent@ TOR_CPPFLAGS_libminiupnpc = @TOR_CPPFLAGS_libminiupnpc@ TOR_CPPFLAGS_libnatpmp = @TOR_CPPFLAGS_libnatpmp@ TOR_CPPFLAGS_openssl = @TOR_CPPFLAGS_openssl@ TOR_CPPFLAGS_zlib = @TOR_CPPFLAGS_zlib@ TOR_LDFLAGS_libevent = @TOR_LDFLAGS_libevent@ TOR_LDFLAGS_libminiupnpc = @TOR_LDFLAGS_libminiupnpc@ TOR_LDFLAGS_libnatpmp = @TOR_LDFLAGS_libnatpmp@ TOR_LDFLAGS_openssl = @TOR_LDFLAGS_openssl@ TOR_LDFLAGS_zlib = @TOR_LDFLAGS_zlib@ TOR_LIBEVENT_LIBS = @TOR_LIBEVENT_LIBS@ TOR_LIB_GDI = @TOR_LIB_GDI@ TOR_LIB_IPHLPAPI = @TOR_LIB_IPHLPAPI@ TOR_LIB_MATH = @TOR_LIB_MATH@ TOR_LIB_WS32 = @TOR_LIB_WS32@ TOR_OPENSSL_LIBS = @TOR_OPENSSL_LIBS@ TOR_ZLIB_LIBS = @TOR_ZLIB_LIBS@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # "foreign" means we don't follow GNU package layout standards # 1.9 means we require automake vesion 1.9 AUTOMAKE_OPTIONS = foreign 1.9 subdir-objects ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES = src/common/libor.a src/common/libor-crypto.a \ src/common/libor-event.a $(am__append_1) $(am__append_2) \ src/or/libtor.a EXTRA_DIST = src/ext/README src/common/common_sha1.i \ src/common/Makefile.nmake src/or/ntmain.c src/or/or_sha1.i \ src/or/Makefile.nmake src/win32/orconfig.h src/config/geoip \ src/config/geoip6 doc/HACKING doc/asciidoc-helper.sh \ $(html_in) $(man_in) $(txt_in) doc/state-contents.txt \ contrib/suse/tor.sh contrib/cross.sh contrib/exitlist \ contrib/linux-tor-prio.sh contrib/package_nsis-mingw.sh \ contrib/rc.subr contrib/tor-ctrl.sh \ contrib/tor-exit-notice.html contrib/tor-mingw.nsi.in \ contrib/tor.ico contrib/tor.nsi.in contrib/tor.sh \ contrib/torctl ChangeLog INSTALL LICENSE Makefile.nmake README \ ReleaseNotes noinst_HEADERS = $(EXTHEADERS) $(COMMONHEADERS) $(ORHEADERS) \ micro-revision.i src/test/test.h \ src/tools/tor-fw-helper/tor-fw-helper.h \ src/tools/tor-fw-helper/tor-fw-helper-natpmp.h \ src/tools/tor-fw-helper/tor-fw-helper-upnp.h CLEANFILES = micro-revision.i src/or/micro-revision.i \ $(asciidoc_product) config.log DISTCLEANFILES = src/common/common_sha1.i $(html_in) $(man_in) bin_SCRIPTS = contrib/torify #CFLAGS = -Wall -Wpointer-arith -O2 AM_CPPFLAGS = -I$(srcdir)/src/ext -Isrc/ext -I$(srcdir)/src/common \ -Isrc/common -I$(srcdir)/src/or -Isrc/or \ -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" EXTHEADERS = \ src/ext/ht.h \ src/ext/eventdns.h \ src/ext/tinytest.h \ src/ext/strlcat.c \ src/ext/strlcpy.c \ src/ext/tinytest_macros.h \ src/ext/tor_queue.h @USE_OPENBSD_MALLOC_FALSE@libor_extra_source = @USE_OPENBSD_MALLOC_TRUE@libor_extra_source = src/ext/OpenBSD_malloc_Linux.c @BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@src_common_libcurve25519_donna_a_SOURCES = \ @BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@ src/ext/curve25519_donna/curve25519-donna-c64.c @BUILD_CURVE25519_DONNA_TRUE@src_common_libcurve25519_donna_a_SOURCES = \ @BUILD_CURVE25519_DONNA_TRUE@ src/ext/curve25519_donna/curve25519-donna.c @BUILD_CURVE25519_DONNA_C64_FALSE@@BUILD_CURVE25519_DONNA_FALSE@LIBDONNA = @BUILD_CURVE25519_DONNA_C64_TRUE@@BUILD_CURVE25519_DONNA_FALSE@LIBDONNA = src/common/libcurve25519_donna.a @BUILD_CURVE25519_DONNA_TRUE@LIBDONNA = src/common/libcurve25519_donna.a src_common_libcurve25519_donna_a_CFLAGS = @CURVE25519_ENABLED_TRUE@libcrypto_extra_source = src/common/crypto_curve25519.c src_common_libor_a_SOURCES = \ src/common/address.c \ src/common/compat.c \ src/common/container.c \ src/common/di_ops.c \ src/common/log.c \ src/common/memarea.c \ src/common/mempool.c \ src/common/procmon.c \ src/common/util.c \ src/common/util_codedigest.c \ $(libor_extra_source) src_common_libor_crypto_a_SOURCES = \ src/common/aes.c \ src/common/crypto.c \ src/common/crypto_format.c \ src/common/torgzip.c \ src/common/tortls.c \ $(libcrypto_extra_source) src_common_libor_event_a_SOURCES = src/common/compat_libevent.c COMMONHEADERS = \ src/common/address.h \ src/common/aes.h \ src/common/ciphers.inc \ src/common/compat.h \ src/common/compat_libevent.h \ src/common/container.h \ src/common/crypto.h \ src/common/crypto_curve25519.h \ src/common/di_ops.h \ src/common/memarea.h \ src/common/mempool.h \ src/common/procmon.h \ src/common/torgzip.h \ src/common/torint.h \ src/common/torlog.h \ src/common/tortls.h \ src/common/util.h @BUILD_NT_SERVICES_FALSE@tor_platform_source = @BUILD_NT_SERVICES_TRUE@tor_platform_source = src/or/ntmain.c @USE_EXTERNAL_EVDNS_FALSE@evdns_source = src/ext/eventdns.c @USE_EXTERNAL_EVDNS_TRUE@evdns_source = @CURVE25519_ENABLED_FALSE@onion_ntor_source = @CURVE25519_ENABLED_TRUE@onion_ntor_source = src/or/onion_ntor.c src_or_libtor_a_SOURCES = \ src/or/addressmap.c \ src/or/buffers.c \ src/or/channel.c \ src/or/channeltls.c \ src/or/circuitbuild.c \ src/or/circuitlist.c \ src/or/circuitmux.c \ src/or/circuitmux_ewma.c \ src/or/circuitstats.c \ src/or/circuituse.c \ src/or/command.c \ src/or/config.c \ src/or/confparse.c \ src/or/connection.c \ src/or/connection_edge.c \ src/or/connection_or.c \ src/or/control.c \ src/or/cpuworker.c \ src/or/directory.c \ src/or/dirserv.c \ src/or/dirvote.c \ src/or/dns.c \ src/or/dnsserv.c \ src/or/fp_pair.c \ src/or/geoip.c \ src/or/entrynodes.c \ src/or/hibernate.c \ src/or/main.c \ src/or/microdesc.c \ src/or/networkstatus.c \ src/or/nodelist.c \ src/or/onion.c \ src/or/onion_fast.c \ src/or/onion_tap.c \ src/or/transports.c \ src/or/policies.c \ src/or/reasons.c \ src/or/relay.c \ src/or/rendclient.c \ src/or/rendcommon.c \ src/or/rendmid.c \ src/or/rendservice.c \ src/or/rephist.c \ src/or/replaycache.c \ src/or/router.c \ src/or/routerlist.c \ src/or/routerparse.c \ src/or/routerset.c \ src/or/statefile.c \ src/or/status.c \ $(evdns_source) \ $(tor_platform_source) \ $(onion_ntor_source) \ src/or/config_codedigest.c #libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \ # ../common/libor-event.a src_or_tor_SOURCES = src/or/tor_main.c # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on windows, but I assure you that it # matters a lot there, and is quite hard to debug if you forget to do it. src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(LIBDONNA) \ src/common/libor-event.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ ORHEADERS = \ src/or/addressmap.h \ src/or/buffers.h \ src/or/channel.h \ src/or/channeltls.h \ src/or/circuitbuild.h \ src/or/circuitlist.h \ src/or/circuitmux.h \ src/or/circuitmux_ewma.h \ src/or/circuitstats.h \ src/or/circuituse.h \ src/or/command.h \ src/or/config.h \ src/or/confparse.h \ src/or/connection.h \ src/or/connection_edge.h \ src/or/connection_or.h \ src/or/control.h \ src/or/cpuworker.h \ src/or/directory.h \ src/or/dirserv.h \ src/or/dirvote.h \ src/or/dns.h \ src/or/dnsserv.h \ src/or/eventdns_tor.h \ src/or/fp_pair.h \ src/or/geoip.h \ src/or/entrynodes.h \ src/or/hibernate.h \ src/or/main.h \ src/or/microdesc.h \ src/or/networkstatus.h \ src/or/nodelist.h \ src/or/ntmain.h \ src/or/onion.h \ src/or/onion_fast.h \ src/or/onion_ntor.h \ src/or/onion_tap.h \ src/or/or.h \ src/or/transports.h \ src/or/policies.h \ src/or/reasons.h \ src/or/relay.h \ src/or/rendclient.h \ src/or/rendcommon.h \ src/or/rendmid.h \ src/or/rendservice.h \ src/or/rephist.h \ src/or/replaycache.h \ src/or/router.h \ src/or/routerlist.h \ src/or/routerset.h \ src/or/routerparse.h \ src/or/statefile.h \ src/or/status.h src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" \ -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on Windows, but I assure you that it # matters a lot there, and is quite hard to debug if you forget to do it. src_test_test_SOURCES = \ src/test/test.c \ src/test/test_addr.c \ src/test/test_cell_formats.c \ src/test/test_containers.c \ src/test/test_crypto.c \ src/test/test_data.c \ src/test/test_dir.c \ src/test/test_introduce.c \ src/test/test_microdesc.c \ src/test/test_pt.c \ src/test/test_replay.c \ src/test/test_util.c \ src/test/test_config.c \ src/ext/tinytest.c src_test_test_CPPFLAGS = $(src_test_AM_CPPFLAGS) src_test_bench_SOURCES = \ src/test/bench.c src_test_bench_CPPFLAGS = $(src_test_AM_CPPFLAGS) src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ src_test_test_LDADD = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(LIBDONNA) \ src/common/libor-event.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(LIBDONNA) \ src/common/libor-event.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @CURVE25519_ENABLED_TRUE@src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c @CURVE25519_ENABLED_TRUE@src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @CURVE25519_ENABLED_TRUE@src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \ @CURVE25519_ENABLED_TRUE@ src/common/libor-crypto.a $(LIBDONNA) \ @CURVE25519_ENABLED_TRUE@ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ @CURVE25519_ENABLED_TRUE@ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @CURVE25519_ENABLED_TRUE@src_test_test_ntor_cl_AM_CPPFLAGS = \ @CURVE25519_ENABLED_TRUE@ -I"$(top_srcdir)/src/or" src_tools_tor_resolve_SOURCES = src/tools/tor-resolve.c src_tools_tor_resolve_LDFLAGS = src_tools_tor_resolve_LDADD = src/common/libor.a @TOR_LIB_MATH@ @TOR_LIB_WS32@ src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ src_tools_tor_gencert_LDADD = src/common/libor.a src/common/libor-crypto.a \ $(LIBDONNA) \ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ src_tools_tor_checkkey_SOURCES = src/tools/tor-checkkey.c src_tools_tor_checkkey_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ src_tools_tor_checkkey_LDADD = src/common/libor.a src/common/libor-crypto.a \ $(LIBDONNA) \ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ src_tools_tor_fw_helper_tor_fw_helper_SOURCES = \ src/tools/tor-fw-helper/tor-fw-helper.c \ src/tools/tor-fw-helper/tor-fw-helper-natpmp.c \ src/tools/tor-fw-helper/tor-fw-helper-upnp.c @NAT_PMP_FALSE@nat_pmp_ldflags = @NAT_PMP_TRUE@nat_pmp_ldflags = @TOR_LDFLAGS_libnatpmp@ @NAT_PMP_FALSE@nat_pmp_ldadd = @NAT_PMP_TRUE@nat_pmp_ldadd = -lnatpmp @TOR_LIB_IPHLPAPI@ @NAT_PMP_FALSE@nat_pmp_cppflags = @NAT_PMP_TRUE@nat_pmp_cppflags = @TOR_CPPFLAGS_libnatpmp@ @MINIUPNPC_FALSE@miniupnpc_ldflags = @MINIUPNPC_TRUE@miniupnpc_ldflags = @TOR_LDFLAGS_libminiupnpc@ @MINIUPNPC_FALSE@miniupnpc_ldadd = @MINIUPNPC_TRUE@miniupnpc_ldadd = -lminiupnpc @TOR_LIB_IPHLPAPI@ @MINIUPNPC_FALSE@miniupnpc_cppflags = @MINIUPNPC_TRUE@miniupnpc_cppflags = @TOR_CPPFLAGS_libminiupnpc@ src_tools_tor_fw_helper_tor_fw_helper_LDFLAGS = $(nat_pmp_ldflags) $(miniupnpc_ldflags) src_tools_tor_fw_helper_tor_fw_helper_LDADD = src/common/libor.a $(nat_pmp_ldadd) $(miniupnpc_ldadd) -lm @TOR_LIB_WS32@ src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS = $(nat_pmp_cppflags) $(miniupnpc_cppflags) confdir = $(sysconfdir)/tor tordatadir = $(datadir)/tor # fallback-consensus conf_DATA = src/config/torrc.sample tordata_DATA = src/config/geoip src/config/geoip6 regular_mans = doc/tor doc/tor-gencert doc/tor-resolve doc/torify all_mans = $(regular_mans) doc/tor-fw-helper @USE_ASCIIDOC_FALSE@nodist_man1_MANS = @USE_ASCIIDOC_TRUE@@USE_FW_HELPER_FALSE@nodist_man1_MANS = $(regular_mans:=.1) @USE_ASCIIDOC_TRUE@@USE_FW_HELPER_TRUE@nodist_man1_MANS = $(all_mans:=.1) @USE_ASCIIDOC_FALSE@doc_DATA = @USE_ASCIIDOC_TRUE@@USE_FW_HELPER_FALSE@doc_DATA = $(regular_mans:=.html) @USE_ASCIIDOC_TRUE@@USE_FW_HELPER_TRUE@doc_DATA = $(all_mans:=.html) @USE_ASCIIDOC_FALSE@html_in = @USE_ASCIIDOC_TRUE@html_in = $(all_mans:=.html.in) @USE_ASCIIDOC_FALSE@man_in = @USE_ASCIIDOC_TRUE@man_in = $(all_mans:=.1.in) @USE_ASCIIDOC_FALSE@txt_in = @USE_ASCIIDOC_TRUE@txt_in = $(all_mans:=.1.txt) asciidoc_product = $(nodist_man1_MANS) $(doc_DATA) all: orconfig.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .o .obj am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/src/include.am $(srcdir)/src/ext/include.am $(srcdir)/src/common/include.am $(srcdir)/src/or/include.am $(srcdir)/src/test/include.am $(srcdir)/src/tools/include.am $(srcdir)/src/tools/tor-fw-helper/include.am $(srcdir)/src/win32/include.am $(srcdir)/src/config/include.am $(srcdir)/doc/include.am $(srcdir)/contrib/include.am $(srcdir)/contrib/suse/include.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(srcdir)/src/include.am $(srcdir)/src/ext/include.am $(srcdir)/src/common/include.am $(srcdir)/src/or/include.am $(srcdir)/src/test/include.am $(srcdir)/src/tools/include.am $(srcdir)/src/tools/tor-fw-helper/include.am $(srcdir)/src/win32/include.am $(srcdir)/src/config/include.am $(srcdir)/doc/include.am $(srcdir)/contrib/include.am $(srcdir)/contrib/suse/include.am: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): orconfig.h: stamp-h1 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/orconfig.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status orconfig.h $(srcdir)/orconfig.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f orconfig.h stamp-h1 Doxyfile: $(top_builddir)/config.status $(srcdir)/Doxyfile.in cd $(top_builddir) && $(SHELL) ./config.status $@ contrib/suse/tor.sh: $(top_builddir)/config.status $(top_srcdir)/contrib/suse/tor.sh.in cd $(top_builddir) && $(SHELL) ./config.status $@ contrib/tor.logrotate: $(top_builddir)/config.status $(top_srcdir)/contrib/tor.logrotate.in cd $(top_builddir) && $(SHELL) ./config.status $@ contrib/tor.sh: $(top_builddir)/config.status $(top_srcdir)/contrib/tor.sh.in cd $(top_builddir) && $(SHELL) ./config.status $@ contrib/torctl: $(top_builddir)/config.status $(top_srcdir)/contrib/torctl.in cd $(top_builddir) && $(SHELL) ./config.status $@ contrib/torify: $(top_builddir)/config.status $(top_srcdir)/contrib/torify.in cd $(top_builddir) && $(SHELL) ./config.status $@ src/config/torrc.sample: $(top_builddir)/config.status $(top_srcdir)/src/config/torrc.sample.in cd $(top_builddir) && $(SHELL) ./config.status $@ clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) src/ext/curve25519_donna/$(am__dirstamp): @$(MKDIR_P) src/ext/curve25519_donna @: > src/ext/curve25519_donna/$(am__dirstamp) src/ext/curve25519_donna/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/ext/curve25519_donna/$(DEPDIR) @: > src/ext/curve25519_donna/$(DEPDIR)/$(am__dirstamp) src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.$(OBJEXT): \ src/ext/curve25519_donna/$(am__dirstamp) \ src/ext/curve25519_donna/$(DEPDIR)/$(am__dirstamp) src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.$(OBJEXT): \ src/ext/curve25519_donna/$(am__dirstamp) \ src/ext/curve25519_donna/$(DEPDIR)/$(am__dirstamp) src/common/$(am__dirstamp): @$(MKDIR_P) src/common @: > src/common/$(am__dirstamp) src/common/libcurve25519_donna.a: $(src_common_libcurve25519_donna_a_OBJECTS) $(src_common_libcurve25519_donna_a_DEPENDENCIES) $(EXTRA_src_common_libcurve25519_donna_a_DEPENDENCIES) src/common/$(am__dirstamp) $(AM_V_at)-rm -f src/common/libcurve25519_donna.a $(AM_V_AR)$(src_common_libcurve25519_donna_a_AR) src/common/libcurve25519_donna.a $(src_common_libcurve25519_donna_a_OBJECTS) $(src_common_libcurve25519_donna_a_LIBADD) $(AM_V_at)$(RANLIB) src/common/libcurve25519_donna.a src/common/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/common/$(DEPDIR) @: > src/common/$(DEPDIR)/$(am__dirstamp) src/common/aes.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/crypto.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/crypto_format.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/torgzip.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/tortls.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/crypto_curve25519.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/libor-crypto.a: $(src_common_libor_crypto_a_OBJECTS) $(src_common_libor_crypto_a_DEPENDENCIES) $(EXTRA_src_common_libor_crypto_a_DEPENDENCIES) src/common/$(am__dirstamp) $(AM_V_at)-rm -f src/common/libor-crypto.a $(AM_V_AR)$(src_common_libor_crypto_a_AR) src/common/libor-crypto.a $(src_common_libor_crypto_a_OBJECTS) $(src_common_libor_crypto_a_LIBADD) $(AM_V_at)$(RANLIB) src/common/libor-crypto.a src/common/compat_libevent.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/libor-event.a: $(src_common_libor_event_a_OBJECTS) $(src_common_libor_event_a_DEPENDENCIES) $(EXTRA_src_common_libor_event_a_DEPENDENCIES) src/common/$(am__dirstamp) $(AM_V_at)-rm -f src/common/libor-event.a $(AM_V_AR)$(src_common_libor_event_a_AR) src/common/libor-event.a $(src_common_libor_event_a_OBJECTS) $(src_common_libor_event_a_LIBADD) $(AM_V_at)$(RANLIB) src/common/libor-event.a src/common/address.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/compat.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/container.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/di_ops.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/log.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/memarea.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/mempool.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/procmon.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/util.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/util_codedigest.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/ext/$(am__dirstamp): @$(MKDIR_P) src/ext @: > src/ext/$(am__dirstamp) src/ext/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/ext/$(DEPDIR) @: > src/ext/$(DEPDIR)/$(am__dirstamp) src/ext/OpenBSD_malloc_Linux.$(OBJEXT): src/ext/$(am__dirstamp) \ src/ext/$(DEPDIR)/$(am__dirstamp) src/common/libor.a: $(src_common_libor_a_OBJECTS) $(src_common_libor_a_DEPENDENCIES) $(EXTRA_src_common_libor_a_DEPENDENCIES) src/common/$(am__dirstamp) $(AM_V_at)-rm -f src/common/libor.a $(AM_V_AR)$(src_common_libor_a_AR) src/common/libor.a $(src_common_libor_a_OBJECTS) $(src_common_libor_a_LIBADD) $(AM_V_at)$(RANLIB) src/common/libor.a src/or/$(am__dirstamp): @$(MKDIR_P) src/or @: > src/or/$(am__dirstamp) src/or/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/or/$(DEPDIR) @: > src/or/$(DEPDIR)/$(am__dirstamp) src/or/addressmap.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/buffers.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/channel.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/channeltls.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/circuitbuild.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/circuitlist.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/circuitmux.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/circuitmux_ewma.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/circuitstats.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/circuituse.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/command.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/config.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/confparse.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/connection.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/connection_edge.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/connection_or.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/control.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/cpuworker.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/directory.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/dirserv.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/dirvote.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/dns.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/dnsserv.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/fp_pair.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/geoip.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/entrynodes.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/hibernate.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/main.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/microdesc.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/networkstatus.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/nodelist.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/onion.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/onion_fast.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/onion_tap.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/transports.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/policies.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/reasons.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/relay.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/rendclient.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/rendcommon.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/rendmid.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/rendservice.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/rephist.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/replaycache.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/router.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/routerlist.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/routerparse.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/routerset.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/statefile.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/status.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/ext/eventdns.$(OBJEXT): src/ext/$(am__dirstamp) \ src/ext/$(DEPDIR)/$(am__dirstamp) src/or/ntmain.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/onion_ntor.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/config_codedigest.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/libtor.a: $(src_or_libtor_a_OBJECTS) $(src_or_libtor_a_DEPENDENCIES) $(EXTRA_src_or_libtor_a_DEPENDENCIES) src/or/$(am__dirstamp) $(AM_V_at)-rm -f src/or/libtor.a $(AM_V_AR)$(src_or_libtor_a_AR) src/or/libtor.a $(src_or_libtor_a_OBJECTS) $(src_or_libtor_a_LIBADD) $(AM_V_at)$(RANLIB) src/or/libtor.a install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) clean-noinstPROGRAMS: -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) src/or/tor_main.$(OBJEXT): src/or/$(am__dirstamp) \ src/or/$(DEPDIR)/$(am__dirstamp) src/or/tor$(EXEEXT): $(src_or_tor_OBJECTS) $(src_or_tor_DEPENDENCIES) $(EXTRA_src_or_tor_DEPENDENCIES) src/or/$(am__dirstamp) @rm -f src/or/tor$(EXEEXT) $(AM_V_CCLD)$(src_or_tor_LINK) $(src_or_tor_OBJECTS) $(src_or_tor_LDADD) $(LIBS) src/test/$(am__dirstamp): @$(MKDIR_P) src/test @: > src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/test/$(DEPDIR) @: > src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_bench-bench.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/bench$(EXEEXT): $(src_test_bench_OBJECTS) $(src_test_bench_DEPENDENCIES) $(EXTRA_src_test_bench_DEPENDENCIES) src/test/$(am__dirstamp) @rm -f src/test/bench$(EXEEXT) $(AM_V_CCLD)$(src_test_bench_LINK) $(src_test_bench_OBJECTS) $(src_test_bench_LDADD) $(LIBS) src/test/src_test_test-test.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_addr.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_cell_formats.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_containers.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_crypto.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_data.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_dir.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_introduce.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_microdesc.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_pt.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_replay.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_util.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/src_test_test-test_config.$(OBJEXT): \ src/test/$(am__dirstamp) src/test/$(DEPDIR)/$(am__dirstamp) src/ext/src_test_test-tinytest.$(OBJEXT): src/ext/$(am__dirstamp) \ src/ext/$(DEPDIR)/$(am__dirstamp) src/test/test$(EXEEXT): $(src_test_test_OBJECTS) $(src_test_test_DEPENDENCIES) $(EXTRA_src_test_test_DEPENDENCIES) src/test/$(am__dirstamp) @rm -f src/test/test$(EXEEXT) $(AM_V_CCLD)$(src_test_test_LINK) $(src_test_test_OBJECTS) $(src_test_test_LDADD) $(LIBS) src/test/test-child.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-child$(EXEEXT): $(src_test_test_child_OBJECTS) $(src_test_test_child_DEPENDENCIES) $(EXTRA_src_test_test_child_DEPENDENCIES) src/test/$(am__dirstamp) @rm -f src/test/test-child$(EXEEXT) $(AM_V_CCLD)$(LINK) $(src_test_test_child_OBJECTS) $(src_test_test_child_LDADD) $(LIBS) src/test/test_ntor_cl.$(OBJEXT): src/test/$(am__dirstamp) \ src/test/$(DEPDIR)/$(am__dirstamp) src/test/test-ntor-cl$(EXEEXT): $(src_test_test_ntor_cl_OBJECTS) $(src_test_test_ntor_cl_DEPENDENCIES) $(EXTRA_src_test_test_ntor_cl_DEPENDENCIES) src/test/$(am__dirstamp) @rm -f src/test/test-ntor-cl$(EXEEXT) $(AM_V_CCLD)$(src_test_test_ntor_cl_LINK) $(src_test_test_ntor_cl_OBJECTS) $(src_test_test_ntor_cl_LDADD) $(LIBS) src/tools/$(am__dirstamp): @$(MKDIR_P) src/tools @: > src/tools/$(am__dirstamp) src/tools/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/tools/$(DEPDIR) @: > src/tools/$(DEPDIR)/$(am__dirstamp) src/tools/tor-checkkey.$(OBJEXT): src/tools/$(am__dirstamp) \ src/tools/$(DEPDIR)/$(am__dirstamp) src/tools/tor-checkkey$(EXEEXT): $(src_tools_tor_checkkey_OBJECTS) $(src_tools_tor_checkkey_DEPENDENCIES) $(EXTRA_src_tools_tor_checkkey_DEPENDENCIES) src/tools/$(am__dirstamp) @rm -f src/tools/tor-checkkey$(EXEEXT) $(AM_V_CCLD)$(src_tools_tor_checkkey_LINK) $(src_tools_tor_checkkey_OBJECTS) $(src_tools_tor_checkkey_LDADD) $(LIBS) src/tools/tor-fw-helper/$(am__dirstamp): @$(MKDIR_P) src/tools/tor-fw-helper @: > src/tools/tor-fw-helper/$(am__dirstamp) src/tools/tor-fw-helper/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/tools/tor-fw-helper/$(DEPDIR) @: > src/tools/tor-fw-helper/$(DEPDIR)/$(am__dirstamp) src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.$(OBJEXT): \ src/tools/tor-fw-helper/$(am__dirstamp) \ src/tools/tor-fw-helper/$(DEPDIR)/$(am__dirstamp) src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.$(OBJEXT): \ src/tools/tor-fw-helper/$(am__dirstamp) \ src/tools/tor-fw-helper/$(DEPDIR)/$(am__dirstamp) src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.$(OBJEXT): \ src/tools/tor-fw-helper/$(am__dirstamp) \ src/tools/tor-fw-helper/$(DEPDIR)/$(am__dirstamp) src/tools/tor-fw-helper/tor-fw-helper$(EXEEXT): $(src_tools_tor_fw_helper_tor_fw_helper_OBJECTS) $(src_tools_tor_fw_helper_tor_fw_helper_DEPENDENCIES) $(EXTRA_src_tools_tor_fw_helper_tor_fw_helper_DEPENDENCIES) src/tools/tor-fw-helper/$(am__dirstamp) @rm -f src/tools/tor-fw-helper/tor-fw-helper$(EXEEXT) $(AM_V_CCLD)$(src_tools_tor_fw_helper_tor_fw_helper_LINK) $(src_tools_tor_fw_helper_tor_fw_helper_OBJECTS) $(src_tools_tor_fw_helper_tor_fw_helper_LDADD) $(LIBS) src/tools/tor-gencert.$(OBJEXT): src/tools/$(am__dirstamp) \ src/tools/$(DEPDIR)/$(am__dirstamp) src/tools/tor-gencert$(EXEEXT): $(src_tools_tor_gencert_OBJECTS) $(src_tools_tor_gencert_DEPENDENCIES) $(EXTRA_src_tools_tor_gencert_DEPENDENCIES) src/tools/$(am__dirstamp) @rm -f src/tools/tor-gencert$(EXEEXT) $(AM_V_CCLD)$(src_tools_tor_gencert_LINK) $(src_tools_tor_gencert_OBJECTS) $(src_tools_tor_gencert_LDADD) $(LIBS) src/tools/tor-resolve.$(OBJEXT): src/tools/$(am__dirstamp) \ src/tools/$(DEPDIR)/$(am__dirstamp) src/tools/tor-resolve$(EXEEXT): $(src_tools_tor_resolve_OBJECTS) $(src_tools_tor_resolve_DEPENDENCIES) $(EXTRA_src_tools_tor_resolve_DEPENDENCIES) src/tools/$(am__dirstamp) @rm -f src/tools/tor-resolve$(EXEEXT) $(AM_V_CCLD)$(src_tools_tor_resolve_LINK) $(src_tools_tor_resolve_OBJECTS) $(src_tools_tor_resolve_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f src/common/address.$(OBJEXT) -rm -f src/common/aes.$(OBJEXT) -rm -f src/common/compat.$(OBJEXT) -rm -f src/common/compat_libevent.$(OBJEXT) -rm -f src/common/container.$(OBJEXT) -rm -f src/common/crypto.$(OBJEXT) -rm -f src/common/crypto_curve25519.$(OBJEXT) -rm -f src/common/crypto_format.$(OBJEXT) -rm -f src/common/di_ops.$(OBJEXT) -rm -f src/common/log.$(OBJEXT) -rm -f src/common/memarea.$(OBJEXT) -rm -f src/common/mempool.$(OBJEXT) -rm -f src/common/procmon.$(OBJEXT) -rm -f src/common/torgzip.$(OBJEXT) -rm -f src/common/tortls.$(OBJEXT) -rm -f src/common/util.$(OBJEXT) -rm -f src/common/util_codedigest.$(OBJEXT) -rm -f src/ext/OpenBSD_malloc_Linux.$(OBJEXT) -rm -f src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.$(OBJEXT) -rm -f src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.$(OBJEXT) -rm -f src/ext/eventdns.$(OBJEXT) -rm -f src/ext/src_test_test-tinytest.$(OBJEXT) -rm -f src/or/addressmap.$(OBJEXT) -rm -f src/or/buffers.$(OBJEXT) -rm -f src/or/channel.$(OBJEXT) -rm -f src/or/channeltls.$(OBJEXT) -rm -f src/or/circuitbuild.$(OBJEXT) -rm -f src/or/circuitlist.$(OBJEXT) -rm -f src/or/circuitmux.$(OBJEXT) -rm -f src/or/circuitmux_ewma.$(OBJEXT) -rm -f src/or/circuitstats.$(OBJEXT) -rm -f src/or/circuituse.$(OBJEXT) -rm -f src/or/command.$(OBJEXT) -rm -f src/or/config.$(OBJEXT) -rm -f src/or/config_codedigest.$(OBJEXT) -rm -f src/or/confparse.$(OBJEXT) -rm -f src/or/connection.$(OBJEXT) -rm -f src/or/connection_edge.$(OBJEXT) -rm -f src/or/connection_or.$(OBJEXT) -rm -f src/or/control.$(OBJEXT) -rm -f src/or/cpuworker.$(OBJEXT) -rm -f src/or/directory.$(OBJEXT) -rm -f src/or/dirserv.$(OBJEXT) -rm -f src/or/dirvote.$(OBJEXT) -rm -f src/or/dns.$(OBJEXT) -rm -f src/or/dnsserv.$(OBJEXT) -rm -f src/or/entrynodes.$(OBJEXT) -rm -f src/or/fp_pair.$(OBJEXT) -rm -f src/or/geoip.$(OBJEXT) -rm -f src/or/hibernate.$(OBJEXT) -rm -f src/or/main.$(OBJEXT) -rm -f src/or/microdesc.$(OBJEXT) -rm -f src/or/networkstatus.$(OBJEXT) -rm -f src/or/nodelist.$(OBJEXT) -rm -f src/or/ntmain.$(OBJEXT) -rm -f src/or/onion.$(OBJEXT) -rm -f src/or/onion_fast.$(OBJEXT) -rm -f src/or/onion_ntor.$(OBJEXT) -rm -f src/or/onion_tap.$(OBJEXT) -rm -f src/or/policies.$(OBJEXT) -rm -f src/or/reasons.$(OBJEXT) -rm -f src/or/relay.$(OBJEXT) -rm -f src/or/rendclient.$(OBJEXT) -rm -f src/or/rendcommon.$(OBJEXT) -rm -f src/or/rendmid.$(OBJEXT) -rm -f src/or/rendservice.$(OBJEXT) -rm -f src/or/rephist.$(OBJEXT) -rm -f src/or/replaycache.$(OBJEXT) -rm -f src/or/router.$(OBJEXT) -rm -f src/or/routerlist.$(OBJEXT) -rm -f src/or/routerparse.$(OBJEXT) -rm -f src/or/routerset.$(OBJEXT) -rm -f src/or/statefile.$(OBJEXT) -rm -f src/or/status.$(OBJEXT) -rm -f src/or/tor_main.$(OBJEXT) -rm -f src/or/transports.$(OBJEXT) -rm -f src/test/src_test_bench-bench.$(OBJEXT) -rm -f src/test/src_test_test-test.$(OBJEXT) -rm -f src/test/src_test_test-test_addr.$(OBJEXT) -rm -f src/test/src_test_test-test_cell_formats.$(OBJEXT) -rm -f src/test/src_test_test-test_config.$(OBJEXT) -rm -f src/test/src_test_test-test_containers.$(OBJEXT) -rm -f src/test/src_test_test-test_crypto.$(OBJEXT) -rm -f src/test/src_test_test-test_data.$(OBJEXT) -rm -f src/test/src_test_test-test_dir.$(OBJEXT) -rm -f src/test/src_test_test-test_introduce.$(OBJEXT) -rm -f src/test/src_test_test-test_microdesc.$(OBJEXT) -rm -f src/test/src_test_test-test_pt.$(OBJEXT) -rm -f src/test/src_test_test-test_replay.$(OBJEXT) -rm -f src/test/src_test_test-test_util.$(OBJEXT) -rm -f src/test/test-child.$(OBJEXT) -rm -f src/test/test_ntor_cl.$(OBJEXT) -rm -f src/tools/tor-checkkey.$(OBJEXT) -rm -f src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.$(OBJEXT) -rm -f src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.$(OBJEXT) -rm -f src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.$(OBJEXT) -rm -f src/tools/tor-gencert.$(OBJEXT) -rm -f src/tools/tor-resolve.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/address.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/aes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/compat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/compat_libevent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/container.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/crypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/crypto_curve25519.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/crypto_format.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/di_ops.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/memarea.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/mempool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/procmon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/torgzip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/tortls.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/util_codedigest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/ext/$(DEPDIR)/OpenBSD_malloc_Linux.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/ext/$(DEPDIR)/eventdns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/ext/$(DEPDIR)/src_test_test-tinytest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna-c64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/addressmap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/buffers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/channel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/channeltls.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/circuitbuild.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/circuitlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/circuitmux.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/circuitmux_ewma.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/circuitstats.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/circuituse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/command.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/config_codedigest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/confparse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/connection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/connection_edge.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/connection_or.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/control.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/cpuworker.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/directory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/dirserv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/dirvote.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/dns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/dnsserv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/entrynodes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/fp_pair.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/geoip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/hibernate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/microdesc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/networkstatus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/nodelist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/ntmain.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/onion.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/onion_fast.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/onion_ntor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/onion_tap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/policies.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/reasons.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/relay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/rendclient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/rendcommon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/rendmid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/rendservice.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/rephist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/replaycache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/router.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/routerlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/routerparse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/routerset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/statefile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/status.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/tor_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/or/$(DEPDIR)/transports.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_bench-bench.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_addr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_cell_formats.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_containers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_crypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_dir.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_introduce.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_microdesc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_pt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_replay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/src_test_test-test_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test-child.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/test/$(DEPDIR)/test_ntor_cl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/tools/$(DEPDIR)/tor-checkkey.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/tools/$(DEPDIR)/tor-gencert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/tools/$(DEPDIR)/tor-resolve.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.o: src/ext/curve25519_donna/curve25519-donna-c64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_common_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -MT src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.o -MD -MP -MF src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna-c64.Tpo -c -o src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.o `test -f 'src/ext/curve25519_donna/curve25519-donna-c64.c' || echo '$(srcdir)/'`src/ext/curve25519_donna/curve25519-donna-c64.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna-c64.Tpo src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna-c64.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/curve25519_donna/curve25519-donna-c64.c' object='src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_common_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -c -o src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.o `test -f 'src/ext/curve25519_donna/curve25519-donna-c64.c' || echo '$(srcdir)/'`src/ext/curve25519_donna/curve25519-donna-c64.c src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.obj: src/ext/curve25519_donna/curve25519-donna-c64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_common_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -MT src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.obj -MD -MP -MF src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna-c64.Tpo -c -o src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.obj `if test -f 'src/ext/curve25519_donna/curve25519-donna-c64.c'; then $(CYGPATH_W) 'src/ext/curve25519_donna/curve25519-donna-c64.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/curve25519_donna/curve25519-donna-c64.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna-c64.Tpo src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna-c64.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/curve25519_donna/curve25519-donna-c64.c' object='src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_common_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -c -o src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna-c64.obj `if test -f 'src/ext/curve25519_donna/curve25519-donna-c64.c'; then $(CYGPATH_W) 'src/ext/curve25519_donna/curve25519-donna-c64.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/curve25519_donna/curve25519-donna-c64.c'; fi` src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.o: src/ext/curve25519_donna/curve25519-donna.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_common_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -MT src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.o -MD -MP -MF src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna.Tpo -c -o src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.o `test -f 'src/ext/curve25519_donna/curve25519-donna.c' || echo '$(srcdir)/'`src/ext/curve25519_donna/curve25519-donna.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna.Tpo src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/curve25519_donna/curve25519-donna.c' object='src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_common_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -c -o src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.o `test -f 'src/ext/curve25519_donna/curve25519-donna.c' || echo '$(srcdir)/'`src/ext/curve25519_donna/curve25519-donna.c src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.obj: src/ext/curve25519_donna/curve25519-donna.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_common_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -MT src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.obj -MD -MP -MF src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna.Tpo -c -o src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.obj `if test -f 'src/ext/curve25519_donna/curve25519-donna.c'; then $(CYGPATH_W) 'src/ext/curve25519_donna/curve25519-donna.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/curve25519_donna/curve25519-donna.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna.Tpo src/ext/curve25519_donna/$(DEPDIR)/src_common_libcurve25519_donna_a-curve25519-donna.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/curve25519_donna/curve25519-donna.c' object='src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_common_libcurve25519_donna_a_CFLAGS) $(CFLAGS) -c -o src/ext/curve25519_donna/src_common_libcurve25519_donna_a-curve25519-donna.obj `if test -f 'src/ext/curve25519_donna/curve25519-donna.c'; then $(CYGPATH_W) 'src/ext/curve25519_donna/curve25519-donna.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/curve25519_donna/curve25519-donna.c'; fi` src/test/src_test_bench-bench.o: src/test/bench.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_bench_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_bench-bench.o -MD -MP -MF src/test/$(DEPDIR)/src_test_bench-bench.Tpo -c -o src/test/src_test_bench-bench.o `test -f 'src/test/bench.c' || echo '$(srcdir)/'`src/test/bench.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_bench-bench.Tpo src/test/$(DEPDIR)/src_test_bench-bench.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/bench.c' object='src/test/src_test_bench-bench.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_bench_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_bench-bench.o `test -f 'src/test/bench.c' || echo '$(srcdir)/'`src/test/bench.c src/test/src_test_bench-bench.obj: src/test/bench.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_bench_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_bench-bench.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_bench-bench.Tpo -c -o src/test/src_test_bench-bench.obj `if test -f 'src/test/bench.c'; then $(CYGPATH_W) 'src/test/bench.c'; else $(CYGPATH_W) '$(srcdir)/src/test/bench.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_bench-bench.Tpo src/test/$(DEPDIR)/src_test_bench-bench.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/bench.c' object='src/test/src_test_bench-bench.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_bench_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_bench-bench.obj `if test -f 'src/test/bench.c'; then $(CYGPATH_W) 'src/test/bench.c'; else $(CYGPATH_W) '$(srcdir)/src/test/bench.c'; fi` src/test/src_test_test-test.o: src/test/test.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test.Tpo -c -o src/test/src_test_test-test.o `test -f 'src/test/test.c' || echo '$(srcdir)/'`src/test/test.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test.Tpo src/test/$(DEPDIR)/src_test_test-test.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test.c' object='src/test/src_test_test-test.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test.o `test -f 'src/test/test.c' || echo '$(srcdir)/'`src/test/test.c src/test/src_test_test-test.obj: src/test/test.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test.Tpo -c -o src/test/src_test_test-test.obj `if test -f 'src/test/test.c'; then $(CYGPATH_W) 'src/test/test.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test.Tpo src/test/$(DEPDIR)/src_test_test-test.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test.c' object='src/test/src_test_test-test.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test.obj `if test -f 'src/test/test.c'; then $(CYGPATH_W) 'src/test/test.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test.c'; fi` src/test/src_test_test-test_addr.o: src/test/test_addr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_addr.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_addr.Tpo -c -o src/test/src_test_test-test_addr.o `test -f 'src/test/test_addr.c' || echo '$(srcdir)/'`src/test/test_addr.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_addr.Tpo src/test/$(DEPDIR)/src_test_test-test_addr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_addr.c' object='src/test/src_test_test-test_addr.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_addr.o `test -f 'src/test/test_addr.c' || echo '$(srcdir)/'`src/test/test_addr.c src/test/src_test_test-test_addr.obj: src/test/test_addr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_addr.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_addr.Tpo -c -o src/test/src_test_test-test_addr.obj `if test -f 'src/test/test_addr.c'; then $(CYGPATH_W) 'src/test/test_addr.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_addr.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_addr.Tpo src/test/$(DEPDIR)/src_test_test-test_addr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_addr.c' object='src/test/src_test_test-test_addr.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_addr.obj `if test -f 'src/test/test_addr.c'; then $(CYGPATH_W) 'src/test/test_addr.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_addr.c'; fi` src/test/src_test_test-test_cell_formats.o: src/test/test_cell_formats.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_cell_formats.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_cell_formats.Tpo -c -o src/test/src_test_test-test_cell_formats.o `test -f 'src/test/test_cell_formats.c' || echo '$(srcdir)/'`src/test/test_cell_formats.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_cell_formats.Tpo src/test/$(DEPDIR)/src_test_test-test_cell_formats.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_cell_formats.c' object='src/test/src_test_test-test_cell_formats.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_cell_formats.o `test -f 'src/test/test_cell_formats.c' || echo '$(srcdir)/'`src/test/test_cell_formats.c src/test/src_test_test-test_cell_formats.obj: src/test/test_cell_formats.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_cell_formats.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_cell_formats.Tpo -c -o src/test/src_test_test-test_cell_formats.obj `if test -f 'src/test/test_cell_formats.c'; then $(CYGPATH_W) 'src/test/test_cell_formats.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_cell_formats.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_cell_formats.Tpo src/test/$(DEPDIR)/src_test_test-test_cell_formats.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_cell_formats.c' object='src/test/src_test_test-test_cell_formats.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_cell_formats.obj `if test -f 'src/test/test_cell_formats.c'; then $(CYGPATH_W) 'src/test/test_cell_formats.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_cell_formats.c'; fi` src/test/src_test_test-test_containers.o: src/test/test_containers.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_containers.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_containers.Tpo -c -o src/test/src_test_test-test_containers.o `test -f 'src/test/test_containers.c' || echo '$(srcdir)/'`src/test/test_containers.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_containers.Tpo src/test/$(DEPDIR)/src_test_test-test_containers.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_containers.c' object='src/test/src_test_test-test_containers.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_containers.o `test -f 'src/test/test_containers.c' || echo '$(srcdir)/'`src/test/test_containers.c src/test/src_test_test-test_containers.obj: src/test/test_containers.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_containers.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_containers.Tpo -c -o src/test/src_test_test-test_containers.obj `if test -f 'src/test/test_containers.c'; then $(CYGPATH_W) 'src/test/test_containers.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_containers.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_containers.Tpo src/test/$(DEPDIR)/src_test_test-test_containers.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_containers.c' object='src/test/src_test_test-test_containers.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_containers.obj `if test -f 'src/test/test_containers.c'; then $(CYGPATH_W) 'src/test/test_containers.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_containers.c'; fi` src/test/src_test_test-test_crypto.o: src/test/test_crypto.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_crypto.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_crypto.Tpo -c -o src/test/src_test_test-test_crypto.o `test -f 'src/test/test_crypto.c' || echo '$(srcdir)/'`src/test/test_crypto.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_crypto.Tpo src/test/$(DEPDIR)/src_test_test-test_crypto.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_crypto.c' object='src/test/src_test_test-test_crypto.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_crypto.o `test -f 'src/test/test_crypto.c' || echo '$(srcdir)/'`src/test/test_crypto.c src/test/src_test_test-test_crypto.obj: src/test/test_crypto.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_crypto.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_crypto.Tpo -c -o src/test/src_test_test-test_crypto.obj `if test -f 'src/test/test_crypto.c'; then $(CYGPATH_W) 'src/test/test_crypto.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_crypto.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_crypto.Tpo src/test/$(DEPDIR)/src_test_test-test_crypto.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_crypto.c' object='src/test/src_test_test-test_crypto.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_crypto.obj `if test -f 'src/test/test_crypto.c'; then $(CYGPATH_W) 'src/test/test_crypto.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_crypto.c'; fi` src/test/src_test_test-test_data.o: src/test/test_data.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_data.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_data.Tpo -c -o src/test/src_test_test-test_data.o `test -f 'src/test/test_data.c' || echo '$(srcdir)/'`src/test/test_data.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_data.Tpo src/test/$(DEPDIR)/src_test_test-test_data.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_data.c' object='src/test/src_test_test-test_data.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_data.o `test -f 'src/test/test_data.c' || echo '$(srcdir)/'`src/test/test_data.c src/test/src_test_test-test_data.obj: src/test/test_data.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_data.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_data.Tpo -c -o src/test/src_test_test-test_data.obj `if test -f 'src/test/test_data.c'; then $(CYGPATH_W) 'src/test/test_data.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_data.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_data.Tpo src/test/$(DEPDIR)/src_test_test-test_data.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_data.c' object='src/test/src_test_test-test_data.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_data.obj `if test -f 'src/test/test_data.c'; then $(CYGPATH_W) 'src/test/test_data.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_data.c'; fi` src/test/src_test_test-test_dir.o: src/test/test_dir.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_dir.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_dir.Tpo -c -o src/test/src_test_test-test_dir.o `test -f 'src/test/test_dir.c' || echo '$(srcdir)/'`src/test/test_dir.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_dir.Tpo src/test/$(DEPDIR)/src_test_test-test_dir.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_dir.c' object='src/test/src_test_test-test_dir.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_dir.o `test -f 'src/test/test_dir.c' || echo '$(srcdir)/'`src/test/test_dir.c src/test/src_test_test-test_dir.obj: src/test/test_dir.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_dir.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_dir.Tpo -c -o src/test/src_test_test-test_dir.obj `if test -f 'src/test/test_dir.c'; then $(CYGPATH_W) 'src/test/test_dir.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_dir.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_dir.Tpo src/test/$(DEPDIR)/src_test_test-test_dir.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_dir.c' object='src/test/src_test_test-test_dir.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_dir.obj `if test -f 'src/test/test_dir.c'; then $(CYGPATH_W) 'src/test/test_dir.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_dir.c'; fi` src/test/src_test_test-test_introduce.o: src/test/test_introduce.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_introduce.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_introduce.Tpo -c -o src/test/src_test_test-test_introduce.o `test -f 'src/test/test_introduce.c' || echo '$(srcdir)/'`src/test/test_introduce.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_introduce.Tpo src/test/$(DEPDIR)/src_test_test-test_introduce.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_introduce.c' object='src/test/src_test_test-test_introduce.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_introduce.o `test -f 'src/test/test_introduce.c' || echo '$(srcdir)/'`src/test/test_introduce.c src/test/src_test_test-test_introduce.obj: src/test/test_introduce.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_introduce.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_introduce.Tpo -c -o src/test/src_test_test-test_introduce.obj `if test -f 'src/test/test_introduce.c'; then $(CYGPATH_W) 'src/test/test_introduce.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_introduce.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_introduce.Tpo src/test/$(DEPDIR)/src_test_test-test_introduce.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_introduce.c' object='src/test/src_test_test-test_introduce.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_introduce.obj `if test -f 'src/test/test_introduce.c'; then $(CYGPATH_W) 'src/test/test_introduce.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_introduce.c'; fi` src/test/src_test_test-test_microdesc.o: src/test/test_microdesc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_microdesc.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_microdesc.Tpo -c -o src/test/src_test_test-test_microdesc.o `test -f 'src/test/test_microdesc.c' || echo '$(srcdir)/'`src/test/test_microdesc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_microdesc.Tpo src/test/$(DEPDIR)/src_test_test-test_microdesc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_microdesc.c' object='src/test/src_test_test-test_microdesc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_microdesc.o `test -f 'src/test/test_microdesc.c' || echo '$(srcdir)/'`src/test/test_microdesc.c src/test/src_test_test-test_microdesc.obj: src/test/test_microdesc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_microdesc.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_microdesc.Tpo -c -o src/test/src_test_test-test_microdesc.obj `if test -f 'src/test/test_microdesc.c'; then $(CYGPATH_W) 'src/test/test_microdesc.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_microdesc.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_microdesc.Tpo src/test/$(DEPDIR)/src_test_test-test_microdesc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_microdesc.c' object='src/test/src_test_test-test_microdesc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_microdesc.obj `if test -f 'src/test/test_microdesc.c'; then $(CYGPATH_W) 'src/test/test_microdesc.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_microdesc.c'; fi` src/test/src_test_test-test_pt.o: src/test/test_pt.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_pt.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_pt.Tpo -c -o src/test/src_test_test-test_pt.o `test -f 'src/test/test_pt.c' || echo '$(srcdir)/'`src/test/test_pt.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_pt.Tpo src/test/$(DEPDIR)/src_test_test-test_pt.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_pt.c' object='src/test/src_test_test-test_pt.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_pt.o `test -f 'src/test/test_pt.c' || echo '$(srcdir)/'`src/test/test_pt.c src/test/src_test_test-test_pt.obj: src/test/test_pt.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_pt.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_pt.Tpo -c -o src/test/src_test_test-test_pt.obj `if test -f 'src/test/test_pt.c'; then $(CYGPATH_W) 'src/test/test_pt.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_pt.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_pt.Tpo src/test/$(DEPDIR)/src_test_test-test_pt.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_pt.c' object='src/test/src_test_test-test_pt.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_pt.obj `if test -f 'src/test/test_pt.c'; then $(CYGPATH_W) 'src/test/test_pt.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_pt.c'; fi` src/test/src_test_test-test_replay.o: src/test/test_replay.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_replay.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_replay.Tpo -c -o src/test/src_test_test-test_replay.o `test -f 'src/test/test_replay.c' || echo '$(srcdir)/'`src/test/test_replay.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_replay.Tpo src/test/$(DEPDIR)/src_test_test-test_replay.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_replay.c' object='src/test/src_test_test-test_replay.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_replay.o `test -f 'src/test/test_replay.c' || echo '$(srcdir)/'`src/test/test_replay.c src/test/src_test_test-test_replay.obj: src/test/test_replay.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_replay.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_replay.Tpo -c -o src/test/src_test_test-test_replay.obj `if test -f 'src/test/test_replay.c'; then $(CYGPATH_W) 'src/test/test_replay.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_replay.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_replay.Tpo src/test/$(DEPDIR)/src_test_test-test_replay.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_replay.c' object='src/test/src_test_test-test_replay.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_replay.obj `if test -f 'src/test/test_replay.c'; then $(CYGPATH_W) 'src/test/test_replay.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_replay.c'; fi` src/test/src_test_test-test_util.o: src/test/test_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_util.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_util.Tpo -c -o src/test/src_test_test-test_util.o `test -f 'src/test/test_util.c' || echo '$(srcdir)/'`src/test/test_util.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_util.Tpo src/test/$(DEPDIR)/src_test_test-test_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_util.c' object='src/test/src_test_test-test_util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_util.o `test -f 'src/test/test_util.c' || echo '$(srcdir)/'`src/test/test_util.c src/test/src_test_test-test_util.obj: src/test/test_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_util.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_util.Tpo -c -o src/test/src_test_test-test_util.obj `if test -f 'src/test/test_util.c'; then $(CYGPATH_W) 'src/test/test_util.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_util.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_util.Tpo src/test/$(DEPDIR)/src_test_test-test_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_util.c' object='src/test/src_test_test-test_util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_util.obj `if test -f 'src/test/test_util.c'; then $(CYGPATH_W) 'src/test/test_util.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_util.c'; fi` src/test/src_test_test-test_config.o: src/test/test_config.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_config.o -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_config.Tpo -c -o src/test/src_test_test-test_config.o `test -f 'src/test/test_config.c' || echo '$(srcdir)/'`src/test/test_config.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_config.Tpo src/test/$(DEPDIR)/src_test_test-test_config.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_config.c' object='src/test/src_test_test-test_config.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_config.o `test -f 'src/test/test_config.c' || echo '$(srcdir)/'`src/test/test_config.c src/test/src_test_test-test_config.obj: src/test/test_config.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/test/src_test_test-test_config.obj -MD -MP -MF src/test/$(DEPDIR)/src_test_test-test_config.Tpo -c -o src/test/src_test_test-test_config.obj `if test -f 'src/test/test_config.c'; then $(CYGPATH_W) 'src/test/test_config.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_config.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/test/$(DEPDIR)/src_test_test-test_config.Tpo src/test/$(DEPDIR)/src_test_test-test_config.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/test/test_config.c' object='src/test/src_test_test-test_config.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/test/src_test_test-test_config.obj `if test -f 'src/test/test_config.c'; then $(CYGPATH_W) 'src/test/test_config.c'; else $(CYGPATH_W) '$(srcdir)/src/test/test_config.c'; fi` src/ext/src_test_test-tinytest.o: src/ext/tinytest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/src_test_test-tinytest.o -MD -MP -MF src/ext/$(DEPDIR)/src_test_test-tinytest.Tpo -c -o src/ext/src_test_test-tinytest.o `test -f 'src/ext/tinytest.c' || echo '$(srcdir)/'`src/ext/tinytest.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/$(DEPDIR)/src_test_test-tinytest.Tpo src/ext/$(DEPDIR)/src_test_test-tinytest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/tinytest.c' object='src/ext/src_test_test-tinytest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/src_test_test-tinytest.o `test -f 'src/ext/tinytest.c' || echo '$(srcdir)/'`src/ext/tinytest.c src/ext/src_test_test-tinytest.obj: src/ext/tinytest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/ext/src_test_test-tinytest.obj -MD -MP -MF src/ext/$(DEPDIR)/src_test_test-tinytest.Tpo -c -o src/ext/src_test_test-tinytest.obj `if test -f 'src/ext/tinytest.c'; then $(CYGPATH_W) 'src/ext/tinytest.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/tinytest.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ext/$(DEPDIR)/src_test_test-tinytest.Tpo src/ext/$(DEPDIR)/src_test_test-tinytest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ext/tinytest.c' object='src/ext/src_test_test-tinytest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_test_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/ext/src_test_test-tinytest.obj `if test -f 'src/ext/tinytest.c'; then $(CYGPATH_W) 'src/ext/tinytest.c'; else $(CYGPATH_W) '$(srcdir)/src/ext/tinytest.c'; fi` src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.o: src/tools/tor-fw-helper/tor-fw-helper.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.o -MD -MP -MF src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.Tpo -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.o `test -f 'src/tools/tor-fw-helper/tor-fw-helper.c' || echo '$(srcdir)/'`src/tools/tor-fw-helper/tor-fw-helper.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.Tpo src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/tools/tor-fw-helper/tor-fw-helper.c' object='src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.o `test -f 'src/tools/tor-fw-helper/tor-fw-helper.c' || echo '$(srcdir)/'`src/tools/tor-fw-helper/tor-fw-helper.c src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.obj: src/tools/tor-fw-helper/tor-fw-helper.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.obj -MD -MP -MF src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.Tpo -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.obj `if test -f 'src/tools/tor-fw-helper/tor-fw-helper.c'; then $(CYGPATH_W) 'src/tools/tor-fw-helper/tor-fw-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/tools/tor-fw-helper/tor-fw-helper.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.Tpo src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/tools/tor-fw-helper/tor-fw-helper.c' object='src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper.obj `if test -f 'src/tools/tor-fw-helper/tor-fw-helper.c'; then $(CYGPATH_W) 'src/tools/tor-fw-helper/tor-fw-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/tools/tor-fw-helper/tor-fw-helper.c'; fi` src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.o: src/tools/tor-fw-helper/tor-fw-helper-natpmp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.o -MD -MP -MF src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.Tpo -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.o `test -f 'src/tools/tor-fw-helper/tor-fw-helper-natpmp.c' || echo '$(srcdir)/'`src/tools/tor-fw-helper/tor-fw-helper-natpmp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.Tpo src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/tools/tor-fw-helper/tor-fw-helper-natpmp.c' object='src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.o `test -f 'src/tools/tor-fw-helper/tor-fw-helper-natpmp.c' || echo '$(srcdir)/'`src/tools/tor-fw-helper/tor-fw-helper-natpmp.c src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.obj: src/tools/tor-fw-helper/tor-fw-helper-natpmp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.obj -MD -MP -MF src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.Tpo -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.obj `if test -f 'src/tools/tor-fw-helper/tor-fw-helper-natpmp.c'; then $(CYGPATH_W) 'src/tools/tor-fw-helper/tor-fw-helper-natpmp.c'; else $(CYGPATH_W) '$(srcdir)/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.Tpo src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/tools/tor-fw-helper/tor-fw-helper-natpmp.c' object='src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-natpmp.obj `if test -f 'src/tools/tor-fw-helper/tor-fw-helper-natpmp.c'; then $(CYGPATH_W) 'src/tools/tor-fw-helper/tor-fw-helper-natpmp.c'; else $(CYGPATH_W) '$(srcdir)/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c'; fi` src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.o: src/tools/tor-fw-helper/tor-fw-helper-upnp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.o -MD -MP -MF src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.Tpo -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.o `test -f 'src/tools/tor-fw-helper/tor-fw-helper-upnp.c' || echo '$(srcdir)/'`src/tools/tor-fw-helper/tor-fw-helper-upnp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.Tpo src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/tools/tor-fw-helper/tor-fw-helper-upnp.c' object='src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.o `test -f 'src/tools/tor-fw-helper/tor-fw-helper-upnp.c' || echo '$(srcdir)/'`src/tools/tor-fw-helper/tor-fw-helper-upnp.c src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.obj: src/tools/tor-fw-helper/tor-fw-helper-upnp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.obj -MD -MP -MF src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.Tpo -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.obj `if test -f 'src/tools/tor-fw-helper/tor-fw-helper-upnp.c'; then $(CYGPATH_W) 'src/tools/tor-fw-helper/tor-fw-helper-upnp.c'; else $(CYGPATH_W) '$(srcdir)/src/tools/tor-fw-helper/tor-fw-helper-upnp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.Tpo src/tools/tor-fw-helper/$(DEPDIR)/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/tools/tor-fw-helper/tor-fw-helper-upnp.c' object='src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_tor_fw_helper_tor_fw_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/tools/tor-fw-helper/src_tools_tor_fw_helper_tor_fw_helper-tor-fw-helper-upnp.obj `if test -f 'src/tools/tor-fw-helper/tor-fw-helper-upnp.c'; then $(CYGPATH_W) 'src/tools/tor-fw-helper/tor-fw-helper-upnp.c'; else $(CYGPATH_W) '$(srcdir)/src/tools/tor-fw-helper/tor-fw-helper-upnp.c'; fi` install-man1: $(nodist_man1_MANS) @$(NORMAL_INSTALL) @list1='$(nodist_man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(nodist_man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-confDATA: $(conf_DATA) @$(NORMAL_INSTALL) @list='$(conf_DATA)'; test -n "$(confdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(confdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(confdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(confdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(confdir)" || exit $$?; \ done uninstall-confDATA: @$(NORMAL_UNINSTALL) @list='$(conf_DATA)'; test -n "$(confdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(confdir)'; $(am__uninstall_files_from_dir) install-docDATA: $(doc_DATA) @$(NORMAL_INSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-docDATA: @$(NORMAL_UNINSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-tordataDATA: $(tordata_DATA) @$(NORMAL_INSTALL) @list='$(tordata_DATA)'; test -n "$(tordatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(tordatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(tordatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(tordatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(tordatadir)" || exit $$?; \ done uninstall-tordataDATA: @$(NORMAL_UNINSTALL) @list='$(tordata_DATA)'; test -n "$(tordatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(tordatadir)'; $(am__uninstall_files_from_dir) ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) orconfig.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) orconfig.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) orconfig.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) orconfig.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ col="$$grn"; \ else \ col="$$red"; \ fi; \ echo "$${col}$$dashes$${std}"; \ echo "$${col}$$banner$${std}"; \ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ test -z "$$report" || echo "$${col}$$report$${std}"; \ echo "$${col}$$dashes$${std}"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically \`make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod u+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(SCRIPTS) $(MANS) $(DATA) \ $(HEADERS) orconfig.h installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(confdir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(tordatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f src/common/$(DEPDIR)/$(am__dirstamp) -rm -f src/common/$(am__dirstamp) -rm -f src/ext/$(DEPDIR)/$(am__dirstamp) -rm -f src/ext/$(am__dirstamp) -rm -f src/ext/curve25519_donna/$(DEPDIR)/$(am__dirstamp) -rm -f src/ext/curve25519_donna/$(am__dirstamp) -rm -f src/or/$(DEPDIR)/$(am__dirstamp) -rm -f src/or/$(am__dirstamp) -rm -f src/test/$(DEPDIR)/$(am__dirstamp) -rm -f src/test/$(am__dirstamp) -rm -f src/tools/$(DEPDIR)/$(am__dirstamp) -rm -f src/tools/$(am__dirstamp) -rm -f src/tools/tor-fw-helper/$(DEPDIR)/$(am__dirstamp) -rm -f src/tools/tor-fw-helper/$(am__dirstamp) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-noinstLIBRARIES \ clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf src/common/$(DEPDIR) src/ext/$(DEPDIR) src/ext/curve25519_donna/$(DEPDIR) src/or/$(DEPDIR) src/test/$(DEPDIR) src/tools/$(DEPDIR) src/tools/tor-fw-helper/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-confDATA install-docDATA install-man \ install-tordataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-binSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf src/common/$(DEPDIR) src/ext/$(DEPDIR) src/ext/curve25519_donna/$(DEPDIR) src/or/$(DEPDIR) src/test/$(DEPDIR) src/tools/$(DEPDIR) src/tools/tor-fw-helper/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-confDATA uninstall-docDATA uninstall-man \ uninstall-tordataDATA uninstall-man: uninstall-man1 .MAKE: all check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am am--refresh check check-TESTS check-am \ clean clean-binPROGRAMS clean-generic clean-noinstLIBRARIES \ clean-noinstPROGRAMS ctags dist dist-all dist-bzip2 dist-gzip \ dist-lzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-compile distclean-generic \ distclean-hdr distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-binSCRIPTS \ install-confDATA install-data install-data-am install-docDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-strip install-tordataDATA installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-confDATA uninstall-docDATA uninstall-man \ uninstall-man1 uninstall-tordataDATA src/common/common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(COMMONHEADERS) $(AM_V_GEN)if test "@SHA1SUM@" != none; then \ (cd "$(srcdir)" && "@SHA1SUM@" $(src_common_libor_SOURCES) $(src_common_libor_crypto_a_SOURCES) $(COMMONHEADERS)) | "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > $@; \ elif test "@OPENSSL@" != none; then \ (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_common_libor_SOURCES) $(src_Common_libor_crypto_a_SOURCES) $(COMMONHEADERS)) | "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > $@; \ else \ rm $@; \ touch $@; \ fi src/common/util_codedigest.o: src/common/common_sha1.i src/or/tor_main.o: micro-revision.i src/or/config_codedigest.o: src/or/or_sha1.i micro-revision.i: FORCE @rm -f micro-revision.tmp; \ if test -d "$(top_srcdir)/.git" && \ test -x "`which git 2>&1;true`"; then \ HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \ echo \"$$HASH\" > micro-revision.tmp; \ fi; \ if test ! -f micro-revision.tmp ; then \ if test ! -f micro-revision.i ; then \ echo '""' > micro-revision.i; \ fi; \ elif test ! -f micro-revision.i || \ test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \ mv micro-revision.tmp micro-revision.i; \ fi; true src/or/or_sha1.i: $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS) $(AM_V_GEN)if test "@SHA1SUM@" != none; then \ (cd "$(srcdir)" && "@SHA1SUM@" $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS) ) | \ "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > src/or/or_sha1.i; \ elif test "@OPENSSL@" != none; then \ (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS)) | \ "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > src/or/or_sha1.i; \ else \ rm src/or/or_sha1.i; \ touch src/or/or_sha1.i; \ fi FORCE: # fallback_consensus # If we don't have it, fake it. src_config_fallback-consensus: touch src/config/fallback-consensus # Generate the html documentation from asciidoc, but don't do # machine-specific replacements yet $(html_in) : $(AM_V_GEN)$(top_srcdir)/doc/asciidoc-helper.sh html @ASCIIDOC@ $(top_srcdir)/$@ # Generate the manpage from asciidoc, but don't do # machine-specific replacements yet $(man_in) : $(AM_V_GEN)$(top_srcdir)/doc/asciidoc-helper.sh man @A2X@ $(top_srcdir)/$@ doc/tor.1.in: doc/tor.1.txt doc/tor-gencert.1.in: doc/tor-gencert.1.txt doc/tor-resolve.1.in: doc/tor-resolve.1.txt doc/torify.1.in: doc/torify.1.txt doc/tor-fw-helper.1.in: doc/tor-fw-helper.1.txt doc/tor.html.in: doc/tor.1.txt doc/tor-gencert.html.in: doc/tor-gencert.1.txt doc/tor-resolve.html.in: doc/tor-resolve.1.txt doc/torify.html.in: doc/torify.1.txt doc/tor-fw-helper.html.in: doc/tor-fw-helper.1.txt # use ../config.status to swap all machine-specific magic strings # in the asciidoc with their replacements. $(asciidoc_product) : $(AM_V_GEN)$(MKDIR_P) $(@D) $(AM_V_at)if test -e $(top_srcdir)/$@.in && ! test -e $@.in ; then \ cp $(top_srcdir)/$@.in $@; \ fi $(AM_V_at)./config.status -q --file=$@; doc/tor.html: doc/tor.html.in doc/tor-gencert.html: doc/tor-gencert.html.in doc/tor-resolve.html: doc/tor-resolve.html.in doc/torify.html: doc/torify.html.in doc/tor-fw-helper.html: doc/tor-fw-helper.html.in doc/tor.1: doc/tor.1.in doc/tor-gencert.1: doc/tor-gencert.1.in doc/tor-resolve.1: doc/tor-resolve.1.in doc/torify.1: doc/torify.1.in doc/tor-fw-helper.1: doc/tor-fw-helper.1.in #install-data-local: # $(INSTALL) -m 755 -d $(LOCALSTATEDIR)/lib/tor # Allows to override rpmbuild with rpmbuild-md5 from fedora-packager so that # building for EL5 won't fail on https://bugzilla.redhat.com/show_bug.cgi?id=490613 RPMBUILD ?= rpmbuild # Use automake's dist-gzip target to build the tarball dist-rpm: dist-gzip TIMESTAMP=$$(date +"%Y-%m-%d_%H.%M.%S"); \ RPM_BUILD_DIR=$$(mktemp -d "/tmp/tor-rpm-build-$$TIMESTAMP-XXXX"); \ mkdir -p "$$RPM_BUILD_DIR"/{BUILD,RPMS,SOURCES/"tor-$(VERSION)",SPECS,SRPMS}; \ cp -fa "$(distdir).tar.gz" "$$RPM_BUILD_DIR"/SOURCES/; \ LIBS=-lrt $(RPMBUILD) -ba --define "_topdir $$RPM_BUILD_DIR" tor.spec; \ cp -fa "$$RPM_BUILD_DIR"/SRPMS/* .; \ cp -fa "$$RPM_BUILD_DIR"/RPMS/* .; \ rm -rf "$$RPM_BUILD_DIR"; \ echo "RPM build finished"; \ #end of dist-rpm dist: check doxygen: doxygen && cd doc/doxygen/latex && make test: all ./src/test/test # Avoid strlcpy.c, strlcat.c, aes.c, OpenBSD_malloc_Linux.c, sha256.c, # eventdns.[hc], tinytest*.[ch] check-spaces: ./contrib/checkSpace.pl -C \ src/common/*.[ch] \ src/or/*.[ch] \ src/test/*.[ch] \ src/tools/*.[ch] \ src/tools/tor-fw-helper/*.[ch] check-docs: ./contrib/checkOptionDocs.pl check-logs: ./contrib/checkLogs.pl \ src/*/*.[ch] | sort -n version: @echo "Tor @VERSION@" @if test -d "$(top_srcdir)/.git" && test -x "`which git 2>&1;true`"; then \ echo -n "git: " ;\ (cd "$(top_srcdir)" && git rev-parse --short=16 HEAD); \ fi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tor-0.2.4.20/m4/0000755000175000017500000000000012255753763010101 500000000000000tor-0.2.4.20/m4/ax_check_sign.m40000644000175000017500000000403512166112776013044 00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_sign.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_SIGN (TYPE, [ACTION-IF-SIGNED], [ACTION-IF-UNSIGNED], [INCLUDES]) # # DESCRIPTION # # Checks whether TYPE is signed or not. If no INCLUDES are specified, the # default includes are used. If ACTION-IF-SIGNED is given, it is # additional shell code to execute when the type is signed. If # ACTION-IF-UNSIGNED is given, it is executed when the type is unsigned. # # This macro assumes that the type exists. Therefore the existence of the # type should be checked before calling this macro. For example: # # AC_CHECK_HEADERS([wchar.h]) # AC_CHECK_TYPE([wchar_t],,[ AC_MSG_ERROR([Type wchar_t not found.]) ]) # AX_CHECK_SIGN([wchar_t], # [ AC_DEFINE(WCHAR_T_SIGNED, 1, [Define if wchar_t is signed]) ], # [ AC_DEFINE(WCHAR_T_UNSIGNED, 1, [Define if wchar_t is unsigned]) ], [ # #ifdef HAVE_WCHAR_H # #include # #endif # ]) # # LICENSE # # Copyright (c) 2008 Ville Laurikari # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AU_ALIAS([VL_CHECK_SIGN], [AX_CHECK_SIGN]) AC_DEFUN([AX_CHECK_SIGN], [ typename=`echo $1 | sed "s/@<:@^a-zA-Z0-9_@:>@/_/g"` AC_CACHE_CHECK([whether $1 is signed], ax_cv_decl_${typename}_signed, [ AC_TRY_COMPILE([$4], [ int foo @<:@ 1 - 2 * !((($1) -1) < 0) @:>@ ], [ eval "ax_cv_decl_${typename}_signed=\"yes\"" ], [ eval "ax_cv_decl_${typename}_signed=\"no\"" ])]) symbolname=`echo $1 | sed "s/@<:@^a-zA-Z0-9_@:>@/_/g" | tr "a-z" "A-Z"` if eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"yes\""; then $2 elif eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"no\""; then $3 fi ])dnl tor-0.2.4.20/depcomp0000755000175000017500000005064312255745724011064 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2012-03-27.16; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # A tabulation character. tab=' ' # A newline character. nl=' ' if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' "$nl" < "$tmpdepfile" | ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependent.h'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. # However on # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\': # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... # tcc 0.9.26 (FIXME still under development at the moment of writing) # will emit a similar output, but also prepend the continuation lines # with horizontal tabulation characters. "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form 'foo.o: dependent.h', # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ < "$tmpdepfile" > "$depfile" sed ' s/[ '"$tab"'][ '"$tab"']*/ /g s/^ *// s/ *\\*$// s/^[^:]*: *// /^$/d /:$/d s/$/ :/ ' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test "$stat" = 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' "$nl" < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: tor-0.2.4.20/compile0000755000175000017500000001615212255745723011061 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-03-05.13; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010, 2012 Free # Software Foundation, Inc. # Written by Tom Tromey . # # 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, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: tor-0.2.4.20/orconfig.h.in0000644000175000017500000003744012255745720012067 00000000000000/* orconfig.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* tor's build directory */ #undef BUILDDIR /* tor's configuration directory */ #undef CONFDIR /* Defined if we have a curve25519 implementation */ #undef CURVE25519_ENABLED /* Enable dmalloc's malloc function check */ #undef DMALLOC_FUNC_CHECK /* Define to 1 iff memset(0) sets doubles to 0.0 */ #undef DOUBLE_0_REP_IS_ZERO_BYTES /* Defined if we try to use freelists for buffer RAM chunks */ #undef ENABLE_BUF_FREELISTS /* Defined if we default to host local appdata paths on Windows */ #undef ENABLE_LOCAL_APPDATA /* Defined if we will try to use multithreading */ #undef ENABLE_THREADS /* Define if enum is always signed */ #undef ENUM_VALS_ARE_SIGNED /* Define to nothing if C supports flexible array members, and to 1 if it does not. That way, with a declaration like `struct s { int n; double d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99 compilers. When computing the size of such an object, don't use 'sizeof (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)' instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with MSVC and with C++ compilers. */ #undef FLEXIBLE_ARRAY_MEMBER /* Define to 1 if you have the `accept4' function. */ #undef HAVE_ACCEPT4 /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ASSERT_H /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* Define to 1 if you have the header file. */ #undef HAVE_CRT_EXTERNS_H /* Define to 1 if you have the header file. */ #undef HAVE_CRYPTO_SCALARMULT_CURVE25519_H /* Define to 1 if you have the declaration of `mlockall', and to 0 if you don't. */ #undef HAVE_DECL_MLOCKALL /* Define to 1 if you have the header file. */ #undef HAVE_DMALLOC_H /* Define to 1 if you have the `dmalloc_strdup' function. */ #undef HAVE_DMALLOC_STRDUP /* Define to 1 if you have the `dmalloc_strndup' function. */ #undef HAVE_DMALLOC_STRNDUP /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the `evdns_set_outgoing_bind_address' function. */ #undef HAVE_EVDNS_SET_OUTGOING_BIND_ADDRESS /* Define to 1 if you have the header file. */ #undef HAVE_EVENT2_BUFFEREVENT_SSL_H /* Define to 1 if you have the header file. */ #undef HAVE_EVENT2_DNS_H /* Define to 1 if you have the header file. */ #undef HAVE_EVENT2_EVENT_H /* Define to 1 if you have the `event_base_loopexit' function. */ #undef HAVE_EVENT_BASE_LOOPEXIT /* Define to 1 if you have the `event_get_method' function. */ #undef HAVE_EVENT_GET_METHOD /* Define to 1 if you have the `event_get_version' function. */ #undef HAVE_EVENT_GET_VERSION /* Define to 1 if you have the `event_get_version_number' function. */ #undef HAVE_EVENT_GET_VERSION_NUMBER /* Define to 1 if you have the `event_set_log_callback' function. */ #undef HAVE_EVENT_SET_LOG_CALLBACK /* Defined if we have extern char **environ already declared */ #undef HAVE_EXTERN_ENVIRON_DECLARED /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `flock' function. */ #undef HAVE_FLOCK /* Define to 1 if you have the `ftime' function. */ #undef HAVE_FTIME /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO /* Define this if you have any gethostbyname_r() */ #undef HAVE_GETHOSTBYNAME_R /* Define this if gethostbyname_r takes 3 arguments */ #undef HAVE_GETHOSTBYNAME_R_3_ARG /* Define this if gethostbyname_r takes 5 arguments */ #undef HAVE_GETHOSTBYNAME_R_5_ARG /* Define this if gethostbyname_r takes 6 arguments */ #undef HAVE_GETHOSTBYNAME_R_6_ARG /* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS /* Define to 1 if you have the `getresgid' function. */ #undef HAVE_GETRESGID /* Define to 1 if you have the `getresuid' function. */ #undef HAVE_GETRESUID /* Define to 1 if you have the `getrlimit' function. */ #undef HAVE_GETRLIMIT /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the `gmtime_r' function. */ #undef HAVE_GMTIME_R /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H /* Define to 1 if you have the `inet_aton' function. */ #undef HAVE_INET_ATON /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `ioctl' function. */ #undef HAVE_IOCTL /* Define to 1 if you have the `issetugid' function. */ #undef HAVE_ISSETUGID /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NETFILTER_IPV4_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_TYPES_H /* Define to 1 if you have the `llround' function. */ #undef HAVE_LLROUND /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have the `lround' function. */ #undef HAVE_LROUND /* Define to 1 if you have the header file. */ #undef HAVE_MACHINE_LIMITS_H /* Defined if the compiler supports __FUNCTION__ */ #undef HAVE_MACRO__FUNCTION__ /* Defined if the compiler supports __FUNC__ */ #undef HAVE_MACRO__FUNC__ /* Defined if the compiler supports __func__ */ #undef HAVE_MACRO__func__ /* Define to 1 if you have the `mallinfo' function. */ #undef HAVE_MALLINFO /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_NP_H /* Define to 1 if you have the `memmem' function. */ #undef HAVE_MEMMEM /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `mlockall' function. */ #undef HAVE_MLOCKALL /* Define to 1 if you have the header file. */ #undef HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN6_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_PFVAR_H /* Define to 1 if you have the `prctl' function. */ #undef HAVE_PRCTL /* Define to 1 if you have the `pthread_create' function. */ #undef HAVE_PTHREAD_CREATE /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H /* Define to 1 if you have the header file. */ #undef HAVE_PWD_H /* Define to 1 if you have the `rint' function. */ #undef HAVE_RINT /* Define to 1 if the system has the type `rlim_t'. */ #undef HAVE_RLIM_T /* Define to 1 if the system has the type `sa_family_t'. */ #undef HAVE_SA_FAMILY_T /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the `socketpair' function. */ #undef HAVE_SOCKETPAIR /* Define to 1 if the system has the type `ssize_t'. */ #undef HAVE_SSIZE_T /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strptime' function. */ #undef HAVE_STRPTIME /* Define to 1 if you have the `strtok_r' function. */ #undef HAVE_STRTOK_R /* Define to 1 if you have the `strtoull' function. */ #undef HAVE_STRTOULL /* Define to 1 if `min_heap_idx' is a member of `struct event'. */ #undef HAVE_STRUCT_EVENT_MIN_HEAP_IDX /* Define to 1 if the system has the type `struct in6_addr'. */ #undef HAVE_STRUCT_IN6_ADDR /* Define to 1 if `s6_addr16' is a member of `struct in6_addr'. */ #undef HAVE_STRUCT_IN6_ADDR_S6_ADDR16 /* Define to 1 if `s6_addr32' is a member of `struct in6_addr'. */ #undef HAVE_STRUCT_IN6_ADDR_S6_ADDR32 /* Define to 1 if the system has the type `struct sockaddr_in6'. */ #undef HAVE_STRUCT_SOCKADDR_IN6 /* Define to 1 if `sin6_len' is a member of `struct sockaddr_in6'. */ #undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN /* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */ #undef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN /* Define to 1 if `tv_sec' is a member of `struct timeval'. */ #undef HAVE_STRUCT_TIMEVAL_TV_SEC /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PRCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SYSLIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UTIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if the system has the type `uint'. */ #undef HAVE_UINT /* Define to 1 if you have the `uname' function. */ #undef HAVE_UNAME /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H /* Define to 1 if the system has the type `u_char'. */ #undef HAVE_U_CHAR /* Define to 1 if you have the `vasprintf' function. */ #undef HAVE_VASPRINTF /* Define to 1 if you have the `_NSGetEnviron' function. */ #undef HAVE__NSGETENVIRON /* Define to 1 if you have the `_vscprintf' function. */ #undef HAVE__VSCPRINTF /* Defined if we want to keep track of how much of each kind of resource we download. */ #undef INSTRUMENT_DOWNLOADS /* name of the syslog facility */ #undef LOGFACILITY /* Define to 1 iff malloc(0) returns a pointer */ #undef MALLOC_ZERO_WORKS /* Define to 1 if we are building with UPnP. */ #undef MINIUPNPC /* libminiupnpc version 1.5 found */ #undef MINIUPNPC15 /* Define to 1 if we are building with nat-pmp. */ #undef NAT_PMP /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* Define to 1 iff memset(0) sets pointers to NULL */ #undef NULL_REP_IS_ZERO_BYTES /* "Define to handle pf on OpenBSD properly" */ #undef OPENBSD /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 iff right-shifting a negative value performs sign-extension */ #undef RSHIFT_DOES_SIGN_EXTEND /* The size of `cell_t', as computed by sizeof. */ #undef SIZEOF_CELL_T /* The size of `char', as computed by sizeof. */ #undef SIZEOF_CHAR /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT /* The size of `int16_t', as computed by sizeof. */ #undef SIZEOF_INT16_T /* The size of `int32_t', as computed by sizeof. */ #undef SIZEOF_INT32_T /* The size of `int64_t', as computed by sizeof. */ #undef SIZEOF_INT64_T /* The size of `int8_t', as computed by sizeof. */ #undef SIZEOF_INT8_T /* The size of `intptr_t', as computed by sizeof. */ #undef SIZEOF_INTPTR_T /* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG /* The size of `long long', as computed by sizeof. */ #undef SIZEOF_LONG_LONG /* The size of `pid_t', as computed by sizeof. */ #undef SIZEOF_PID_T /* The size of `short', as computed by sizeof. */ #undef SIZEOF_SHORT /* The size of `size_t', as computed by sizeof. */ #undef SIZEOF_SIZE_T /* The size of `socklen_t', as computed by sizeof. */ #undef SIZEOF_SOCKLEN_T /* The size of `time_t', as computed by sizeof. */ #undef SIZEOF_TIME_T /* The size of `uint16_t', as computed by sizeof. */ #undef SIZEOF_UINT16_T /* The size of `uint32_t', as computed by sizeof. */ #undef SIZEOF_UINT32_T /* The size of `uint64_t', as computed by sizeof. */ #undef SIZEOF_UINT64_T /* The size of `uint8_t', as computed by sizeof. */ #undef SIZEOF_UINT8_T /* The size of `uintptr_t', as computed by sizeof. */ #undef SIZEOF_UINTPTR_T /* The size of `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P /* The size of `__int64', as computed by sizeof. */ #undef SIZEOF___INT64 /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if time_t is signed */ #undef TIME_T_IS_SIGNED /* Defined if we're going to use Libevent's buffered IO API */ #undef USE_BUFFEREVENTS /* Defined if we should use an internal curve25519_donna{,_c64} implementation */ #undef USE_CURVE25519_DONNA /* Defined if we should use a curve25519 from nacl */ #undef USE_CURVE25519_NACL /* Debug memory allocation library */ #undef USE_DMALLOC /* "Define to enable transparent proxy support" */ #undef USE_TRANSPARENT /* Define to 1 iff we represent negative integers with two's complement */ #undef USING_TWOS_COMPLEMENT /* Version number of package */ #undef VERSION /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define on some platforms to activate x_r() functions in time.h */ #undef _REENTRANT /* Define to `unsigned short' if does not define. */ #undef u_int16_t /* Define to `unsigned long' if does not define. */ #undef u_int32_t /* Define to `unsigned long long' if does not define. */ #undef u_int64_t /* Define to `unsigned char' if does not define. */ #undef u_int8_t tor-0.2.4.20/ReleaseNotes0000644000175000017500000176343412255673711012031 00000000000000 This document summarizes new features and bugfixes in each stable release of Tor. If you want to see more detailed descriptions of the changes in each development snapshot, see the ChangeLog file. Changes in version 0.2.4.20 - 2013-12-22 Tor 0.2.4.20 fixes potentially poor random number generation for users who 1) use OpenSSL 1.0.0 or later, 2) set "HardwareAccel 1" in their torrc file, 3) have "Sandy Bridge" or "Ivy Bridge" Intel processors, and 4) have no state file in their DataDirectory (as would happen on first start). Users who generated relay or hidden service identity keys in such a situation should discard them and generate new ones. This release also fixes a logic error that caused Tor clients to build many more preemptive circuits than they actually need. o Major bugfixes: - Do not allow OpenSSL engines to replace the PRNG, even when HardwareAccel is set. The only default builtin PRNG engine uses the Intel RDRAND instruction to replace the entire PRNG, and ignores all attempts to seed it with more entropy. That's cryptographically stupid: the right response to a new alleged entropy source is never to discard all previously used entropy sources. Fixes bug 10402; works around behavior introduced in OpenSSL 1.0.0. Diagnosis and investigation thanks to "coderman" and "rl1987". - Fix assertion failure when AutomapHostsOnResolve yields an IPv6 address. Fixes bug 10465; bugfix on 0.2.4.7-alpha. - Avoid launching spurious extra circuits when a stream is pending. This fixes a bug where any circuit that _wasn't_ unusable for new streams would be treated as if it were, causing extra circuits to be launched. Fixes bug 10456; bugfix on 0.2.4.12-alpha. o Minor bugfixes: - Avoid a crash bug when starting with a corrupted microdescriptor cache file. Fixes bug 10406; bugfix on 0.2.2.6-alpha. - If we fail to dump a previously cached microdescriptor to disk, avoid freeing duplicate data later on. Fixes bug 10423; bugfix on 0.2.4.13-alpha. Spotted by "bobnomnom". Changes in version 0.2.4.19 - 2013-12-11 The Tor 0.2.4 release series is dedicated to the memory of Aaron Swartz (1986-2013). Aaron worked on diverse projects including helping to guide Creative Commons, playing a key role in stopping SOPA/PIPA, bringing transparency to the U.S government's PACER documents, and contributing design and development for Tor and Tor2Web. Aaron was one of the latest martyrs in our collective fight for civil liberties and human rights, and his death is all the more painful because he was one of us. Tor 0.2.4.19, the first stable release in the 0.2.4 branch, features a new circuit handshake and link encryption that use ECC to provide better security and efficiency; makes relays better manage circuit creation requests; uses "directory guards" to reduce client enumeration risks; makes bridges collect and report statistics about the pluggable transports they support; cleans up and improves our geoip database; gets much closer to IPv6 support for clients, bridges, and relays; makes directory authorities use measured bandwidths rather than advertised ones when computing flags and thresholds; disables client-side DNS caching to reduce tracking risks; and fixes a big bug in bridge reachability testing. This release introduces two new design abstractions in the code: a new "channel" abstraction between circuits and or_connections to allow for implementing alternate relay-to-relay transports, and a new "circuitmux" abstraction storing the queue of circuits for a channel. The release also includes many stability, security, and privacy fixes. o Major features (new circuit handshake): - Tor now supports a new circuit extension handshake designed by Ian Goldberg, Douglas Stebila, and Berkant Ustaoglu. Our original circuit extension handshake, later called "TAP", was a bit slow (especially on the relay side), had a fragile security proof, and used weaker keys than we'd now prefer. The new circuit handshake uses Dan Bernstein's "curve25519" elliptic-curve Diffie-Hellman function, making it significantly more secure than the older handshake, and significantly faster. Tor can use one of two built-in pure-C curve25519-donna implementations by Adam Langley, or it can link against the "nacl" library for a tuned version if present. The built-in version is very fast for 64-bit systems when building with GCC. The built-in 32-bit version is still faster than the old TAP protocol, but using libnacl is better on most such hosts. Implements proposal 216; closes ticket 7202. o Major features (better link encryption): - Relays can now enable the ECDHE TLS ciphersuites when available and appropriate. These ciphersuites let us negotiate forward-secure TLS secret keys more safely and more efficiently than with our previous use of Diffie-Hellman modulo a 1024-bit prime. By default, public relays prefer the (faster) P224 group, and bridges prefer the (more common) P256 group; you can override this with the TLSECGroup option. This feature requires clients running 0.2.3.17-beta or later, and requires both sides to be running OpenSSL 1.0.0 or later with ECC support. OpenSSL 1.0.1, with the compile-time option "enable-ec_nistp_64_gcc_128", is highly recommended. Implements the relay side of proposal 198; closes ticket 7200. - Re-enable TLS 1.1 and 1.2 when built with OpenSSL 1.0.1e or later. Resolves ticket 6055. (OpenSSL before 1.0.1 didn't have TLS 1.1 or 1.2, and OpenSSL from 1.0.1 through 1.0.1d had bugs that prevented renegotiation from working with TLS 1.1 or 1.2, so we had disabled them to solve bug 6033.) o Major features (relay performance): - Instead of limiting the number of queued onionskins (aka circuit create requests) to a fixed, hard-to-configure number, we limit the size of the queue based on how many we expect to be able to process in a given amount of time. We estimate the time it will take to process an onionskin based on average processing time of previous onionskins. Closes ticket 7291. You'll never have to configure MaxOnionsPending again. - Relays process the new "NTor" circuit-level handshake requests with higher priority than the old "TAP" circuit-level handshake requests. We still process some TAP requests to not totally starve 0.2.3 clients when NTor becomes popular. A new consensus parameter "NumNTorsPerTAP" lets us tune the balance later if we need to. Implements ticket 9574. o Major features (client bootstrapping resilience): - Add a new "FallbackDir" torrc option to use when we can't use a directory mirror from the consensus (either because we lack a consensus, or because they're all down). Currently, all authorities are fallbacks by default, and there are no other default fallbacks, but that will change. This option will allow us to give clients a longer list of servers to try to get a consensus from when first connecting to the Tor network, and thereby reduce load on the directory authorities. Implements proposal 206, "Preconfigured directory sources for bootstrapping". We also removed the old "FallbackNetworkstatus" option, since we never got it working well enough to use it. Closes bug 572. - If we have no circuits open, use a relaxed timeout (the 95th-percentile cutoff) until a circuit succeeds. This heuristic should allow Tor to succeed at building circuits even when the network connection drastically changes. Should help with bug 3443. o Major features (use of guards): - Support directory guards (proposal 207): when possible, clients now use their entry guards for non-anonymous directory requests. This can help prevent client enumeration. Note that this behavior only works when we have a usable consensus directory, and when options about what to download are more or less standard. In the future we should re-bootstrap from our guards, rather than re-bootstrapping from the preconfigured list of directory sources that ships with Tor. Resolves ticket 6526. - Raise the default time that a client keeps an entry guard from "1-2 months" to "2-3 months", as suggested by Tariq Elahi's WPES 2012 paper. (We would make it even longer, but we need better client load balancing first.) Also, make the guard lifetime controllable via a new GuardLifetime torrc option and a GuardLifetime consensus parameter. Start of a fix for bug 8240; bugfix on 0.1.1.11-alpha. o Major features (bridges with pluggable transports): - Bridges now report the pluggable transports they support to the bridge authority, so it can pass the supported transports on to bridgedb and/or eventually do reachability testing. Implements ticket 3589. - Automatically forward the TCP ports of pluggable transport proxies using tor-fw-helper if PortForwarding is enabled. Implements ticket 4567. o Major features (geoip database): - Maxmind began labelling Tor relays as being in country "A1", which breaks by-country node selection inside Tor. Now we use a script to replace "A1" ("Anonymous Proxy") entries in our geoip file with real country codes. This script fixes about 90% of "A1" entries automatically and uses manual country code assignments to fix the remaining 10%. See src/config/README.geoip for details. Fixes bug 6266. - Add GeoIP database for IPv6 addresses. The new config option is GeoIPv6File. - Update to the October 2 2013 Maxmind GeoLite Country database. o Major features (IPv6): - Clients who set "ClientUseIPv6 1" may connect to entry nodes over IPv6. Set "ClientPreferIPv6ORPort 1" to make this even more likely to happen. Implements ticket 5535. - All kind of relays, not just bridges, can now advertise an IPv6 OR port. Implements ticket 6362. - Relays can now exit to IPv6 addresses: make sure that you have IPv6 connectivity, then set the IPv6Exit flag to 1. Also make sure your exit policy reads as you would like: the address * applies to all address families, whereas *4 is IPv4 address only, and *6 is IPv6 addresses only. On the client side, you'll need to wait for enough exits to support IPv6, apply the "IPv6Traffic" flag to a SocksPort, and use Socks5. Closes ticket 5547, implements proposal 117 as revised in proposal 208. - Bridge authorities now accept IPv6 bridge addresses and include them in network status documents. Implements ticket 5534. - Directory authorities vote on IPv6 OR ports. Implements ticket 6363. o Major features (directory authorities): - Directory authorities now prefer using measured bandwidths to advertised ones when computing flags and thresholds. Resolves ticket 8273. - Directory authorities that vote measured bandwidths about more than a threshold number of relays now treat relays with unmeasured bandwidths as having bandwidth 0 when computing their flags. Resolves ticket 8435. - Directory authorities now support a new consensus method (17) where they cap the published bandwidth of relays for which insufficient bandwidth measurements exist. Fixes part of bug 2286. - Directory authorities that set "DisableV2DirectoryInfo_ 1" no longer serve any v2 directory information. Now we can test disabling the old deprecated v2 directory format, and see whether doing so has any effect on network load. Begins to fix bug 6783. o Major features (build and portability): - Switch to a nonrecursive Makefile structure. Now instead of each Makefile.am invoking other Makefile.am's, there is a master Makefile.am that includes the others. This change makes our build process slightly more maintainable, and improves parallelism for building with make -j. Original patch by Stewart Smith; various fixes by Jim Meyering. - Where available, we now use automake's "silent" make rules by default, so that warnings are easier to spot. You can get the old behavior with "make V=1". Patch by Stewart Smith for ticket 6522. - Resume building correctly with MSVC and Makefile.nmake. This patch resolves numerous bugs and fixes reported by ultramage, including 7305, 7308, 7309, 7310, 7312, 7313, 7315, 7316, and 7669. o Security features: - Switch to a completely time-invariant approach for picking nodes weighted by bandwidth. Our old approach would run through the part of the loop after it had made its choice slightly slower than it ran through the part of the loop before it had made its choice. Addresses ticket 6538. - Disable the use of Guard nodes when in Tor2WebMode. Guard usage by tor2web clients allows hidden services to identify tor2web clients through their repeated selection of the same rendezvous and introduction point circuit endpoints (their guards). Resolves ticket 6888. o Major bugfixes (relay denial of service): - When we have too much memory queued in circuits (according to a new MaxMemInCellQueues option), close the circuits that have the oldest queued cells, on the theory that those are most responsible for us running low on memory. This prevents us from running out of memory as a relay if circuits fill up faster than they can be drained. Fixes bugs 9063 and 9093; bugfix on the 54th commit of Tor. This bug is a further fix beyond bug 6252, whose fix was merged into 0.2.3.21-rc. - Reject bogus create and relay cells with 0 circuit ID or 0 stream ID: these could be used to create unexpected streams and circuits which would count as "present" to some parts of Tor but "absent" to others, leading to zombie circuits and streams or to a bandwidth denial-of-service. Fixes bug 7889; bugfix on every released version of Tor. Reported by "oftc_must_be_destroyed". - Avoid a bug where our response to TLS renegotiation under certain network conditions could lead to a busy-loop, with 100% CPU consumption. Fixes bug 5650; bugfix on 0.2.0.16-alpha. o Major bugfixes (asserts, crashes, leaks): - Prevent the get_freelists() function from running off the end of the list of freelists if it somehow gets an unrecognized allocation. Fixes bug 8844; bugfix on 0.2.0.16-alpha. Reported by eugenis. - Avoid a memory leak where we would leak a consensus body when we find that a consensus which we couldn't previously verify due to missing certificates is now verifiable. Fixes bug 8719; bugfix on 0.2.0.10-alpha. - If we are unable to save a microdescriptor to the journal, do not drop it from memory and then reattempt downloading it. Fixes bug 9645; bugfix on 0.2.2.6-alpha. - Fix an assertion failure that would occur when disabling the ORPort setting on a running Tor process while accounting was enabled. Fixes bug 6979; bugfix on 0.2.2.18-alpha. - Avoid an assertion failure on OpenBSD (and perhaps other BSDs) when an exit connection with optimistic data succeeds immediately rather than returning EINPROGRESS. Fixes bug 9017; bugfix on 0.2.3.1-alpha. - Fix a memory leak that would occur whenever a configuration option changed. Fixes bug 8718; bugfix on 0.2.3.3-alpha. o Major bugfixes (relay rate limiting): - When a TLS write is partially successful but incomplete, remember that the flushed part has been flushed, and notice that bytes were actually written. Reported and fixed pseudonymously. Fixes bug 7708; bugfix on Tor 0.1.0.5-rc. - Raise the default BandwidthRate/BandwidthBurst values from 5MB/10MB to 1GB/1GB. The previous defaults were intended to be "basically infinite", but it turns out they're now limiting our 100mbit+ relays and bridges. Fixes bug 6605; bugfix on 0.2.0.10-alpha (the last time we raised it). - No longer stop reading or writing on cpuworker connections when our rate limiting buckets go empty. Now we should handle circuit handshake requests more promptly. Resolves bug 9731. o Major bugfixes (client-side privacy): - When we mark a circuit as unusable for new circuits, have it continue to be unusable for new circuits even if MaxCircuitDirtiness is increased too much at the wrong time, or the system clock jumps backwards. Fixes bug 6174; bugfix on 0.0.2pre26. - If ClientDNSRejectInternalAddresses ("do not believe DNS queries which have resolved to internal addresses") is set, apply that rule to IPv6 as well. Fixes bug 8475; bugfix on 0.2.0.7-alpha. - When an exit relay rejects a stream with reason "exit policy", but we only know an exit policy summary (e.g. from the microdesc consensus) for it, do not mark the relay as useless for all exiting. Instead, mark just the circuit as unsuitable for that particular address. Fixes part of bug 7582; bugfix on 0.2.3.2-alpha. o Major bugfixes (stream isolation): - Allow applications to get proper stream isolation with IsolateSOCKSAuth. Many SOCKS5 clients that want to offer username/password authentication also offer "no authentication". Tor had previously preferred "no authentication", so the applications never actually sent Tor their auth details. Now Tor selects username/password authentication if it's offered. You can disable this behavior on a per-SOCKSPort basis via PreferSOCKSNoAuth. Fixes bug 8117; bugfix on 0.2.3.3-alpha. - Follow the socks5 protocol when offering username/password authentication. The fix for bug 8117 exposed this bug, and it turns out real-world applications like Pidgin do care. Bugfix on 0.2.3.2-alpha; fixes bug 8879. o Major bugfixes (client circuit building): - Alter circuit build timeout measurement to start at the point where we begin the CREATE/CREATE_FAST step (as opposed to circuit initialization). This should make our timeout measurements more uniform. Previously, we were sometimes including ORconn setup time in our circuit build time measurements. Should resolve bug 3443. - If the circuit build timeout logic is disabled (via the consensus, or because we are an authority), then don't build testing circuits. Fixes bug 9657; bugfix on 0.2.2.14-alpha. o Major bugfixes (client-side DNS): - Turn off the client-side DNS cache by default. Updating and using the DNS cache is now configurable on a per-client-port level. SOCKSPort, DNSPort, etc lines may now contain {No,}Cache{IPv4,IPv6,}DNS lines to indicate that we shouldn't cache these types of DNS answers when we receive them from an exit node in response to an application request on this port, and {No,}UseCached{IPv4,IPv6,DNS} lines to indicate that if we have cached DNS answers of these types, we shouldn't use them. It's potentially risky to use cached DNS answers at the client, since doing so can indicate to one exit what answers we've gotten for DNS lookups in the past. With IPv6, this becomes especially problematic. Using cached DNS answers for requests on the same circuit would present less linkability risk, since all traffic on a circuit is already linkable, but it would also provide little performance benefit: the exit node caches DNS replies too. Implements a simplified version of Proposal 205. Implements ticket 7570. o Major bugfixes (hidden service privacy): - Limit hidden service descriptors to at most ten introduction points, to slow one kind of guard enumeration. Fixes bug 9002; bugfix on 0.1.1.11-alpha. o Major bugfixes (directory fetching): - If the time to download the next old-style networkstatus is in the future, do not decline to consider whether to download the next microdescriptor networkstatus. Fixes bug 9564; bugfix on 0.2.3.14-alpha. - We used to always request authority certificates by identity digest, meaning we'd get the newest one even when we wanted one with a different signing key. Then we would complain about being given a certificate we already had, and never get the one we really wanted. Now we use the "fp-sk/" resource as well as the "fp/" resource to request the one we want. Fixes bug 5595; bugfix on 0.2.0.8-alpha. o Major bugfixes (bridge reachability): - Bridges now send AUTH_CHALLENGE cells during their v3 handshakes; previously they did not, which prevented them from receiving successful connections from relays for self-test or bandwidth testing. Also, when a relay is extending a circuit to a bridge, it needs to send a NETINFO cell, even when the bridge hasn't sent an AUTH_CHALLENGE cell. Fixes bug 9546; bugfix on 0.2.3.6-alpha. o Major bugfixes (control interface): - When receiving a new configuration file via the control port's LOADCONF command, do not treat the defaults file as absent. Fixes bug 9122; bugfix on 0.2.3.9-alpha. o Major bugfixes (directory authorities): - Stop marking every relay as having been down for one hour every time we restart a directory authority. These artificial downtimes were messing with our Stable and Guard flag calculations. Fixes bug 8218 (introduced by the fix for 1035). Bugfix on 0.2.2.23-alpha. - When computing directory thresholds, ignore any rejected-as-sybil nodes during the computation so that they can't influence Fast, Guard, etc. (We should have done this for proposal 109.) Fixes bug 8146. - When marking a node as a likely sybil, reset its uptime metrics to zero, so that it cannot time towards getting marked as Guard, Stable, or HSDir. (We should have done this for proposal 109.) Fixes bug 8147. - Fix a bug in the voting algorithm that could yield incorrect results when a non-naming authority declared too many flags. Fixes bug 9200; bugfix on 0.2.0.3-alpha. o Internal abstraction features: - Introduce new channel_t abstraction between circuits and or_connection_t to allow for implementing alternate OR-to-OR transports. A channel_t is an abstract object which can either be a cell-bearing channel, which is responsible for authenticating and handshaking with the remote OR and transmitting cells to and from it, or a listening channel, which spawns new cell-bearing channels at the request of remote ORs. Implements part of ticket 6465. - Make a channel_tls_t subclass of channel_t, adapting it to the existing or_connection_t code. The V2/V3 protocol handshaking code which formerly resided in command.c has been moved below the channel_t abstraction layer and may be found in channeltls.c now. Implements the rest of ticket 6465. - Introduce new circuitmux_t storing the queue of circuits for a channel; this encapsulates and abstracts the queue logic and circuit selection policy, and allows the latter to be overridden easily by switching out a policy object. The existing EWMA behavior is now implemented as a circuitmux_policy_t. Resolves ticket 6816. o New build requirements: - Tor now requires OpenSSL 0.9.8 or later. OpenSSL 1.0.0 or later is strongly recommended. - Tor maintainers now require Automake version 1.9 or later to build Tor from the Git repository. (Automake is not required when building from a source distribution.) o Minor features (protocol): - No longer include the "opt" prefix when generating routerinfos or v2 directories: it has been needless since Tor 0.1.2. Closes ticket 5124. - Reject EXTEND cells sent to nonexistent streams. According to the spec, an EXTEND cell sent to _any_ nonzero stream ID is invalid, but we were only checking for stream IDs that were currently in use. Found while hunting for more instances of bug 6271. Bugfix on 0.0.2pre8, which introduced incremental circuit construction. - Tor relays and clients now support a better CREATE/EXTEND cell format, allowing the sender to specify multiple address, identity, and handshake types. Implements Robert Ransom's proposal 200; closes ticket 7199. - Reject as invalid most directory objects containing a NUL. Belt-and-suspender fix for bug 8037. o Minor features (security): - Clear keys and key-derived material left on the stack in rendservice.c and rendclient.c. Check return value of crypto_pk_write_private_key_to_string() in rend_service_load_keys(). These fixes should make us more forward-secure against cold-boot attacks and the like. Fixes bug 2385. - Use our own weak RNG when we need a weak RNG. Windows's rand() and Irix's random() only return 15 bits; Solaris's random() returns more bits but its RAND_MAX says it only returns 15, and so on. Motivated by the fix for bug 7801; bugfix on 0.2.2.20-alpha. o Minor features (control protocol): - Add a "GETINFO signal/names" control port command. Implements ticket 3842. - Provide default values for all options via "GETINFO config/defaults". Implements ticket 4971. - Allow an optional $ before the node identity digest in the controller command GETINFO ns/id/, for consistency with md/id/ and desc/id/. Resolves ticket 7059. - Add CACHED keyword to ADDRMAP events in the control protocol to indicate whether a DNS result will be cached or not. Resolves ticket 8596. - Generate bootstrapping status update events correctly when fetching microdescriptors. Fixes bug 9927. o Minor features (path selection): - When deciding whether we have enough descriptors to build circuits, instead of looking at raw relay counts, look at which fraction of (bandwidth-weighted) paths we're able to build. This approach keeps clients from building circuits if their paths are likely to stand out statistically. The default fraction of paths needed is taken from the consensus directory; you can override it with the new PathsNeededToBuildCircuits option. Fixes ticket 5956. - When any country code is listed in ExcludeNodes or ExcludeExitNodes, and we have GeoIP information, also exclude all nodes with unknown countries "??" and "A1". This behavior is controlled by the new GeoIPExcludeUnknown option: you can make such nodes always excluded with "GeoIPExcludeUnknown 1", and disable the feature with "GeoIPExcludeUnknown 0". Setting "GeoIPExcludeUnknown auto" gets you the default behavior. Implements feature 7706. o Minor features (hidden services): - Improve circuit build timeout handling for hidden services. In particular: adjust build timeouts more accurately depending upon the number of hop-RTTs that a particular circuit type undergoes. Additionally, launch intro circuits in parallel if they timeout, and take the first one to reply as valid. - The Tor client now ignores sub-domain components of a .onion address. This change makes HTTP "virtual" hosting possible: http://foo.aaaaaaaaaaaaaaaa.onion/ and http://bar.aaaaaaaaaaaaaaaa.onion/ can be two different websites hosted on the same hidden service. Implements proposal 204. - Enable Tor to read configuration, state, and key information from a FIFO. Previously Tor would only read from files with a positive stat.st_size. Code from meejah; fixes bug 6044. o Minor features (clients): - Teach bridge-using clients to avoid 0.2.2.x bridges when making microdescriptor-related dir requests, and only fall back to normal descriptors if none of their bridges can handle microdescriptors (as opposed to the fix in ticket 4013, which caused them to fall back to normal descriptors if *any* of their bridges preferred them). Resolves ticket 4994. - Tweak tor-fw-helper to accept an arbitrary amount of arbitrary TCP ports to forward. In the past it only accepted two ports: the ORPort and the DirPort. o Minor features (protecting client timestamps): - Clients no longer send timestamps in their NETINFO cells. These were not used for anything, and they provided one small way for clients to be distinguished from each other as they moved from network to network or behind NAT. Implements part of proposal 222. - Clients now round timestamps in INTRODUCE cells down to the nearest 10 minutes. If a new Support022HiddenServices option is set to 0, or if it's set to "auto" and the feature is disabled in the consensus, the timestamp is sent as 0 instead. Implements part of proposal 222. - Stop sending timestamps in AUTHENTICATE cells. This is not such a big deal from a security point of view, but it achieves no actual good purpose, and isn't needed. Implements part of proposal 222. - Reduce down accuracy of timestamps in hidden service descriptors. Implements part of proposal 222. o Minor features (bridges): - Make bridge relays check once a minute for whether their IP address has changed, rather than only every 15 minutes. Resolves bugs 1913 and 1992. - Bridge statistics now count bridge clients connecting over IPv6: bridge statistics files now list "bridge-ip-versions" and extra-info documents list "geoip6-db-digest". The control protocol "CLIENTS_SEEN" and "ip-to-country" queries now support IPv6. Initial implementation by "shkoo", addressing ticket 5055. - Add a new torrc option "ServerTransportListenAddr" to let bridge operators select the address where their pluggable transports will listen for connections. Resolves ticket 7013. - Randomize the lifetime of our SSL link certificate, so censors can't use the static value for filtering Tor flows. Resolves ticket 8443; related to ticket 4014 which was included in 0.2.2.33. o Minor features (relays): - Option OutboundBindAddress can be specified multiple times and accepts IPv6 addresses. Resolves ticket 6876. o Minor features (IPv6, client side): - AutomapHostsOnResolve now supports IPv6 addresses. By default, we prefer to hand out virtual IPv6 addresses, since there are more of them and we can't run out. To override this behavior and make IPv4 addresses preferred, set NoPreferIPv6Automap on whatever SOCKSPort or DNSPort you're using for resolving. Implements ticket 7571. - AutomapHostsOnResolve responses are now randomized, to avoid annoying situations where Tor is restarted and applications connect to the wrong addresses. - Never try more than 1000 times to pick a new virtual address when AutomapHostsOnResolve is set. That's good enough so long as we aren't close to handing out our entire virtual address space; if you're getting there, it's best to switch to IPv6 virtual addresses anyway. o Minor features (IPv6, relay/authority side): - New config option "AuthDirHasIPv6Connectivity 1" that directory authorities should set if they have IPv6 connectivity and want to do reachability tests for IPv6 relays. Implements feature 5974. - A relay with an IPv6 OR port now sends that address in NETINFO cells (in addition to its other address). Implements ticket 6364. o Minor features (directory authorities): - Directory authorities no long accept descriptors for any version of Tor before 0.2.2.35, or for any 0.2.3 release before 0.2.3.10-alpha. These versions are insecure, unsupported, or both. Implements ticket 6789. - When directory authorities are computing thresholds for flags, never let the threshold for the Fast flag fall below 4096 bytes. Also, do not consider nodes with extremely low bandwidths when deciding thresholds for various directory flags. This change should raise our threshold for Fast relays, possibly in turn improving overall network performance; see ticket 1854. Resolves ticket 8145. - Directory authorities now include inside each vote a statement of the performance thresholds they used when assigning flags. Implements ticket 8151. - Add an "ignoring-advertised-bws" boolean to the flag-threshold lines in directory authority votes to describe whether they have enough measured bandwidths to ignore advertised (relay descriptor) bandwidth claims. Resolves ticket 8711. o Minor features (path bias detection): - Path Use Bias: Perform separate accounting for successful circuit use. Keep separate statistics on stream attempt rates versus stream success rates for each guard. Provide configurable thresholds to determine when to emit log messages or disable use of guards that fail too many stream attempts. Resolves ticket 7802. - Create three levels of Path Bias log messages, as opposed to just two. These are configurable via consensus as well as via the torrc options PathBiasNoticeRate, PathBiasWarnRate, PathBiasExtremeRate. The default values are 0.70, 0.50, and 0.30 respectively. - Separate the log message levels from the decision to drop guards, which also is available via torrc option PathBiasDropGuards. PathBiasDropGuards still defaults to 0 (off). - Deprecate PathBiasDisableRate in favor of PathBiasDropGuards in combination with PathBiasExtremeRate. - Increase the default values for PathBiasScaleThreshold and PathBiasCircThreshold from (200, 20) to (300, 150). - Add in circuit usage accounting to path bias. If we try to use a built circuit but fail for any reason, it counts as path bias. Certain classes of circuits where the adversary gets to pick your destination node are exempt from this accounting. Usage accounting can be specifically disabled via consensus parameter or torrc. - Convert all internal path bias state to double-precision floating point, to avoid roundoff error and other issues. - Only record path bias information for circuits that have completed *two* hops. Assuming end-to-end tagging is the attack vector, this makes us more resilient to ambient circuit failure without any detection capability loss. o Minor features (build): - Tor now builds correctly on Bitrig, an OpenBSD fork. Patch from dhill. Resolves ticket 6982. - Compile on win64 using mingw64. Fixes bug 7260; patches from "yayooo". - Work correctly on Unix systems where EAGAIN and EWOULDBLOCK are separate error codes; or at least, don't break for that reason. Fixes bug 7935. Reported by "oftc_must_be_destroyed". o Build improvements (autotools): - Warn if building on a platform with an unsigned time_t: there are too many places where Tor currently assumes that time_t can hold negative values. We'd like to fix them all, but probably some will remain. - Do not report status verbosely from autogen.sh unless the -v flag is specified. Fixes issue 4664. Patch from Onizuka. - Detect and reject attempts to build Tor with threading support when OpenSSL has been compiled without threading support. Fixes bug 6673. - Try to detect if we are ever building on a platform where memset(...,0,...) does not set the value of a double to 0.0. Such platforms are permitted by the C standard, though in practice they're pretty rare (since IEEE 754 is nigh-ubiquitous). We don't currently support them, but it's better to detect them and fail than to perform erroneously. - We no longer warn so much when generating manpages from their asciidoc source. - Use Ville Laurikari's implementation of AX_CHECK_SIGN() to determine the signs of types during autoconf. This is better than our old approach, which didn't work when cross-compiling. o Minor features (log messages, warnings): - Detect when we're running with a version of OpenSSL other than the one we compiled with. This conflict has occasionally given people hard-to-track-down errors. - Warn users who run hidden services on a Tor client with UseEntryGuards disabled that their hidden services will be vulnerable to http://freehaven.net/anonbib/#hs-attack06 (the attack which motivated Tor to support entry guards in the first place). Resolves ticket 6889. - Warn when we are binding low ports when hibernation is enabled; previously we had warned when we were _advertising_ low ports with hibernation enabled. Fixes bug 7285; bugfix on 0.2.3.9-alpha. - Issue a warning when running with the bufferevents backend enabled. It's still not stable, and people should know that they're likely to hit unexpected problems. Closes ticket 9147. o Minor features (log messages, notices): - Refactor resolve_my_address() so it returns the method by which we decided our public IP address (explicitly configured, resolved from explicit hostname, guessed from interfaces, learned by gethostname). Now we can provide more helpful log messages when a relay guesses its IP address incorrectly (e.g. due to unexpected lines in /etc/hosts). Resolves ticket 2267. - Track how many "TAP" and "NTor" circuit handshake requests we get, and how many we complete, and log it every hour to help relay operators follow trends in network load. Addresses ticket 9658. o Minor features (log messages, diagnostics): - If we fail to free a microdescriptor because of bug 7164, log the filename and line number from which we tried to free it. - We compute the overhead from passing onionskins back and forth to cpuworkers, and report it when dumping statistics in response to SIGUSR1. Supports ticket 7291. - Add another diagnostic to the heartbeat message: track and log overhead that TLS is adding to the data we write. If this is high, we are sending too little data to SSL_write at a time. Diagnostic for bug 7707. - Log packaged cell fullness as part of the heartbeat message. Diagnosis to try to determine the extent of bug 7743. - Add more detail to a log message about relaxed timeouts, to help track bug 7799. - When learning a fingerprint for a bridge, log its corresponding transport type. Implements ticket 7896. - Warn more aggressively when flushing microdescriptors to a microdescriptor cache fails, in an attempt to mitigate bug 8031, or at least make it more diagnosable. - Improve the log message when "Bug/attack: unexpected sendme cell from client" occurs, to help us track bug 8093. - Improve debugging output to help track down bug 8185 ("Bug: outgoing relay cell has n_chan==NULL. Dropping.") o Minor features (log messages, quieter bootstrapping): - Log fewer lines at level "notice" about our OpenSSL and Libevent versions and capabilities when everything is going right. Resolves part of ticket 6736. - Omit the first heartbeat log message, because it never has anything useful to say, and it clutters up the bootstrapping messages. Resolves ticket 6758. - Don't log about reloading the microdescriptor cache at startup. Our bootstrap warnings are supposed to tell the user when there's a problem, and our bootstrap notices say when there isn't. Resolves ticket 6759; bugfix on 0.2.2.6-alpha. - Don't log "I learned some more directory information" when we're reading cached directory information. Reserve it for when new directory information arrives in response to a fetch. Resolves ticket 6760. - Don't complain about bootstrapping problems while hibernating. These complaints reflect a general code problem, but not one with any problematic effects (no connections are actually opened). Fixes part of bug 7302; bugfix on 0.2.3.2-alpha. o Minor features (testing): - In our testsuite, create temporary directories with a bit more entropy in their name to make name collisions less likely. Fixes bug 8638. - Add benchmarks for DH (1024-bit multiplicative group) and ECDH (P-256) Diffie-Hellman handshakes to src/or/bench. - Add benchmark functions to test onion handshake performance. o Renamed options: - The DirServer option is now DirAuthority, for consistency with current naming patterns. You can still use the old DirServer form. o Minor bugfixes (protocol): - Fix the handling of a TRUNCATE cell when it arrives while the circuit extension is in progress. Fixes bug 7947; bugfix on 0.0.7.1. - When a Tor client gets a "truncated" relay cell, the first byte of its payload specifies why the circuit was truncated. We were ignoring this 'reason' byte when tearing down the circuit, resulting in the controller not being told why the circuit closed. Now we pass the reason from the truncated cell to the controller. Bugfix on 0.1.2.3-alpha; fixes bug 7039. - Fix a misframing issue when reading the version numbers in a VERSIONS cell. Previously we would recognize [00 01 00 02] as 'version 1, version 2, and version 0x100', when it should have only included versions 1 and 2. Fixes bug 8059; bugfix on 0.2.0.10-alpha. Reported pseudonymously. - Make the format and order of STREAM events for DNS lookups consistent among the various ways to launch DNS lookups. Fixes bug 8203; bugfix on 0.2.0.24-rc. Patch by "Desoxy". o Minor bugfixes (syscalls and disk interaction): - Always check the return values of functions fcntl() and setsockopt(). We don't believe these are ever actually failing in practice, but better safe than sorry. Also, checking these return values should please analysis tools like Coverity. Patch from 'flupzor'. Fixes bug 8206; bugfix on all versions of Tor. - Avoid double-closing the listener socket in our socketpair() replacement (used on Windows) in the case where the addresses on our opened sockets don't match what we expected. Fixes bug 9400; bugfix on 0.0.2pre7. Found by Coverity. - Correctly store microdescriptors and extrainfo descriptors that include an internal NUL byte. Fixes bug 8037; bugfix on 0.2.0.1-alpha. Bug reported by "cypherpunks". - If for some reason we fail to write a microdescriptor while rebuilding the cache, do not let the annotations from that microdescriptor linger in the cache file, and do not let the microdescriptor stay recorded as present in its old location. Fixes bug 9047; bugfix on 0.2.2.6-alpha. - Use direct writes rather than stdio when building microdescriptor caches, in an attempt to mitigate bug 8031, or at least make it less common. o Minor fixes (config options): - Warn and fail if a server is configured not to advertise any ORPorts at all. (We need *something* to put in our descriptor, or we just won't work.) - Behave correctly when the user disables LearnCircuitBuildTimeout but doesn't tell us what they would like the timeout to be. Fixes bug 6304; bugfix on 0.2.2.14-alpha. - Rename the (internal-use-only) UsingTestingNetworkDefaults option to start with a triple-underscore so the controller won't touch it. Patch by Meejah. Fixes bug 3155. Bugfix on 0.2.2.23-alpha. - Rename the (testing-use-only) _UseFilteringSSLBufferevents option so it doesn't start with _. Fixes bug 3155. Bugfix on 0.2.3.1-alpha. - When autodetecting the number of CPUs, use the number of available CPUs in preference to the number of configured CPUs. Inform the user if this reduces the number of available CPUs. Fixes bug 8002; bugfix on 0.2.3.1-alpha. - Command-line option "--version" implies "--quiet". Fixes bug 6997. - Make it an error when you set EntryNodes but disable UseGuardNodes, since it will (surprisingly to some users) ignore EntryNodes. Fixes bug 8180; bugfix on 0.2.3.11-alpha. - Avoid overflows when the user sets MaxCircuitDirtiness to a ridiculously high value, by imposing a (ridiculously high) 30-day maximum on MaxCircuitDirtiness. o Minor bugfixes (control protocol): - Stop sending a stray "(null)" in some cases for the server status "EXTERNAL_ADDRESS" controller event. Resolves bug 8200; bugfix on 0.1.2.6-alpha. - The ADDRMAP command can no longer generate an ill-formed error code on a failed MAPADDRESS. It now says "internal" rather than an English sentence fragment with spaces in the middle. Bugfix on Tor 0.2.0.19-alpha. o Minor bugfixes (clients / edges): - When we receive a RELAY_END cell with the reason DONE, or with no reason, before receiving a RELAY_CONNECTED cell, report the SOCKS status as "connection refused". Previously we reported these cases as success but then immediately closed the connection. Fixes bug 7902; bugfix on 0.1.0.1-rc. Reported by "oftc_must_be_destroyed". - If the guard we choose first doesn't answer, we would try the second guard, but once we connected to the second guard we would abandon it and retry the first one, slowing down bootstrapping. The fix is to treat all our initially chosen guards as acceptable to use. Fixes bug 9946; bugfix on 0.1.1.11-alpha. - When choosing which stream on a formerly stalled circuit to wake first, make better use of the platform's weak RNG. Previously, we had been using the % ("modulo") operator to try to generate a 1/N chance of picking each stream, but this behaves badly with many platforms' choice of weak RNG. Fixes bug 7801; bugfix on 0.2.2.20-alpha. o Minor bugfixes (path bias detection): - If the state file's path bias counts are invalid (presumably from a buggy Tor prior to 0.2.4.10-alpha), make them correct. Also add additional checks and log messages to the scaling of Path Bias counts, in case there still are remaining issues with scaling. Should help resolve bug 8235. - Prevent rounding error in path bias counts when scaling them down, and use the correct scale factor default. Also demote some path bias related log messages down a level and make others less scary sounding. Fixes bug 6647. Bugfix on 0.2.3.17-beta. - Remove a source of rounding error during path bias count scaling; don't count cannibalized circuits as used for path bias until we actually try to use them; and fix a circuit_package_relay_cell() warning message about n_chan==NULL. Fixes bug 7802. - Paste the description for PathBias parameters from the man page into or.h, so the code documents them too. Fixes bug 7982; bugfix on 0.2.3.17-beta. o Minor bugfixes (relays): - Stop trying to resolve our hostname so often (e.g. every time we think about doing a directory fetch). Now we reuse the cached answer in some cases. Fixes bugs 1992 (bugfix on 0.2.0.20-rc) and 2410 (bugfix on 0.1.2.2-alpha). - When examining the list of network interfaces to find our address, do not consider non-running or disabled network interfaces. Fixes bug 9904; bugfix on 0.2.3.11-alpha. Patch from "hantwister". o Minor bugfixes (blocking resistance): - Only disable TLS session ticket support when running as a TLS server. Now clients will blend better with regular Firefox connections. Fixes bug 7189; bugfix on Tor 0.2.3.23-rc. o Minor bugfixes (IPv6): - Use square brackets around IPv6 addresses in numerous places that needed them, including log messages, HTTPS CONNECT proxy requests, TransportProxy statefile entries, and pluggable transport extra-info lines. Fixes bug 7011; patch by David Fifield. o Minor bugfixes (directory authorities): - Reject consensus votes with more than 64 known-flags. We aren't even close to that limit yet, and our code doesn't handle it correctly. Fixes bug 6833; bugfix on 0.2.0.1-alpha. - Correctly handle votes with more than 31 flags. Fixes bug 6853; bugfix on 0.2.0.3-alpha. o Minor bugfixes (memory leaks): - Avoid leaking memory if we fail to compute a consensus signature or we generate a consensus we can't parse. Bugfix on 0.2.0.5-alpha. - Fix a memory leak when receiving headers from an HTTPS proxy. Bugfix on 0.2.1.1-alpha; fixes bug 7816. - Fix a memory leak during safe-cookie controller authentication. Bugfix on 0.2.3.13-alpha; fixes bug 7816. - Free some more still-in-use memory at exit, to make hunting for memory leaks easier. Resolves bug 7029. o Minor bugfixes (code correctness): - Increase the width of the field used to remember a connection's link protocol version to two bytes. Harmless for now, since the only currently recognized versions are one byte long. Reported pseudonymously. Fixes bug 8062; bugfix on 0.2.0.10-alpha. - Fix a crash when debugging unit tests on Windows: deallocate a shared library with FreeLibrary, not CloseHandle. Fixes bug 7306; bugfix on 0.2.2.17-alpha. Reported by "ultramage". - When detecting the largest possible file descriptor (in order to close all file descriptors when launching a new program), actually use _SC_OPEN_MAX. The old code for doing this was very, very broken. Fixes bug 8209; bugfix on 0.2.3.1-alpha. Found by Coverity; this is CID 743383. - Avoid a crash if we fail to generate an extrainfo descriptor. Fixes bug 8208; bugfix on 0.2.3.16-alpha. Found by Coverity; this is CID 718634. - Avoid an off-by-one error when checking buffer boundaries when formatting the exit status of a pluggable transport helper. This is probably not an exploitable bug, but better safe than sorry. Fixes bug 9928; bugfix on 0.2.3.18-rc. Bug found by Pedro Ribeiro. - Get rid of a couple of harmless clang warnings, where we compared enums to ints. These warnings are newly introduced in clang 3.2. o Minor bugfixes (code cleanliness): - Avoid use of reserved identifiers in our C code. The C standard doesn't like us declaring anything that starts with an underscore, so let's knock it off before we get in trouble. Fix for bug 1031; bugfix on the first Tor commit. - Fix round_to_power_of_2() so it doesn't invoke undefined behavior with large values. This situation was untriggered, but nevertheless incorrect. Fixes bug 6831; bugfix on 0.2.0.1-alpha. - Fix an impossible buffer overrun in the AES unit tests. Fixes bug 8845; bugfix on 0.2.0.7-alpha. Found by eugenis. - Fix handling of rendezvous client authorization types over 8. Fixes bug 6861; bugfix on 0.2.1.5-alpha. - Remove a couple of extraneous semicolons that were upsetting the cparser library. Patch by Christian Grothoff. Fixes bug 7115; bugfix on 0.2.2.1-alpha. - When complaining about a client port on a public address, log which address we're complaining about. Fixes bug 4020; bugfix on 0.2.3.3-alpha. Patch by Tom Fitzhenry. o Minor bugfixes (log messages, warnings): - If we encounter a write failure on a SOCKS connection before we finish our SOCKS handshake, don't warn that we closed the connection before we could send a SOCKS reply. Fixes bug 8427; bugfix on 0.1.0.1-rc. - Fix a directory authority warn caused when we have a large amount of badexit bandwidth. Fixes bug 8419; bugfix on 0.2.2.10-alpha. - Downgrade "Failed to hand off onionskin" messages to "debug" severity, since they're typically redundant with the "Your computer is too slow" messages. Fixes bug 7038; bugfix on 0.2.2.16-alpha. - Avoid spurious warnings when configuring multiple client ports of which only some are nonlocal. Previously, we had claimed that some were nonlocal when in fact they weren't. Fixes bug 7836; bugfix on 0.2.3.3-alpha. o Minor bugfixes (log messages, other): - Fix log messages and comments to avoid saying "GMT" when we mean "UTC". Fixes bug 6113. - When rejecting a configuration because we were unable to parse a quoted string, log an actual error message. Fixes bug 7950; bugfix on 0.2.0.16-alpha. - Correctly recognize that [::1] is a loopback address. Fixes bug 8377; bugfix on 0.2.1.3-alpha. - Don't log inappropriate heartbeat messages when hibernating: a hibernating node is _expected_ to drop out of the consensus, decide it isn't bootstrapped, and so forth. Fixes bug 7302; bugfix on 0.2.3.1-alpha. - Eliminate several instances where we use "Nickname=ID" to refer to nodes in logs. Use "Nickname (ID)" instead. (Elsewhere, we still use "$ID=Nickname", which is also acceptable.) Fixes bug 7065. Bugfix on 0.2.3.21-rc. o Minor bugfixes (build): - Fix some bugs in tor-fw-helper-natpmp when trying to build and run it on Windows. More bugs likely remain. Patch from Gisle Vanem. Fixes bug 7280; bugfix on 0.2.3.1-alpha. o Documentation fixes: - Make the torify manpage no longer refer to tsocks; torify hasn't supported tsocks since 0.2.3.14-alpha. - Make the tor manpage no longer reference tsocks. - Fix the GeoIPExcludeUnknown documentation to refer to ExcludeExitNodes rather than the currently nonexistent ExcludeEntryNodes. Spotted by "hamahangi" on tor-talk. - Resolve a typo in torrc.sample.in. Fixes bug 6819; bugfix on 0.2.3.14-alpha. - Say "KBytes" rather than "KB" in the man page (for various values of K), to further reduce confusion about whether Tor counts in units of memory or fractions of units of memory. Resolves ticket 7054. - Update tor-fw-helper.1.txt and tor-fw-helper.c to make option names match. Fixes bug 7768. - Fix the documentation of HeartbeatPeriod to say that the heartbeat message is logged at notice, not at info. - Clarify the usage and risks of setting the ContactInfo torrc line for your relay or bridge. Resolves ticket 9854. - Add anchors to the manpage so we can link to the html version of the documentation for specific options. Resolves ticket 9866. - Replace remaining references to DirServer in man page and log entries. Resolves ticket 10124. o Removed features: - Stop exporting estimates of v2 and v3 directory traffic shares in extrainfo documents. They were unneeded and sometimes inaccurate. Also stop exporting any v2 directory request statistics. Resolves ticket 5823. - Drop support for detecting and warning about versions of Libevent before 1.3e. Nothing reasonable ships with them any longer; warning the user about them shouldn't be needed. Resolves ticket 6826. - Now that all versions before 0.2.2.x are disallowed, we no longer need to work around their missing features. Remove a bunch of compatibility code. o Removed files: - The tor-tsocks.conf is no longer distributed or installed. We recommend that tsocks users use torsocks instead. Resolves ticket 8290. - Remove some of the older contents of doc/ as obsolete; move others to torspec.git. Fixes bug 8965. o Code simplification: - Avoid using character buffers when constructing most directory objects: this approach was unwieldy and error-prone. Instead, build smartlists of strings, and concatenate them when done. - Rename "isin" functions to "contains", for grammar. Resolves ticket 5285. - Rename Tor's logging function log() to tor_log(), to avoid conflicts with the natural logarithm function from the system libm. Resolves ticket 7599. - Start using OpenBSD's implementation of queue.h, so that we don't need to hand-roll our own pointer and list structures whenever we need them. (We can't rely on a sys/queue.h, since some operating systems don't have them, and the ones that do have them don't all present the same extensions.) - Start using OpenBSD's implementation of queue.h (originally by Niels Provos). - Enhance our internal sscanf replacement so that we can eliminate the last remaining uses of the system sscanf. (Though those uses of sscanf were safe, sscanf itself is generally error prone, so we want to eliminate when we can.) Fixes ticket 4195 and Coverity CID 448. - Replace all calls to snprintf() outside of src/ext with tor_snprintf(). Also remove the #define to replace snprintf with _snprintf on Windows; they have different semantics, and all of our callers should be using tor_snprintf() anyway. Fixes bug 7304. o Refactoring: - Add a wrapper function for the common "log a message with a rate-limit" case. - Split the onion.c file into separate modules for the onion queue and the different handshakes it supports. - Move the client-side address-map/virtual-address/DNS-cache code out of connection_edge.c into a new addressmap.c module. - Move the entry node code from circuitbuild.c to its own file. - Move the circuit build timeout tracking code from circuitbuild.c to its own file. - Source files taken from other packages now reside in src/ext; previously they were scattered around the rest of Tor. - Move the generic "config" code into a new file, and have "config.c" hold only torrc- and state-related code. Resolves ticket 6823. - Move the core of our "choose a weighted element at random" logic into its own function, and give it unit tests. Now the logic is testable, and a little less fragile too. - Move ipv6_preferred from routerinfo_t to node_t. Addresses bug 4620. - Move last_reachable and testing_since from routerinfo_t to node_t. Implements ticket 5529. - Add replaycache_t structure, functions and unit tests, then refactor rend_service_introduce() to be more clear to read, improve, debug, and test. Resolves bug 6177. o Removed code: - Remove some now-needless code that tried to aggressively flush OR connections as data was added to them. Since 0.2.0.1-alpha, our cell queue logic has saved us from the failure mode that this code was supposed to prevent. Removing this code will limit the number of baroque control flow paths through Tor's network logic. Reported pseudonymously on IRC. Fixes bug 6468; bugfix on 0.2.0.1-alpha. - Remove unused code for parsing v1 directories and "running routers" documents. Fixes bug 6887. - Remove the marshalling/unmarshalling code for sending requests to cpuworkers over a socket, and instead just send structs. The recipient will always be the same Tor binary as the sender, so any encoding is overkill. - Remove the testing_since field of node_t, which hasn't been used for anything since 0.2.0.9-alpha. - Finally remove support for malloc_good_size and malloc_usable_size. We had hoped that these functions would let us eke a little more memory out of our malloc implementation. Unfortunately, the only implementations that provided these functions are also ones that are already efficient about not overallocation: they never got us more than 7 or so bytes per allocation. Removing them saves us a little code complexity and a nontrivial amount of build complexity. Changes in version 0.2.3.25 - 2012-11-19 The Tor 0.2.3 release series is dedicated to the memory of Len "rabbi" Sassaman (1980-2011), a long-time cypherpunk, anonymity researcher, Mixmaster maintainer, Pynchon Gate co-designer, CodeCon organizer, programmer, and friend. Unstinting in his dedication to the cause of freedom, he inspired and helped many of us as we began our work on anonymity, and inspires us still. Please honor his memory by writing software to protect people's freedoms, and by helping others to do so. Tor 0.2.3.25, the first stable release in the 0.2.3 branch, features significantly reduced directory overhead (via microdescriptors), enormous crypto performance improvements for fast relays on new enough hardware, a new v3 TLS handshake protocol that can better resist fingerprinting, support for protocol obfuscation plugins (aka pluggable transports), better scalability for hidden services, IPv6 support for bridges, performance improvements like allowing clients to skip the first round-trip on the circuit ("optimistic data") and refilling token buckets more often, a new "stream isolation" design to isolate different applications on different circuits, and many stability, security, and privacy fixes. Major features (v3 directory protocol): - Clients now use microdescriptors instead of regular descriptors to build circuits. Microdescriptors are authority-generated summaries of regular descriptors' contents, designed to change very rarely (see proposal 158 for details). This feature is designed to save bandwidth, especially for clients on slow internet connections. Use "UseMicrodescriptors 0" to disable it. - Caches now download, cache, and serve microdescriptors, as well as multiple "flavors" of the consensus, including a flavor that describes microdescriptors. o Major features (build hardening): - Enable gcc and ld hardening by default. Resolves ticket 5210. o Major features (relay scaling): - When built to use OpenSSL 1.0.1, and built for an x86 or x86_64 instruction set, take advantage of OpenSSL's AESNI, bitsliced, or vectorized AES implementations as appropriate. These can be much, much faster than other AES implementations. - When using OpenSSL 1.0.0 or later, use OpenSSL's counter mode implementation. It makes AES_CTR about 7% faster than our old one (which was about 10% faster than the one OpenSSL used to provide). Resolves ticket 4526. - Use OpenSSL's EVP interface for AES encryption, so that all AES operations can use hardware acceleration (if present). Resolves ticket 4442. - Unconditionally use OpenSSL's AES implementation instead of our old built-in one. OpenSSL's AES has been better for a while, and relatively few servers should still be on any version of OpenSSL that doesn't have good optimized assembly AES. o Major features (blocking resistance): - Update TLS cipher list to match Firefox 8 and later. Resolves ticket 4744. - Remove support for clients falsely claiming to support standard ciphersuites that they can actually provide. As of modern OpenSSL versions, it's not necessary to fake any standard ciphersuite, and doing so prevents us from using better ciphersuites in the future, since servers can't know whether an advertised ciphersuite is really supported or not. Some hosts -- notably, ones with very old versions of OpenSSL or where OpenSSL has been built with ECC disabled -- will stand out because of this change; TBB users should not be affected. Implements the client side of proposal 198. - Implement a new handshake protocol (v3) for authenticating Tors to each other over TLS. It should be more resistant to fingerprinting than previous protocols, and should require less TLS hacking for future Tor implementations. Implements proposal 176. - Allow variable-length padding cells, to disguise the length of Tor's TLS records. Implements part of proposal 184. - While we're trying to bootstrap, record how many TLS connections fail in each state, and report which states saw the most failures in response to any bootstrap failures. This feature may speed up diagnosis of censorship events. Implements ticket 3116. o Major features (pluggable transports): - Clients and bridges can now be configured to use a separate "transport" proxy. This approach makes the censorship arms race easier by allowing bridges to use protocol obfuscation plugins. Implements proposal 180 (tickets 2841 and 3472). o Major features (DoS resistance): - Now that Tor 0.2.0.x is completely deprecated, enable the final part of "Proposal 110: Avoiding infinite length circuits" by refusing all circuit-extend requests that do not use a relay_early cell. This change helps Tor resist a class of denial-of-service attacks by limiting the maximum circuit length. - Tear down the circuit if we get an unexpected SENDME cell. Clients could use this trick to make their circuits receive cells faster than our flow control would have allowed, or to gum up the network, or possibly to do targeted memory denial-of-service attacks on entry nodes. Fixes bug 6252. Bugfix on the 54th commit on Tor -- from July 2002, before the release of Tor 0.0.0. o Major features (hidden services): - Adjust the number of introduction points that a hidden service will try to maintain based on how long its introduction points remain in use and how many introductions they handle. Fixes part of bug 3825. - Add a "tor2web mode" for clients that want to connect to hidden services non-anonymously (and possibly more quickly). As a safety measure to try to keep users from turning this on without knowing what they are doing, tor2web mode must be explicitly enabled at compile time, and a copy of Tor compiled to run in tor2web mode cannot be used as a normal Tor client. Implements feature 2553. o Major features (IPv6): - Clients can now connect to private bridges over IPv6. Bridges still need at least one IPv4 address in order to connect to other relays. Note that we don't yet handle the case where the user has two bridge lines for the same bridge (one IPv4, one IPv6). Implements parts of proposal 186. o Major features (directory authorities): - Use a more secure consensus parameter voting algorithm. Now at least three directory authorities or a majority of them must vote on a given parameter before it will be included in the consensus. Implements proposal 178. - Remove the artificially low cutoff of 20KB to guarantee the Fast flag. In the past few years the average relay speed has picked up, and while the "top 7/8 of the network get the Fast flag" and "all relays with 20KB or more of capacity get the Fast flag" rules used to have the same result, now the top 7/8 of the network has a capacity more like 32KB. Bugfix on 0.2.1.14-rc. Fixes bug 4489. o Major features (performance): - Exit nodes now accept and queue data on not-yet-connected streams. Previously, the client wasn't allowed to send data until the stream was connected, which slowed down all connections. This change will enable clients to perform a "fast-start" on streams and send data without having to wait for a confirmation that the stream has opened. Patch from Ian Goldberg; implements the server side of Proposal 174. - When using an exit relay running 0.2.3.x, clients can now "optimistically" send data before the exit relay reports that the stream has opened. This saves a round trip when starting connections where the client speaks first (such as web browsing). This behavior is controlled by a consensus parameter (currently disabled). To turn it on or off manually, use the "OptimisticData" torrc option. Implements proposal 181; code by Ian Goldberg. - Add a new TokenBucketRefillInterval option to refill token buckets more frequently than once per second. This should improve network performance, alleviate queueing problems, and make traffic less bursty. Implements proposal 183; closes ticket 3630. Design by Florian Tschorsch and Björn Scheuermann; implementation by Florian Tschorsch. - Raise the threshold of server descriptors needed (75%) and exit server descriptors needed (50%) before we will declare ourselves bootstrapped. This will make clients start building circuits a little later, but makes the initially constructed circuits less skewed and less in conflict with further directory fetches. Fixes ticket 3196. o Major features (relays): - Relays now try regenerating and uploading their descriptor more frequently if they are not listed in the consensus, or if the version of their descriptor listed in the consensus is too old. This fix should prevent situations where a server declines to re-publish itself because it has done so too recently, even though the authorities decided not to list its recent-enough descriptor. Fix for bug 3327. o Major features (stream isolation): - You can now configure Tor so that streams from different applications are isolated on different circuits, to prevent an attacker who sees your streams as they leave an exit node from linking your sessions to one another. To do this, choose some way to distinguish the applications: have them connect to different SocksPorts, or have one of them use SOCKS4 while the other uses SOCKS5, or have them pass different authentication strings to the SOCKS proxy. Then, use the new SocksPort syntax to configure the degree of isolation you need. This implements Proposal 171. - There's a new syntax for specifying multiple client ports (such as SOCKSPort, TransPort, DNSPort, NATDPort): you can now just declare multiple *Port entries with full addr:port syntax on each. The old *ListenAddress format is still supported, but you can't mix it with the new *Port syntax. o Major features (bufferevents): - Tor can now optionally build with the "bufferevents" buffered IO backend provided by Libevent 2. To use this feature, make sure you have the latest possible version of Libevent, and pass the --enable-bufferevents flag to configure when building Tor from source. This feature will make our networking code more flexible, let us stack layers on each other, and let us use more efficient zero-copy transports where available. - Add experimental support for running on Windows with IOCP and no kernel-space socket buffers. This feature is controlled by a new "UserspaceIOCPBuffers" config option (off by default), which has no effect unless Tor has been built with bufferevents enabled, you're running on Windows, and you've set "DisableIOCP 0". In the long run, this may help solve or mitigate bug 98. o Major features (path selection): - The EntryNodes option can now include country codes like {de} or IP addresses or network masks. Previously we had disallowed these options because we didn't have an efficient way to keep the list up to date. Addresses ticket 1982, but see bug 2798 for an unresolved issue here. o Major features (port forwarding): - Add support for automatic port mapping on the many home routers that support NAT-PMP or UPnP. To build the support code, you'll need to have the libnatpnp library and/or the libminiupnpc library, and you'll need to enable the feature specifically by passing "--enable-upnp" and/or "--enable-natpnp" to ./configure. To turn it on, use the new PortForwarding option. o Major features (logging): - Add a new 'Heartbeat' log message type to periodically log a message describing Tor's status at level Notice. This feature is meant for operators who log at notice, and want to make sure that their Tor server is still working. Implementation by George Kadianakis. - Make logging resolution configurable with a new LogTimeGranularity option, and change the default from 1 millisecond to 1 second. Implements enhancement 1668. o Major features (other): - New "DisableNetwork" config option to prevent Tor from launching any connections or accepting any connections except on a control port. Bundles and controllers can set this option before letting Tor talk to the rest of the network, for example to prevent any connections to a non-bridge address. Packages like Orbot can also use this option to instruct Tor to save power when the network is off. - Try to use system facilities for enumerating local interface addresses, before falling back to our old approach (which was binding a UDP socket, and calling getsockname() on it). That approach was scaring OS X users whose draconian firewall software warned about binding to UDP sockets regardless of whether packets were sent. Now we try to use getifaddrs(), SIOCGIFCONF, or GetAdaptersAddresses(), depending on what the system supports. Resolves ticket 1827. - Add experimental support for a "defaults" torrc file to be parsed before the regular torrc. Torrc options override the defaults file's options in the same way that the command line overrides the torrc. The SAVECONF controller command saves only those options which differ between the current configuration and the defaults file. HUP reloads both files. Implements task 4552. o New directory authorities: - Add Faravahar (run by Sina Rabbani) as the ninth v3 directory authority. Closes ticket 5749. o Security/privacy fixes: - Avoid read-from-freed-memory and double-free bugs that could occur when a DNS request fails while launching it. Fixes bug 6480; bugfix on 0.2.0.1-alpha. - Reject any attempt to extend to an internal address. Without this fix, a router could be used to probe addresses on an internal network to see whether they were accepting connections. Fixes bug 6710; bugfix on 0.0.8pre1. - Close any connection that sends unrecognized junk before the TLS handshake. Solves an issue noted in bug 4369. - The advertised platform of a relay now includes only its operating system's name (e.g., "Linux", "Darwin", "Windows 7"), and not its service pack level (for Windows) or its CPU architecture (for Unix). Also drop the "git-XYZ" tag in the version. Packagers can insert an extra string in the platform line by setting the preprocessor variable TOR_BUILD_TAG. Resolves bug 2988. - Disable TLS session tickets. OpenSSL's implementation was giving our TLS session keys the lifetime of our TLS context objects, when perfect forward secrecy would want us to discard anything that could decrypt a link connection as soon as the link connection was closed. Fixes bug 7139; bugfix on all versions of Tor linked against OpenSSL 1.0.0 or later. Found by Florent Daignière. - Tor tries to wipe potentially sensitive data after using it, so that if some subsequent security failure exposes Tor's memory, the damage will be limited. But we had a bug where the compiler was eliminating these wipe operations when it decided that the memory was no longer visible to a (correctly running) program, hence defeating our attempt at defense in depth. We fix that by using OpenSSL's OPENSSL_cleanse() operation, which a compiler is unlikely to optimize away. Future versions of Tor may use a less ridiculously heavy approach for this. Fixes bug 7352. Reported in an article by Andrey Karpov. o Major bugfixes (crashes and asserts): - Avoid a pair of double-free and use-after-mark bugs that can occur with certain timings in canceled and re-received DNS requests. Fixes bug 6472; bugfix on 0.0.7rc1. - Fix a denial of service attack by which any directory authority could crash all the others, or by which a single v2 directory authority could crash everybody downloading v2 directory information. Fixes bug 7191; bugfix on 0.2.0.10-alpha. - Fix an assert that directory authorities could trigger on sighup during some configuration state transitions. We now don't treat it as a fatal error when the new descriptor we just generated in init_keys() isn't accepted. Fixes bug 4438; bugfix on 0.2.1.9-alpha. - Avoid segfault when starting up having run with an extremely old version of Tor and parsing its state file. Fixes bug 6801; bugfix on 0.2.2.23-alpha. o Major bugfixes (clients): - If we are unable to find any exit that supports our predicted ports, stop calling them predicted, so that we don't loop and build hopeless circuits indefinitely. Fixes bug 3296; bugfix on 0.0.9pre6, which introduced predicted ports. - Check at each new consensus whether our entry guards were picked long enough ago that we should rotate them. Previously, we only did this check at startup, which could lead to us holding a guard indefinitely. Fixes bug 5380; bugfix on 0.2.1.14-rc. - When fetching a bridge descriptor from a bridge authority, always do so anonymously, whether we have been able to open circuits or not. Partial fix for bug 1938; bugfix on 0.2.0.7-alpha. This behavior makes it *safer* to use UpdateBridgesFromAuthority, but we'll need to wait for bug 6010 before it's actually usable. o Major bugfixes (directory voting): - Check more thoroughly to prevent a rogue authority from double-voting on any consensus directory parameter. Previously, authorities would crash in this case if the total number of votes for any parameter exceeded the number of active voters, but would let it pass otherwise. Partially fixes bug 5786; bugfix on 0.2.2.2-alpha. - When computing weight parameters, behave more robustly in the presence of a bad bwweightscale value. Previously, the authorities would crash if they agreed on a sufficiently broken weight_scale value; now, they use a reasonable default and carry on. Fixes the rest of bug 5786; bugfix on 0.2.2.17-alpha. - If authorities are unable to get a v2 consensus document from other directory authorities, they no longer fall back to fetching them from regular directory caches. Fixes bug 5635; bugfix on 0.2.2.26-beta, where routers stopped downloading v2 consensus documents entirely. o Major bugfixes (relays): - Fix a bug handling SENDME cells on nonexistent streams that could result in bizarre window values. Report and patch contributed pseudonymously. Fixes part of bug 6271. This bug was introduced before the first Tor release, in svn commit r152. - Don't update the AccountingSoftLimitHitAt state file entry whenever tor gets started. This prevents a wrong average bandwidth estimate, which would cause relays to always start a new accounting interval at the earliest possible moment. Fixes bug 2003; bugfix on 0.2.2.7-alpha. Reported by Bryon Eldridge, who also helped immensely in tracking this bug down. - Fix a possible crash bug when checking for deactivated circuits in connection_or_flush_from_first_active_circuit(). Fixes bug 6341; bugfix on 0.2.2.7-alpha. Bug report and fix received pseudonymously. - Set the SO_REUSEADDR socket option before we call bind() on outgoing connections. This change should allow busy exit relays to stop running out of available sockets as quickly. Fixes bug 4950; bugfix on 0.2.2.26-beta. o Major bugfixes (blocking resistance): - Bridges no longer include their address in NETINFO cells on outgoing OR connections, to allow them to blend in better with clients. Removes another avenue for enumerating bridges. Reported by "troll_un". Fixes bug 4348; bugfix on 0.2.0.10-alpha, when NETINFO cells were introduced. - Warn the user when HTTPProxy, but no other proxy type, is configured. This can cause surprising behavior: it doesn't send all of Tor's traffic over the HTTPProxy -- it sends unencrypted directory traffic only. Resolves ticket 4663. o Major bugfixes (hidden services): - Improve hidden service robustness: when an attempt to connect to a hidden service ends, be willing to refetch its hidden service descriptors from each of the HSDir relays responsible for them immediately. Previously, we would not consider refetching the service's descriptors from each HSDir for 15 minutes after the last fetch, which was inconvenient if the hidden service was not running during the first attempt. Bugfix on 0.2.0.18-alpha; fixes bug 3335. - Hidden services now ignore the timestamps on INTRODUCE2 cells. They used to check that the timestamp was within 30 minutes of their system clock, so they could cap the size of their replay-detection cache, but that approach unnecessarily refused service to clients with wrong clocks. Bugfix on 0.2.1.6-alpha, when the v3 intro-point protocol (the first one which sent a timestamp field in the INTRODUCE2 cell) was introduced; fixes bug 3460. - When one of a hidden service's introduction points appears to be unreachable, stop trying it. Previously, we would keep trying to build circuits to the introduction point until we lost the descriptor, usually because the user gave up and restarted Tor. Fixes part of bug 3825. o Changes to default torrc file: - Stop listing "socksport 9050" in torrc.sample. We open a socks port on 9050 by default anyway, so this should not change anything in practice. - Stop mentioning the deprecated *ListenAddress options in torrc.sample. Fixes bug 5438. - Document unit of bandwidth-related options in sample torrc. Fixes bug 5621. - Fix broken URLs in the sample torrc file, and tell readers about the OutboundBindAddress, ExitPolicyRejectPrivate, and PublishServerDescriptor options. Addresses bug 4652. o Minor features (directory authorities): - Consider new, removed or changed IPv6 OR ports a non-cosmetic change when the authority is deciding whether to accept a newly uploaded descriptor. Implements ticket 6423. - Directory authorities are now a little more lenient at accepting older router descriptors, or newer router descriptors that don't make big changes. This should help ameliorate past and future issues where routers think they have uploaded valid descriptors, but the authorities don't think so. Fix for ticket 2479. - Authority operators can now vote for all relays in a given set of countries to be BadDir/BadExit/Invalid/Rejected. - Provide two consensus parameters (FastFlagMinThreshold and FastFlagMaxThreshold) to control the range of allowable bandwidths for the Fast directory flag. These allow authorities to run experiments on appropriate requirements for being a "Fast" node. The AuthDirFastGuarantee config value still applies. Implements ticket 3946. o Minor features (bridges / bridge authorities): - Make bridge SSL certificates a bit more stealthy by using random serial numbers, in the same fashion as OpenSSL when generating self-signed certificates. Implements ticket 4584. - Tag a bridge's descriptor as "never to be sent unencrypted". This shouldn't matter, since bridges don't open non-anonymous connections to the bridge authority and don't allow unencrypted directory connections from clients, but we might as well make sure. Closes bug 5139. - The Bridge Authority now writes statistics on how many bridge descriptors it gave out in total, and how many unique descriptors it gave out. It also lists how often the most and least commonly fetched descriptors were given out, as well as the median and 25th/75th percentile. Implements tickets 4200 and 4294. o Minor features (IPv6): - Make the code that clients use to detect an address change be IPv6-aware, so that it won't fill clients' logs with error messages when trying to get the IPv4 address of an IPv6 connection. Implements ticket 5537. - Relays now understand an IPv6 address when they get one from a directory server. Resolves ticket 4875. o Minor features (hidden services): - Expire old or over-used hidden service introduction points. Required by fix for bug 3460. - Reduce the lifetime of elements of hidden services' Diffie-Hellman public key replay-detection cache from 60 minutes to 5 minutes. This replay-detection cache is now used only to detect multiple INTRODUCE2 cells specifying the same rendezvous point, so we can avoid launching multiple simultaneous attempts to connect to it. - When a hidden service's introduction point times out, consider trying it again during the next attempt to connect to the HS. Previously, we would not try it again unless a newly fetched descriptor contained it. Required by fixes for bugs 1297 and 3825. o Minor features (relays): - Relays now include a reason for regenerating their descriptors in an HTTP header when uploading to the authorities. This will make it easier to debug descriptor-upload issues in the future. - Turn on directory request statistics by default and include them in extra-info descriptors. Don't break if we have no GeoIP database. - Replace files in stats/ rather than appending to them. Now that we include statistics in extra-info descriptors, it makes no sense to keep old statistics forever. Implements ticket 2930. - Relays that set "ConnDirectionStatistics 1" write statistics on the bidirectional use of connections to disk every 24 hours. - Add a GeoIP file digest to the extra-info descriptor. Implements ticket 1883. o Minor features (new config options): - New config option "DynamicDHGroups" (disabled by default) provides each bridge with a unique prime DH modulus to be used during SSL handshakes. This option attempts to help against censors who might use the Apache DH modulus as a static identifier for bridges. Addresses ticket 4548. - New config option "DisableDebuggerAttachment" (on by default) to prevent basic debugging attachment attempts by other processes. Supports Mac OS X and Gnu/Linux. Resolves ticket 3313. - Ordinarily, Tor does not count traffic from private addresses (like 127.0.0.1 or 10.0.0.1) when calculating rate limits or accounting. There is now a new option, CountPrivateBandwidth, to disable this behavior. Patch from Daniel Cagara. o Minor features (different behavior for old config options): - Allow MapAddress directives to specify matches against super-domains, as in "MapAddress *.torproject.org *.torproject.org.torserver.exit". Implements issue 933. - Don't disable the DirPort when we cannot exceed our AccountingMax limit during this interval because the effective bandwidthrate is low enough. This is useful in a situation where AccountMax is only used as an additional safeguard or to provide statistics. - Add port 6523 (Gobby) to LongLivedPorts. Patch by intrigeri; implements ticket 3439. - When configuring a large set of nodes in EntryNodes, and there are enough of them listed as Guard so that we don't need to consider the non-guard entries, prefer the ones listed with the Guard flag. - If you set the NumCPUs option to 0, Tor will now try to detect how many CPUs you have. This is the new default behavior. - The NodeFamily option -- which let you declare that you want to consider nodes to be part of a family whether they list themselves that way or not -- now allows IP address ranges and country codes. o Minor features (new command-line config behavior): - Slightly change behavior of "list" options (that is, config options that can appear more than once) when they appear both in torrc and on the command line. Previously, the command-line options would be appended to the ones from torrc. Now, the command-line options override the torrc options entirely. This new behavior allows the user to override list options (like exit policies and ports to listen on) from the command line, rather than simply appending to the list. - You can get the old (appending) command-line behavior for "list" options by prefixing the option name with a "+". - You can remove all the values for a "list" option from the command line without adding any new ones by prefixing the option name with a "/". o Minor features (controller, new events): - Extend the control protocol to report flags that control a circuit's path selection in CIRC events and in replies to 'GETINFO circuit-status'. Implements part of ticket 2411. - Extend the control protocol to report the hidden service address and current state of a hidden-service-related circuit in CIRC events and in replies to 'GETINFO circuit-status'. Implements part of ticket 2411. - Include the creation time of a circuit in CIRC and CIRC2 control-port events and the list produced by the 'GETINFO circuit-status' control-port command. - Add a new CONF_CHANGED event so that controllers can be notified of any configuration changes made by other controllers, or by the user. Implements ticket 1692. - Add a new SIGNAL event to the controller interface so that controllers can be notified when Tor handles a signal. Resolves issue 1955. Patch by John Brooks. o Minor features (controller, new getinfo options): - Expose our view of whether we have gone dormant to the controller, via a new "GETINFO dormant" value. Torbutton and other controllers can use this to avoid doing periodic requests through Tor while it's dormant (bug 4718). Resolves ticket 5954. - Add a new GETINFO option to get total bytes read and written. Patch from pipe, revised by atagar. Resolves ticket 2345. - Implement new GETINFO controller fields to provide information about the Tor process's pid, euid, username, and resource limits. o Minor features (controller, other): - Allow controllers to request an event notification whenever a circuit is cannibalized or its purpose is changed. Implements part of ticket 3457. - Use absolute path names when reporting the torrc filename in the control protocol, so a controller can more easily find the torrc file. Resolves bug 1101. - When reporting the path to the cookie file to the controller, give an absolute path. Resolves ticket 4881. o Minor features (log messages): - Add more information to a log statement that might help track down bug 4091. If you're seeing "Bug: tor_addr_is_internal() called with a non-IP address" messages (or any Bug messages, for that matter!), please let us know about it. - If EntryNodes are given, but UseEntryGuards is set to 0, warn that EntryNodes will have no effect. Resolves issue 2571. - Try to make the introductory warning message that Tor prints on startup more useful for actually finding help and information. Resolves ticket 2474. - When the system call to create a listener socket fails, log the error message explaining why. This may help diagnose bug 4027. o Minor features (other): - When we fail to initialize Libevent, retry with IOCP disabled so we don't need to turn on multi-threading support in Libevent, which in turn requires a working socketpair(). This is a workaround for bug 4457, which affects Libevent versions from 2.0.1-alpha through 2.0.15-stable. - When starting as root and then changing our UID via the User control option, and we have a ControlSocket configured, make sure that the ControlSocket is owned by the same account that Tor will run under. Implements ticket 3421; fix by Jérémy Bobbio. - Accept attempts to include a password authenticator in the handshake, as supported by SOCKS5. This handles SOCKS clients that don't know how to omit a password when authenticating. Resolves bug 1666. - Check for and recover from inconsistency in the microdescriptor cache. This will make it harder for us to accidentally free a microdescriptor without removing it from the appropriate data structures. Fixes issue 3135; issue noted by "wanoskarnet". - Shorten links in the tor-exit-notice file. Patch by Christian Kujau. o Minor bugfixes (code security): - Prevent a null-pointer dereference when receiving a data cell for a nonexistent stream when the circuit in question has an empty deliver window. We don't believe this is triggerable, since we don't currently allow deliver windows to become empty, but the logic is tricky enough that it's better to make the code robust. Fixes bug 5541; bugfix on 0.0.2pre14. - Fix a (harmless) integer overflow in cell statistics reported by some fast relays. Fixes bug 5849; bugfix on 0.2.2.1-alpha. - Fix our implementation of crypto_random_hostname() so it can't overflow on ridiculously large inputs. (No Tor version has ever provided this kind of bad inputs, but let's be correct in depth.) Fixes bug 4413; bugfix on 0.2.2.9-alpha. Fix by Stephen Palmateer. - Add a (probably redundant) memory clear between iterations of the router status voting loop, to prevent future coding errors where data might leak between iterations of the loop. Resolves ticket 6514. o Minor bugfixes (wrapper functions): - Abort if tor_vasprintf() fails in connection_printf_to_buf() (a utility function used in the control-port code). This shouldn't ever happen unless Tor is completely out of memory, but if it did happen and Tor somehow recovered from it, Tor could have sent a log message to a control port in the middle of a reply to a controller command. Fixes part of bug 3428; bugfix on 0.1.2.3-alpha. - Fix some (not actually triggerable) buffer size checks in usage of tor_inet_ntop(). Fixes bug 4434; bugfix on Tor 0.2.0.1-alpha. Patch by Anders Sundman. - Fix parsing of some corner-cases with tor_inet_pton(). Fixes bug 4515; bugfix on 0.2.0.1-alpha; fix by Anders Sundman. - Enforce correct return behavior of tor_vsscanf() when the '%%' pattern is used. Fixes bug 5558. Bugfix on 0.2.1.13. - Make our replacement implementation of strtok_r() compatible with the standard behavior of strtok_r(). Patch by nils. Fixes bug 5091; bugfix on 0.2.2.1-alpha. - Find more places in the code that should have been testing for invalid sockets using the SOCKET_OK macro. Required for a fix for bug 4533. Bugfix on 0.2.2.28-beta. o Minor bugfixes (code correctness): - Check return value of fputs() when writing authority certificate file. Fixes Coverity issue 709056; bugfix on 0.2.0.1-alpha. - When building Tor on Windows with -DUNICODE (not default), ensure that error messages, filenames, and DNS server names are always NUL-terminated when we convert them to a single-byte encoding. Fixes bug 5909; bugfix on 0.2.2.16-alpha. - Fix a memory leak when trying to launch a DNS request when the nameservers are unconfigurable. Fixes bug 5916; bugfix on Tor 0.1.2.1-alpha. - Correct file sizes when reading binary files on Cygwin, to avoid a bug where Tor would fail to read its state file. Fixes bug 6844; bugfix on 0.1.2.7-alpha. - Make sure to set *socket_error in all error cases in connection_connect(), so it can't produce a warning about errno being zero from errno_to_orconn_end_reason(). Bugfix on 0.2.1.1-alpha; resolves ticket 6028. - Initialize conn->addr to a valid state in spawn_cpuworker(). Fixes bug 4532; found by "troll_un". o Minor bugfixes (clients): - Allow one-hop directory-fetching circuits the full "circuit build timeout" period, rather than just half of it, before failing them and marking the relay down. This fix should help reduce cases where clients declare relays (or worse, bridges) unreachable because the TLS handshake takes a few seconds to complete. Fixes bug 6743; bugfix on 0.2.2.2-alpha, where we changed the timeout from a static 30 seconds. - Ensure we don't cannibalize circuits that are longer than three hops already, so we don't end up making circuits with 5 or more hops. Patch contributed by wanoskarnet. Fixes bug 5231; bugfix on 0.1.0.1-rc which introduced cannibalization. o Minor bugfixes (relays): - Don't publish a new relay descriptor when we reload our onion key, unless the onion key has actually changed. Fixes bug 3263 and resolves another cause of bug 1810. Bugfix on 0.1.1.11-alpha. - When relays refuse a "create" cell because their queue of pending create cells is too big (typically because their cpu can't keep up with the arrival rate), send back reason "resource limit" rather than reason "internal", so network measurement scripts can get a more accurate picture. Bugfix on 0.1.1.11-alpha; fixes bug 7037. - Exit nodes don't need to fetch certificates for authorities that they don't recognize; only directory authorities, bridges, and caches need to do that. Fixes part of bug 2297; bugfix on 0.2.2.11-alpha. o Minor bugfixes (directory authority / mirrors): - Avoid O(n^2) performance characteristics when parsing a large extrainfo cache. Fixes bug 5828; bugfix on 0.2.0.1-alpha. - Authorities no longer include any router in their microdescriptor consensuses for which they couldn't generate or agree on a microdescriptor. Fixes the second piece of bug 6404; fix on 0.2.2.6-alpha. - When checking for requested signatures on the latest consensus before serving it to a client, make sure to check the right consensus flavor. Bugfix on 0.2.2.6-alpha. - Fix an edge case where TestingTorNetwork is set but the authorities and relays all have an uptime of zero, so the private Tor network could briefly lack support for hidden services. Fixes bug 3886; bugfix on 0.2.2.18-alpha. - Directory caches no longer refuse to clean out descriptors because of missing v2 networkstatus documents, unless they're configured to retrieve v2 networkstatus documents. Fixes bug 4838; bugfix on 0.2.2.26-beta. Patch by Daniel Bryg. - Don't serve or accept v2 hidden service descriptors over a relay's DirPort. It's never correct to do so, and disabling it might make it more annoying to exploit any bugs that turn up in the descriptor-parsing code. Fixes bug 7149. o Minor bugfixes (hidden services, client-side): - Assert that hidden-service-related operations are not performed using single-hop circuits. Previously, Tor would assert that client-side streams are not attached to single-hop circuits, but not that other sensitive operations on the client and service side are not performed using single-hop circuits. Fixes bug 3332; bugfix on 0.0.6. - Avoid undefined behaviour when parsing the list of supported rendezvous/introduction protocols in a hidden service descriptor. Previously, Tor would have confused (as-yet-unused) protocol version numbers greater than 32 with lower ones on many platforms. Fixes bug 6827; bugfix on 0.2.0.10-alpha. Found by George Kadianakis. - Don't close hidden service client circuits which have almost finished connecting to their destination when they reach the normal circuit-build timeout. Previously, we would close introduction circuits which are waiting for an acknowledgement from the introduction point, and rendezvous circuits which have been specified in an INTRODUCE1 cell sent to a hidden service, after the normal CBT. Now, we mark them as 'timed out', and launch another rendezvous attempt in parallel. This behavior change can be disabled using the new CloseHSClientCircuitsImmediatelyOnTimeout option. Fixes part of bug 1297; bugfix on 0.2.2.2-alpha. o Minor bugfixes (hidden services, service-side): - Don't close hidden-service-side rendezvous circuits when they reach the normal circuit-build timeout. This behaviour change can be disabled using the new CloseHSServiceRendCircuitsImmediatelyOnTimeout option. Fixes the remaining part of bug 1297; bugfix on 0.2.2.2-alpha. - Don't launch more than 10 service-side introduction-point circuits for a hidden service in five minutes. Previously, we would consider launching more introduction-point circuits if at least one second had passed without any introduction-point circuits failing. Fixes bug 4607; bugfix on 0.0.7pre1. o Minor bugfixes (config option behavior): - If the user tries to set MyFamily on a bridge, refuse to do so, and warn about the security implications. Fixes bug 4657; bugfix on 0.2.0.3-alpha. - The "--quiet" and "--hush" options now apply not only to Tor's behavior before logs are configured, but also to Tor's behavior in the absense of configured logs. Fixes bug 3550; bugfix on 0.2.0.10-alpha. - Change the AllowDotExit rules so they should actually work. We now enforce AllowDotExit only immediately after receiving an address via SOCKS or DNSPort: other sources are free to provide .exit addresses after the resolution occurs. Fixes bug 3940; bugfix on 0.2.2.1-alpha. - Make "LearnCircuitBuildTimeout 0" work more reliably. Specifically, don't depend on the consensus parameters or compute adaptive timeouts when it is disabled. Fixes bug 5049; bugfix on 0.2.2.14-alpha. - After we pick a directory mirror, we would refuse to use it if it's in our ExcludeExitNodes list, resulting in mysterious failures to bootstrap for people who just wanted to avoid exiting from certain locations. Fixes bug 5623; bugfix on 0.2.2.25-alpha. - When told to add a bridge with the same digest as a preexisting bridge but a different addr:port, change the addr:port as requested. Previously we would not notice the change. Fixes half of bug 5603; fix on 0.2.2.26-beta. o Minor bugfixes (controller): - Allow manual 'authenticate' commands to the controller interface from netcat (nc) as well as telnet. We were rejecting them because they didn't come with the expected whitespace at the end of the command. Bugfix on 0.1.1.1-alpha; fixes bug 2893. - Report a real bootstrap problem to the controller on router identity mismatch. Previously we just said "foo", which probably made a lot of sense at the time. Fixes bug 4169; bugfix on 0.2.1.1-alpha. - When we receive a SIGHUP and the controller __ReloadTorrcOnSIGHUP option is set to 0 (which Vidalia version 0.2.16 now does when a SAVECONF attempt fails), perform other actions that SIGHUP usually causes (like reopening the logs). Fixes bug 5095; bugfix on 0.2.1.9-alpha. - Correctly handle checking the permissions on the parent directory of a control socket in the root directory. Bug found by Esteban Manchado Velázquez. Fixes bug 5089; bugfix on Tor 0.2.2.26-beta. - End AUTHCHALLENGE error messages (in the control protocol) with a CRLF. Fixes bug 5760; bugfix on 0.2.2.36. o Minor bugfixes (network reading/writing): - Disable writing on marked-for-close connections when they are blocked on bandwidth, to prevent busy-looping in Libevent. Fixes bug 5263; bugfix on 0.0.2pre13, where we first added a special case for flushing marked connections. - Make sure that there are no unhandled pending TLS errors before reading from a TLS stream. We had checks in 0.1.0.3-rc, but lost them in 0.1.0.5-rc when we refactored read_to_buf_tls(). Bugfix on 0.1.0.5-rc; fixes bug 4528. - Detect SSL handshake even when the initial attempt to write the server hello fails. Fixes bug 4592; bugfix on 0.2.0.13-alpha. - If the client fails to set a reasonable set of ciphersuites during its v2 handshake renegotiation, allow the renegotiation to continue nevertheless (i.e. send all the required certificates). Fixes bug 4591; bugfix on 0.2.0.20-rc. o Minor bugfixes (other): - Exit nodes now correctly report EADDRINUSE and EADDRNOTAVAIL as resource exhaustion, so that clients can adjust their load to try other exits. Fixes bug 4710; bugfix on 0.1.0.1-rc, which started using END_STREAM_REASON_RESOURCELIMIT. - Don't check for whether the address we're using for outbound connections has changed until after the outbound connection has completed. On Windows, getsockname() doesn't succeed until the connection is finished. Fixes bug 5374; bugfix on 0.1.1.14-alpha. - Don't hold a Windows file handle open for every file mapping; the file mapping handle is sufficient. Fixes bug 5951; bugfix on 0.1.2.1-alpha. - Fix wrong TCP port range in parse_port_range(). Fixes bug 6218; bugfix on 0.2.1.10-alpha. - If we fail to write a microdescriptor to the disk cache, do not continue replacing the old microdescriptor file. Fixes bug 2954; bugfix on 0.2.2.6-alpha. o Minor bugfixes (log messages, path selection): - Downgrade "set buildtimeout to low value" messages to "info" severity; they were never an actual problem, there was never anything reasonable to do about them, and they tended to spam logs from time to time. Fixes bug 6251; bugfix on 0.2.2.2-alpha. - Rate-limit the "Weighted bandwidth is 0.000000" message, and add more information to it, so that we can track it down in case it returns again. Mitigates bug 5235. - Check CircuitBuildTimeout and LearnCircuitBuildTimeout in options_validate(); warn if LearnCircuitBuildTimeout is disabled and CircuitBuildTimeout is set unreasonably low. Resolves ticket 5452. - Issue a log message if a guard completes less than 40% of your circuits. Threshold is configurable by torrc option PathBiasNoticeRate and consensus parameter pb_noticepct. There is additional, off-by-default code to disable guards which fail too many circuits. Addresses ticket 5458. o Minor bugfixes (log messages, client): - Downgrade "Got a certificate, but we already have it" log messages from warning to info, except when we're a dirauth. Fixes bug 5238; bugfix on 0.2.1.7-alpha. - Fix the log message describing how we work around discovering that our version is the ill-fated OpenSSL 0.9.8l. Fixes bug 4837; bugfix on 0.2.2.9-alpha. - When logging about a disallowed .exit name, do not also call it an "invalid onion address". Fixes bug 3325; bugfix on 0.2.2.9-alpha. - Fix a log message suggesting that people contact a non-existent email address. Fixes bug 3448. - Rephrase the log message emitted if the TestSocks check is successful. Patch from Fabian Keil; fixes bug 4094. - Log (at debug level) whenever a circuit's purpose is changed. - Log SSL state transitions at log level DEBUG, log domain HANDSHAKE. This can be useful for debugging censorship events. Implements ticket 3264. - We now log which torrc file we're using on startup. Implements ticket 2444. - Rate-limit log messages when asked to connect anonymously to a private address. When these hit, they tended to hit fast and often. Also, don't bother trying to connect to addresses that we are sure will resolve to 127.0.0.1: getting 127.0.0.1 in a directory reply makes us think we have been lied to, even when the address the client tried to connect to was "localhost." Resolves ticket 2822. o Minor bugfixes (log messages, non-client): - Downgrade "eventdns rejected address" message to LOG_PROTOCOL_WARN. Fixes bug 5932; bugfix on 0.2.2.7-alpha. - Don't log that we have "decided to publish new relay descriptor" unless we are actually publishing a descriptor. Fixes bug 3942; bugfix on 0.2.2.28-beta. - Log which authority we're missing votes from when we go to fetch them from the other auths. - Replace "Sending publish request" log messages with "Launching upload", so that they no longer confusingly imply that we're sending something to a directory we might not even be connected to yet. Fixes bug 3311; bugfix on 0.2.0.10-alpha. - Warn when Tor is configured to use accounting in a way that can link a hidden service to some other hidden service or public address. Resolves ticket 6490. - Fix a minor formatting issue in one of tor-gencert's error messages. Fixes bug 4574. o Testing: - Update to the latest version of the tinytest unit testing framework. This includes a couple of bugfixes that can be relevant for running forked unit tests on Windows, and removes all reserved identifiers. - Avoid a false positive in the util/threads unit test by increasing the maximum timeout time. Fixes bug 6227; bugfix on 0.2.0.4-alpha. - Make it possible to set the TestingTorNetwork configuration option using AlternateDirAuthority and AlternateBridgeAuthority as an alternative to setting DirServer. Addresses ticket 6377. - Add a unit test for the environment_variable_names_equal() function. - A wide variety of new unit tests by Esteban Manchado Velázquez. - Numerous new unit tests for functions in util.c and address.c by Anders Sundman. - The long-disabled benchmark tests are now split into their own ./src/test/bench binary. - The benchmark tests can now use more accurate timers than gettimeofday() when such timers are available. - Use tt_assert(), not tor_assert(), for checking for test failures. This makes the unit tests more able to go on in the event that one of them fails. o Build improvements: - Use the dead_strip option when building Tor on OS X. This reduces binary size by almost 19% when linking openssl and libevent statically, which we do for Tor Browser Bundle. - Provide a better error message about possible OSX Asciidoc failure reasons. Fixes bug 6436. - Detect attempts to build Tor on (as yet hypothetical) versions of Windows where sizeof(intptr_t) != sizeof(SOCKET). Partial fix for bug 4533. Bugfix on 0.2.2.28-beta. - On Windows, we now define the _WIN32_WINNT macros only if they are not already defined. This lets the person building Tor decide, if they want, to require a later version of Windows. - Our autogen.sh script now uses autoreconf to launch autoconf, automake, and so on. This is more robust against some of the failure modes associated with running the autotools pieces on their own. - Running "make version" now displays the version of Tor that we're about to build. Idea from katmagic; resolves issue 4400. - Make 'tor --digests' list hashes of all Tor source files. Bugfix on 0.2.2.4-alpha; fixes bug 3427. - New --enable-static-tor configure option for building Tor as statically as possible. Idea, general hackery and thoughts from Alexei Czeskis, John Gilmore, Jacob Appelbaum. Implements ticket 2702. - Limited, experimental support for building with nmake and MSVC. o Build requirements: - Building Tor with bufferevent support now requires Libevent 2.0.13-stable or later. Previous versions of Libevent had bugs in SSL-related bufferevents and related issues that would make Tor work badly with bufferevents. Requiring 2.0.13-stable also allows Tor with bufferevents to take advantage of Libevent APIs introduced after 2.0.8-rc. - Our build system requires automake 1.6 or later to create the Makefile.in files. Previously, you could have used 1.4. This only affects developers and people building Tor from git; people who build Tor from the source distribution without changing the Makefile.am files should be fine. - Detect when we try to build on a platform that doesn't define AF_UNSPEC to 0. We don't work there, so refuse to compile. o Build fixes (compile/link): - Format more doubles with %f, not %lf. Patch from grarpamp to make Tor build correctly on older BSDs again. Fixes bug 3894; bugfix on Tor 0.2.0.8-alpha. - When building with --enable-static-tor on OpenBSD, do not erroneously attempt to link -lrt. Fixes bug 5103. - Set _WIN32_WINNT to 0x0501 consistently throughout the code, so that IPv6 stuff will compile on MSVC, and compilation issues will be easier to track down. Fixes bug 5861. - Fix build and 64-bit compile warnings from --enable-openbsd-malloc. Fixes bug 6379. Bugfix on 0.2.0.20-rc. - Make Tor build correctly again with -DUNICODE -D_UNICODE defined. Fixes bug 6097; bugfix on 0.2.2.16-alpha. o Build fixes (other): - Use the _WIN32 macro throughout our code to detect Windows. (Previously we had used the obsolete 'WIN32' and the idiosyncratic 'MS_WINDOWS'.) - Properly handle the case where the build-tree is not the same as the source tree when generating src/common/common_sha1.i, src/or/micro-revision.i, and src/or/or_sha1.i. Fixes bug 3953; bugfix on 0.2.0.1-alpha. - During configure, search for library containing cos function as libm lives in libcore on some platforms (BeOS/Haiku). Linking against libm was hard-coded before. Fixes the first part of bug 4727; bugfix on 0.2.2.2-alpha. Patch and analysis by Martin Hebnes Pedersen. - Prevent a false positive from the check-spaces script, by disabling the "whitespace between function name and (" check for functions named 'op()'. o Packaging (RPM) changes: - Update our default RPM spec files to work with mock and rpmbuild on RHEL/Fedora. They have an updated set of dependencies and conflicts, a fix for an ancient typo when creating the "_tor" user, and better instructions. Thanks to Ondrej Mikle for the patch series. Fixes bug 6043. - On OpenSUSE, create the /var/run/tor directory on startup if it is not already created. Patch from Andreas Stieger. Fixes bug 2573. o Code refactoring (safety): - Do not use SMARTLIST_FOREACH for any loop whose body exceeds 10 lines. Also, don't nest them. Doing so in the past has led to hard-to-debug code. The new style is to use the SMARTLIST_FOREACH_{BEGIN,END} pair. Addresses issue 6400. - Use macros to indicate OpenSSL versions, so we don't need to worry about accidental hexadecimal bit shifts. - Use tor_sscanf() in place of scanf() in more places through the code. This makes us a little more locale-independent, and should help shut up code-analysis tools that can't tell a safe sscanf string from a dangerous one. - Convert more instances of tor_snprintf+tor_strdup into tor_asprintf. - Use the smartlist_add_asprintf() alias more consistently. o Code refactoring (consolidate): - A major revision to our internal node-selecting and listing logic. Tor already had at least two major ways to look at the question of "which Tor servers do we know about": a list of router descriptors, and a list of entries in the current consensus. With microdescriptors, we're adding a third. Having so many systems without an abstraction layer over them was hurting the codebase. Now, we have a new "node_t" abstraction that presents a consistent interface to a client's view of a Tor node, and holds (nearly) all of the mutable state formerly in routerinfo_t and routerstatus_t. - Move tor_gettimeofday_cached() into compat_libevent.c, and use Libevent's notion of cached time when possible. - Remove duplicate code for invoking getrlimit() from control.c. - Use OpenSSL's built-in SSL_state_string_long() instead of our own homebrewed ssl_state_to_string() replacement. Patch from Emile Snyder. Fixes bug 4653. - Change the symmetric cipher interface so that creating and initializing a stream cipher are no longer separate functions. o Code refactoring (separate): - Make a new "entry connection" struct as an internal subtype of "edge connection", to simplify the code and make exit connections smaller. - Split connection_about_to_close() into separate functions for each connection type. - Rewrite the listener-selection logic so that parsing which ports we want to listen on is now separate from binding to the ports we want. o Code refactoring (name changes): - Rename a handful of old identifiers, mostly related to crypto structures and crypto functions. By convention, our "create an object" functions are called "type_new()", our "free an object" functions are called "type_free()", and our types indicate that they are types only with a final "_t". But a handful of older types and functions broke these rules, with function names like "type_create" or "subsystem_op_type", or with type names like type_env_t. - Rename Tor functions that turn strings into addresses, so that "parse" indicates that no hostname resolution occurs, and "lookup" indicates that hostname resolution may occur. This should help prevent mistakes in the future. Fixes bug 3512. - Use the name "CERTS" consistently to refer to the new cell type; we were calling it CERT in some places and CERTS in others. - Use a TOR_INVALID_SOCKET macro when initializing a socket to an invalid value, rather than just -1. - Rename the bench_{aes,dmap} functions to test_*, so that tinytest can pick them up when the tests aren't disabled. Bugfix on 0.2.2.4-alpha which introduced tinytest. o Code refactoring (other): - Defensively refactor rend_mid_rendezvous() so that protocol violations and length checks happen in the beginning. Fixes bug 5645. - Remove the pure attribute from all functions that used it previously. In many cases we assigned it incorrectly, because the functions might assert or call impure functions, and we don't have evidence that keeping the pure attribute is worthwhile. Implements changes suggested in ticket 4421. - Move the replay-detection cache for the RSA-encrypted parts of INTRODUCE2 cells to the introduction point data structures. Previously, we would use one replay-detection cache per hidden service. Required by fix for bug 3460. - The helper programs tor-gencert, tor-resolve, and tor-checkkey no longer link against Libevent: they never used it, but our library structure used to force them to link it. o Removed features and files: - Remove all internal support for unpadded RSA. We never used it, and it would be a bad idea to start. - Remove some workaround code for OpenSSL 0.9.6 (which is no longer supported). - Remove some redundant #include directives throughout the code. Patch from Andrea Gelmini. - Remove some old code to remember statistics about which descriptors we've served as a directory mirror. The feature wasn't used and is outdated now that microdescriptors are around. - Remove some old code to work around even older versions of Tor that used forked processes to handle DNS requests. Such versions of Tor are no longer in use as relays. - The "torify" script no longer supports the "tsocks" socksifier tool, since tsocks doesn't support DNS and UDP right for Tor. Everyone should be using torsocks instead. Fixes bugs 3530 and 5180. Based on a patch by "ugh". - Remove the torrc.bridge file: we don't use it for anything, and it had become badly desynchronized from torrc.sample. Resolves bug 5622. o Documentation: - Begin a doc/state-contents.txt file to explain the contents of the Tor state file. Fixes bug 2987. - Clarify the documentation for the Alternate*Authority options. Fixes bug 6387. - Document the --defaults-torrc option, and the new semantics for overriding, extending, and clearing lists of options. Closes bug 4748. - Add missing man page documentation for consensus and microdesc files. Resolves ticket 6732. - Fix some typos in the manpages. Patch from A. Costa. Fixes bug 6500. o Documentation fixes: - Improve the manual's documentation for the NT Service command-line options. Addresses ticket 3964. - Clarify SessionGroup documentation slightly; resolves ticket 5437. - Document the changes to the ORPort and DirPort options, and the fact that {OR/Dir}ListenAddress is now unnecessary (and therefore deprecated). Resolves ticket 5597. - Correct a broken faq link in the INSTALL file. Fixes bug 2307. - Clarify that hidden services are TCP only. Fixes bug 6024. Changes in version 0.2.2.39 - 2012-09-11 Tor 0.2.2.39 fixes two more opportunities for remotely triggerable assertions. o Security fixes: - Fix an assertion failure in tor_timegm() that could be triggered by a badly formatted directory object. Bug found by fuzzing with Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc. - Do not crash when comparing an address with port value 0 to an address policy. This bug could have been used to cause a remote assertion failure by or against directory authorities, or to allow some applications to crash clients. Fixes bug 6690; bugfix on 0.2.1.10-alpha. Changes in version 0.2.2.38 - 2012-08-12 Tor 0.2.2.38 fixes a remotely triggerable crash bug, and fixes a timing attack that could in theory leak path information. o Security fixes: - Avoid an uninitialized memory read when reading a vote or consensus document that has an unrecognized flavor name. This read could lead to a remote crash bug. Fixes bug 6530; bugfix on 0.2.2.6-alpha. - Try to leak less information about what relays a client is choosing to a side-channel attacker. Previously, a Tor client would stop iterating through the list of available relays as soon as it had chosen one, thus finishing a little earlier when it picked a router earlier in the list. If an attacker can recover this timing information (nontrivial but not proven to be impossible), they could learn some coarse-grained information about which relays a client was picking (middle nodes in particular are likelier to be affected than exits). The timing attack might be mitigated by other factors (see bug 6537 for some discussion), but it's best not to take chances. Fixes bug 6537; bugfix on 0.0.8rc1. Changes in version 0.2.2.37 - 2012-06-06 Tor 0.2.2.37 introduces a workaround for a critical renegotiation bug in OpenSSL 1.0.1 (where 20% of the Tor network can't talk to itself currently). o Major bugfixes: - Work around a bug in OpenSSL that broke renegotiation with TLS 1.1 and TLS 1.2. Without this workaround, all attempts to speak the v2 Tor connection protocol when both sides were using OpenSSL 1.0.1 would fail. Resolves ticket 6033. - When waiting for a client to renegotiate, don't allow it to add any bytes to the input buffer. This fixes a potential DoS issue. Fixes bugs 5934 and 6007; bugfix on 0.2.0.20-rc. - Fix an edge case where if we fetch or publish a hidden service descriptor, we might build a 4-hop circuit and then use that circuit for exiting afterwards -- even if the new last hop doesn't obey our ExitNodes config option. Fixes bug 5283; bugfix on 0.2.0.10-alpha. o Minor bugfixes: - Fix a build warning with Clang 3.1 related to our use of vasprintf. Fixes bug 5969. Bugfix on 0.2.2.11-alpha. o Minor features: - Tell GCC and Clang to check for any errors in format strings passed to the tor_v*(print|scan)f functions. Changes in version 0.2.2.36 - 2012-05-24 Tor 0.2.2.36 updates the addresses for two of the eight directory authorities, fixes some potential anonymity and security issues, and fixes several crash bugs. Tor 0.2.1.x has reached its end-of-life. Those Tor versions have many known flaws, and nobody should be using them. You should upgrade. If you're using a Linux or BSD and its packages are obsolete, stop using those packages and upgrade anyway. o Directory authority changes: - Change IP address for maatuska (v3 directory authority). - Change IP address for ides (v3 directory authority), and rename it to turtles. o Security fixes: - When building or running with any version of OpenSSL earlier than 0.9.8s or 1.0.0f, disable SSLv3 support. These OpenSSL versions have a bug (CVE-2011-4576) in which their block cipher padding includes uninitialized data, potentially leaking sensitive information to any peer with whom they make a SSLv3 connection. Tor does not use SSL v3 by default, but a hostile client or server could force an SSLv3 connection in order to gain information that they shouldn't have been able to get. The best solution here is to upgrade to OpenSSL 0.9.8s or 1.0.0f (or later). But when building or running with a non-upgraded OpenSSL, we disable SSLv3 entirely to make sure that the bug can't happen. - Never use a bridge or a controller-supplied node as an exit, even if its exit policy allows it. Found by wanoskarnet. Fixes bug 5342. Bugfix on 0.1.1.15-rc (for controller-purpose descriptors) and 0.2.0.3-alpha (for bridge-purpose descriptors). - Only build circuits if we have a sufficient threshold of the total descriptors that are marked in the consensus with the "Exit" flag. This mitigates an attack proposed by wanoskarnet, in which all of a client's bridges collude to restrict the exit nodes that the client knows about. Fixes bug 5343. - Provide controllers with a safer way to implement the cookie authentication mechanism. With the old method, if another locally running program could convince a controller that it was the Tor process, then that program could trick the controller into telling it the contents of an arbitrary 32-byte file. The new "SAFECOOKIE" authentication method uses a challenge-response approach to prevent this attack. Fixes bug 5185; implements proposal 193. o Major bugfixes: - Avoid logging uninitialized data when unable to decode a hidden service descriptor cookie. Fixes bug 5647; bugfix on 0.2.1.5-alpha. - Avoid a client-side assertion failure when receiving an INTRODUCE2 cell on a general purpose circuit. Fixes bug 5644; bugfix on 0.2.1.6-alpha. - Fix builds when the path to sed, openssl, or sha1sum contains spaces, which is pretty common on Windows. Fixes bug 5065; bugfix on 0.2.2.1-alpha. - Correct our replacements for the timeradd() and timersub() functions on platforms that lack them (for example, Windows). The timersub() function is used when expiring circuits, while timeradd() is currently unused. Bug report and patch by Vektor. Fixes bug 4778; bugfix on 0.2.2.24-alpha. - Fix the SOCKET_OK test that we use to tell when socket creation fails so that it works on Win64. Fixes part of bug 4533; bugfix on 0.2.2.29-beta. Bug found by wanoskarnet. o Minor bugfixes: - Reject out-of-range times like 23:59:61 in parse_rfc1123_time(). Fixes bug 5346; bugfix on 0.0.8pre3. - Make our number-parsing functions always treat too-large values as an error, even when those values exceed the width of the underlying type. Previously, if the caller provided these functions with minima or maxima set to the extreme values of the underlying integer type, these functions would return those values on overflow rather than treating overflow as an error. Fixes part of bug 5786; bugfix on 0.0.9. - Older Linux kernels erroneously respond to strange nmap behavior by having accept() return successfully with a zero-length socket. When this happens, just close the connection. Previously, we would try harder to learn the remote address: but there was no such remote address to learn, and our method for trying to learn it was incorrect. Fixes bugs 1240, 4745, and 4747. Bugfix on 0.1.0.3-rc. Reported and diagnosed by "r1eo". - Correct parsing of certain date types in parse_http_time(). Without this patch, If-Modified-Since would behave incorrectly. Fixes bug 5346; bugfix on 0.2.0.2-alpha. Patch from Esteban Manchado Velázques. - Change the BridgePassword feature (part of the "bridge community" design, which is not yet implemented) to use a time-independent comparison. The old behavior might have allowed an adversary to use timing to guess the BridgePassword value. Fixes bug 5543; bugfix on 0.2.0.14-alpha. - Detect and reject certain misformed escape sequences in configuration values. Previously, these values would cause us to crash if received in a torrc file or over an authenticated control port. Bug found by Esteban Manchado Velázquez, and independently by Robert Connolly from Matta Consulting who further noted that it allows a post-authentication heap overflow. Patch by Alexander Schrijver. Fixes bugs 5090 and 5402 (CVE 2012-1668); bugfix on 0.2.0.16-alpha. - Fix a compile warning when using the --enable-openbsd-malloc configure option. Fixes bug 5340; bugfix on 0.2.0.20-rc. - During configure, detect when we're building with clang version 3.0 or lower and disable the -Wnormalized=id and -Woverride-init CFLAGS. clang doesn't support them yet. - When sending an HTTP/1.1 proxy request, include a Host header. Fixes bug 5593; bugfix on 0.2.2.1-alpha. - Fix a NULL-pointer dereference on a badly formed SETCIRCUITPURPOSE command. Found by mikeyc. Fixes bug 5796; bugfix on 0.2.2.9-alpha. - If we hit the error case where routerlist_insert() replaces an existing (old) server descriptor, make sure to remove that server descriptor from the old_routers list. Fix related to bug 1776. Bugfix on 0.2.2.18-alpha. o Minor bugfixes (documentation and log messages): - Fix a typo in a log message in rend_service_rendezvous_has_opened(). Fixes bug 4856; bugfix on Tor 0.0.6. - Update "ClientOnly" man page entry to explain that there isn't really any point to messing with it. Resolves ticket 5005. - Document the GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays directory authority option (introduced in Tor 0.2.2.34). - Downgrade the "We're missing a certificate" message from notice to info: people kept mistaking it for a real problem, whereas it is seldom the problem even when we are failing to bootstrap. Fixes bug 5067; bugfix on 0.2.0.10-alpha. - Correctly spell "connect" in a log message on failure to create a controlsocket. Fixes bug 4803; bugfix on 0.2.2.26-beta. - Clarify the behavior of MaxCircuitDirtiness with hidden service circuits. Fixes issue 5259. o Minor features: - Directory authorities now reject versions of Tor older than 0.2.1.30, and Tor versions between 0.2.2.1-alpha and 0.2.2.20-alpha inclusive. These versions accounted for only a small fraction of the Tor network, and have numerous known security issues. Resolves issue 4788. - Update to the May 1 2012 Maxmind GeoLite Country database. - Feature removal: - When sending or relaying a RELAY_EARLY cell, we used to convert it to a RELAY cell if the connection was using the v1 link protocol. This was a workaround for older versions of Tor, which didn't handle RELAY_EARLY cells properly. Now that all supported versions can handle RELAY_EARLY cells, and now that we're enforcing the "no RELAY_EXTEND commands except in RELAY_EARLY cells" rule, remove this workaround. Addresses bug 4786. Changes in version 0.2.2.35 - 2011-12-16 Tor 0.2.2.35 fixes a critical heap-overflow security issue in Tor's buffers code. Absolutely everybody should upgrade. The bug relied on an incorrect calculation when making data continuous in one of our IO buffers, if the first chunk of the buffer was misaligned by just the wrong amount. The miscalculation would allow an attacker to overflow a piece of heap-allocated memory. To mount this attack, the attacker would need to either open a SOCKS connection to Tor's SocksPort (usually restricted to localhost), or target a Tor instance configured to make its connections through a SOCKS proxy (which Tor does not do by default). Good security practice requires that all heap-overflow bugs should be presumed to be exploitable until proven otherwise, so we are treating this as a potential code execution attack. Please upgrade immediately! This bug does not affect bufferevents-based builds of Tor. Special thanks to "Vektor" for reporting this issue to us! Tor 0.2.2.35 also fixes several bugs in previous versions, including crash bugs for unusual configurations, and a long-term bug that would prevent Tor from starting on Windows machines with draconian AV software. With this release, we remind everyone that 0.2.0.x has reached its formal end-of-life. Those Tor versions have many known flaws, and nobody should be using them. You should upgrade -- ideally to the 0.2.2.x series. If you're using a Linux or BSD and its packages are obsolete, stop using those packages and upgrade anyway. The Tor 0.2.1.x series is also approaching its end-of-life: it will no longer receive support after some time in early 2012. o Major bugfixes: - Fix a heap overflow bug that could occur when trying to pull data into the first chunk of a buffer, when that chunk had already had some data drained from it. Fixes CVE-2011-2778; bugfix on 0.2.0.16-alpha. Reported by "Vektor". - Initialize Libevent with the EVENT_BASE_FLAG_NOLOCK flag enabled, so that it doesn't attempt to allocate a socketpair. This could cause some problems on Windows systems with overzealous firewalls. Fix for bug 4457; workaround for Libevent versions 2.0.1-alpha through 2.0.15-stable. - If we mark an OR connection for close based on a cell we process, don't process any further cells on it. We already avoid further reads on marked-for-close connections, but now we also discard the cells we'd already read. Fixes bug 4299; bugfix on 0.2.0.10-alpha, which was the first version where we might mark a connection for close based on processing a cell on it. - Correctly sanity-check that we don't underflow on a memory allocation (and then assert) for hidden service introduction point decryption. Bug discovered by Dan Rosenberg. Fixes bug 4410; bugfix on 0.2.1.5-alpha. - Fix a memory leak when we check whether a hidden service descriptor has any usable introduction points left. Fixes bug 4424. Bugfix on 0.2.2.25-alpha. - Don't crash when we're running as a relay and don't have a GeoIP file. Bugfix on 0.2.2.34; fixes bug 4340. This backports a fix we've had in the 0.2.3.x branch already. - When running as a client, do not print a misleading (and plain wrong) log message that we're collecting "directory request" statistics: clients don't collect statistics. Also don't create a useless (because empty) stats file in the stats/ directory. Fixes bug 4353; bugfix on 0.2.2.34. o Minor bugfixes: - Detect failure to initialize Libevent. This fix provides better detection for future instances of bug 4457. - Avoid frequent calls to the fairly expensive cull_wedged_cpuworkers function. This was eating up hideously large amounts of time on some busy servers. Fixes bug 4518; bugfix on 0.0.9.8. - Resolve an integer overflow bug in smartlist_ensure_capacity(). Fixes bug 4230; bugfix on Tor 0.1.0.1-rc. Based on a patch by Mansour Moufid. - Don't warn about unused log_mutex in log.c when building with --disable-threads using a recent GCC. Fixes bug 4437; bugfix on 0.1.0.6-rc which introduced --disable-threads. - When configuring, starting, or stopping an NT service, stop immediately after the service configuration attempt has succeeded or failed. Fixes bug 3963; bugfix on 0.2.0.7-alpha. - When sending a NETINFO cell, include the original address received for the other side, not its canonical address. Found by "troll_un"; fixes bug 4349; bugfix on 0.2.0.10-alpha. - Fix a typo in a hibernation-related log message. Fixes bug 4331; bugfix on 0.2.2.23-alpha; found by "tmpname0901". - Fix a memory leak in launch_direct_bridge_descriptor_fetch() that occurred when a client tried to fetch a descriptor for a bridge in ExcludeNodes. Fixes bug 4383; bugfix on 0.2.2.25-alpha. - Backport fixes for a pair of compilation warnings on Windows. Fixes bug 4521; bugfix on 0.2.2.28-beta and on 0.2.2.29-beta. - If we had ever tried to call tor_addr_to_str on an address of unknown type, we would have done a strdup on an uninitialized buffer. Now we won't. Fixes bug 4529; bugfix on 0.2.1.3-alpha. Reported by "troll_un". - Correctly detect and handle transient lookup failures from tor_addr_lookup. Fixes bug 4530; bugfix on 0.2.1.5-alpha. Reported by "troll_un". - Fix null-pointer access that could occur if TLS allocation failed. Fixes bug 4531; bugfix on 0.2.0.20-rc. Found by "troll_un". - Use tor_socket_t type for listener argument to accept(). Fixes bug 4535; bugfix on 0.2.2.28-beta. Found by "troll_un". o Minor features: - Add two new config options for directory authorities: AuthDirFastGuarantee sets a bandwidth threshold for guaranteeing the Fast flag, and AuthDirGuardBWGuarantee sets a bandwidth threshold that is always sufficient to satisfy the bandwidth requirement for the Guard flag. Now it will be easier for researchers to simulate Tor networks with different values. Resolves ticket 4484. - When Tor ignores a hidden service specified in its configuration, include the hidden service's directory in the warning message. Previously, we would only tell the user that some hidden service was ignored. Bugfix on 0.0.6; fixes bug 4426. - Update to the December 6 2011 Maxmind GeoLite Country database. o Packaging changes: - Make it easier to automate expert package builds on Windows, by removing an absolute path from makensis.exe command. Changes in version 0.2.1.32 - 2011-12-16 Tor 0.2.1.32 backports important security and privacy fixes for oldstable. This release is intended only for package maintainers and others who cannot use the 0.2.2 stable series. All others should be using Tor 0.2.2.x or newer. The Tor 0.2.1.x series will reach formal end-of-life some time in early 2012; we will stop releasing patches for it then. o Major bugfixes (also included in 0.2.2.x): - Correctly sanity-check that we don't underflow on a memory allocation (and then assert) for hidden service introduction point decryption. Bug discovered by Dan Rosenberg. Fixes bug 4410; bugfix on 0.2.1.5-alpha. - Fix a heap overflow bug that could occur when trying to pull data into the first chunk of a buffer, when that chunk had already had some data drained from it. Fixes CVE-2011-2778; bugfix on 0.2.0.16-alpha. Reported by "Vektor". o Minor features: - Update to the December 6 2011 Maxmind GeoLite Country database. Changes in version 0.2.2.34 - 2011-10-26 Tor 0.2.2.34 fixes a critical anonymity vulnerability where an attacker can deanonymize Tor users. Everybody should upgrade. The attack relies on four components: 1) Clients reuse their TLS cert when talking to different relays, so relays can recognize a user by the identity key in her cert. 2) An attacker who knows the client's identity key can probe each guard relay to see if that identity key is connected to that guard relay right now. 3) A variety of active attacks in the literature (starting from "Low-Cost Traffic Analysis of Tor" by Murdoch and Danezis in 2005) allow a malicious website to discover the guard relays that a Tor user visiting the website is using. 4) Clients typically pick three guards at random, so the set of guards for a given user could well be a unique fingerprint for her. This release fixes components #1 and #2, which is enough to block the attack; the other two remain as open research problems. Special thanks to "frosty_un" for reporting the issue to us! Clients should upgrade so they are no longer recognizable by the TLS certs they present. Relays should upgrade so they no longer allow a remote attacker to probe them to test whether unpatched clients are currently connected to them. This release also fixes several vulnerabilities that allow an attacker to enumerate bridge relays. Some bridge enumeration attacks still remain; see for example proposal 188. o Privacy/anonymity fixes (clients): - Clients and bridges no longer send TLS certificate chains on outgoing OR connections. Previously, each client or bridge would use the same cert chain for all outgoing OR connections until its IP address changes, which allowed any relay that the client or bridge contacted to determine which entry guards it is using. Fixes CVE-2011-2768. Bugfix on 0.0.9pre5; found by "frosty_un". - If a relay receives a CREATE_FAST cell on a TLS connection, it no longer considers that connection as suitable for satisfying a circuit EXTEND request. Now relays can protect clients from the CVE-2011-2768 issue even if the clients haven't upgraded yet. - Directory authorities no longer assign the Guard flag to relays that haven't upgraded to the above "refuse EXTEND requests to client connections" fix. Now directory authorities can protect clients from the CVE-2011-2768 issue even if neither the clients nor the relays have upgraded yet. There's a new "GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays" config option to let us transition smoothly, else tomorrow there would be no guard relays. o Privacy/anonymity fixes (bridge enumeration): - Bridge relays now do their directory fetches inside Tor TLS connections, like all the other clients do, rather than connecting directly to the DirPort like public relays do. Removes another avenue for enumerating bridges. Fixes bug 4115; bugfix on 0.2.0.35. - Bridges relays now build circuits for themselves in a more similar way to how clients build them. Removes another avenue for enumerating bridges. Fixes bug 4124; bugfix on 0.2.0.3-alpha, when bridges were introduced. - Bridges now refuse CREATE or CREATE_FAST cells on OR connections that they initiated. Relays could distinguish incoming bridge connections from client connections, creating another avenue for enumerating bridges. Fixes CVE-2011-2769. Bugfix on 0.2.0.3-alpha. Found by "frosty_un". o Major bugfixes: - Fix a crash bug when changing node restrictions while a DNS lookup is in-progress. Fixes bug 4259; bugfix on 0.2.2.25-alpha. Bugfix by "Tey'". - Don't launch a useless circuit after failing to use one of a hidden service's introduction points. Previously, we would launch a new introduction circuit, but not set the hidden service which that circuit was intended to connect to, so it would never actually be used. A different piece of code would then create a new introduction circuit correctly. Bug reported by katmagic and found by Sebastian Hahn. Bugfix on 0.2.1.13-alpha; fixes bug 4212. o Minor bugfixes: - Change an integer overflow check in the OpenBSD_Malloc code so that GCC is less likely to eliminate it as impossible. Patch from Mansour Moufid. Fixes bug 4059. - When a hidden service turns an extra service-side introduction circuit into a general-purpose circuit, free the rend_data and intro_key fields first, so we won't leak memory if the circuit is cannibalized for use as another service-side introduction circuit. Bugfix on 0.2.1.7-alpha; fixes bug 4251. - Bridges now skip DNS self-tests, to act a little more stealthily. Fixes bug 4201; bugfix on 0.2.0.3-alpha, which first introduced bridges. Patch by "warms0x". - Fix internal bug-checking logic that was supposed to catch failures in digest generation so that it will fail more robustly if we ask for a nonexistent algorithm. Found by Coverity Scan. Bugfix on 0.2.2.1-alpha; fixes Coverity CID 479. - Report any failure in init_keys() calls launched because our IP address has changed. Spotted by Coverity Scan. Bugfix on 0.1.1.4-alpha; fixes CID 484. o Minor bugfixes (log messages and documentation): - Remove a confusing dollar sign from the example fingerprint in the man page, and also make the example fingerprint a valid one. Fixes bug 4309; bugfix on 0.2.1.3-alpha. - The next version of Windows will be called Windows 8, and it has a major version of 6, minor version of 2. Correctly identify that version instead of calling it "Very recent version". Resolves ticket 4153; reported by funkstar. - Downgrade log messages about circuit timeout calibration from "notice" to "info": they don't require or suggest any human intervention. Patch from Tom Lowenthal. Fixes bug 4063; bugfix on 0.2.2.14-alpha. o Minor features: - Turn on directory request statistics by default and include them in extra-info descriptors. Don't break if we have no GeoIP database. Backported from 0.2.3.1-alpha; implements ticket 3951. - Update to the October 4 2011 Maxmind GeoLite Country database. Changes in version 0.2.1.31 - 2011-10-26 Tor 0.2.1.31 backports important security and privacy fixes for oldstable. This release is intended only for package maintainers and others who cannot use the 0.2.2 stable series. All others should be using Tor 0.2.2.x or newer. o Security fixes (also included in 0.2.2.x): - Replace all potentially sensitive memory comparison operations with versions whose runtime does not depend on the data being compared. This will help resist a class of attacks where an adversary can use variations in timing information to learn sensitive data. Fix for one case of bug 3122. (Safe memcmp implementation by Robert Ransom based partially on code by DJB.) - Fix an assert in parsing router descriptors containing IPv6 addresses. This one took down the directory authorities when somebody tried some experimental code. Bugfix on 0.2.1.3-alpha. o Privacy/anonymity fixes (also included in 0.2.2.x): - Clients and bridges no longer send TLS certificate chains on outgoing OR connections. Previously, each client or bridge would use the same cert chain for all outgoing OR connections until its IP address changes, which allowed any relay that the client or bridge contacted to determine which entry guards it is using. Fixes CVE-2011-2768. Bugfix on 0.0.9pre5; found by "frosty_un". - If a relay receives a CREATE_FAST cell on a TLS connection, it no longer considers that connection as suitable for satisfying a circuit EXTEND request. Now relays can protect clients from the CVE-2011-2768 issue even if the clients haven't upgraded yet. - Bridges now refuse CREATE or CREATE_FAST cells on OR connections that they initiated. Relays could distinguish incoming bridge connections from client connections, creating another avenue for enumerating bridges. Fixes CVE-2011-2769. Bugfix on 0.2.0.3-alpha. Found by "frosty_un". - When receiving a hidden service descriptor, check that it is for the hidden service we wanted. Previously, Tor would store any hidden service descriptors that a directory gave it, whether it wanted them or not. This wouldn't have let an attacker impersonate a hidden service, but it did let directories pre-seed a client with descriptors that it didn't want. Bugfix on 0.0.6. - Avoid linkability based on cached hidden service descriptors: forget all hidden service descriptors cached as a client when processing a SIGNAL NEWNYM command. Fixes bug 3000; bugfix on 0.0.6. - Make the bridge directory authority refuse to answer directory requests for "all" descriptors. It used to include bridge descriptors in its answer, which was a major information leak. Found by "piebeer". Bugfix on 0.2.0.3-alpha. - Don't attach new streams to old rendezvous circuits after SIGNAL NEWNYM. Previously, we would keep using an existing rendezvous circuit if it remained open (i.e. if it were kept open by a long-lived stream, or if a new stream were attached to it before Tor could notice that it was old and no longer in use). Bugfix on 0.1.1.15-rc; fixes bug 3375. o Minor bugfixes (also included in 0.2.2.x): - When we restart our relay, we might get a successful connection from the outside before we've started our reachability tests, triggering a warning: "ORPort found reachable, but I have no routerinfo yet. Failing to inform controller of success." This bug was harmless unless Tor is running under a controller like Vidalia, in which case the controller would never get a REACHABILITY_SUCCEEDED status event. Bugfix on 0.1.2.6-alpha; fixes bug 1172. - Build correctly on OSX with zlib 1.2.4 and higher with all warnings enabled. Fixes bug 1526. - Remove undocumented option "-F" from tor-resolve: it hasn't done anything since 0.2.1.16-rc. - Avoid signed/unsigned comparisons by making SIZE_T_CEILING unsigned. None of the cases where we did this before were wrong, but by making this change we avoid warnings. Fixes bug 2475; bugfix on 0.2.1.28. - Fix a rare crash bug that could occur when a client was configured with a large number of bridges. Fixes bug 2629; bugfix on 0.2.1.2-alpha. Bugfix by trac user "shitlei". - Correct the warning displayed when a rendezvous descriptor exceeds the maximum size. Fixes bug 2750; bugfix on 0.2.1.5-alpha. Found by John Brooks. - Fix an uncommon assertion failure when running with DNSPort under heavy load. Fixes bug 2933; bugfix on 0.2.0.1-alpha. - When warning about missing zlib development packages during compile, give the correct package names. Bugfix on 0.2.0.1-alpha. - Require that introduction point keys and onion keys have public exponent 65537. Bugfix on 0.2.0.10-alpha. - Do not crash when our configuration file becomes unreadable, for example due to a permissions change, between when we start up and when a controller calls SAVECONF. Fixes bug 3135; bugfix on 0.0.9pre6. - Fix warnings from GCC 4.6's "-Wunused-but-set-variable" option. Fixes bug 3208. - Always NUL-terminate the sun_path field of a sockaddr_un before passing it to the kernel. (Not a security issue: kernels are smart enough to reject bad sockaddr_uns.) Found by Coverity; CID #428. Bugfix on Tor 0.2.0.3-alpha. - Don't stack-allocate the list of supplementary GIDs when we're about to log them. Stack-allocating NGROUPS_MAX gid_t elements could take up to 256K, which is way too much stack. Found by Coverity; CID #450. Bugfix on 0.2.1.7-alpha. o Minor bugfixes (only in 0.2.1.x): - Resume using micro-version numbers in 0.2.1.x: our Debian packages rely on them. Bugfix on 0.2.1.30. - Use git revisions instead of svn revisions when generating our micro-version numbers. Bugfix on 0.2.1.15-rc; fixes bug 2402. o Minor features (also included in 0.2.2.x): - Adjust the expiration time on our SSL session certificates to better match SSL certs seen in the wild. Resolves ticket 4014. - Allow nameservers with IPv6 address. Resolves bug 2574. - Update to the October 4 2011 Maxmind GeoLite Country database. Changes in version 0.2.2.33 - 2011-09-13 Tor 0.2.2.33 fixes several bugs, and includes a slight tweak to Tor's TLS handshake that makes relays and bridges that run this new version reachable from Iran again. o Major bugfixes: - Avoid an assertion failure when reloading a configuration with TrackExitHosts changes. Found and fixed by 'laruldan'. Fixes bug 3923; bugfix on 0.2.2.25-alpha. o Minor features (security): - Check for replays of the public-key encrypted portion of an INTRODUCE1 cell, in addition to the current check for replays of the g^x value. This prevents a possible class of active attacks by an attacker who controls both an introduction point and a rendezvous point, and who uses the malleability of AES-CTR to alter the encrypted g^x portion of the INTRODUCE1 cell. We think that these attacks are infeasible (requiring the attacker to send on the order of zettabytes of altered cells in a short interval), but we'd rather block them off in case there are any classes of this attack that we missed. Reported by Willem Pinckaers. o Minor features: - Adjust the expiration time on our SSL session certificates to better match SSL certs seen in the wild. Resolves ticket 4014. - Change the default required uptime for a relay to be accepted as a HSDir (hidden service directory) from 24 hours to 25 hours. Improves on 0.2.0.10-alpha; resolves ticket 2649. - Add a VoteOnHidServDirectoriesV2 config option to allow directory authorities to abstain from voting on assignment of the HSDir consensus flag. Related to bug 2649. - Update to the September 6 2011 Maxmind GeoLite Country database. o Minor bugfixes (documentation and log messages): - Correct the man page to explain that HashedControlPassword and CookieAuthentication can both be set, in which case either method is sufficient to authenticate to Tor. Bugfix on 0.2.0.7-alpha, when we decided to allow these config options to both be set. Issue raised by bug 3898. - Demote the 'replay detected' log message emitted when a hidden service receives the same Diffie-Hellman public key in two different INTRODUCE2 cells to info level. A normal Tor client can cause that log message during its normal operation. Bugfix on 0.2.1.6-alpha; fixes part of bug 2442. - Demote the 'INTRODUCE2 cell is too {old,new}' log message to info level. There is nothing that a hidden service's operator can do to fix its clients' clocks. Bugfix on 0.2.1.6-alpha; fixes part of bug 2442. - Clarify a log message specifying the characters permitted in HiddenServiceAuthorizeClient client names. Previously, the log message said that "[A-Za-z0-9+-_]" were permitted; that could have given the impression that every ASCII character between "+" and "_" was permitted. Now we say "[A-Za-z0-9+_-]". Bugfix on 0.2.1.5-alpha. o Build fixes: - Provide a substitute implementation of lround() for MSVC, which apparently lacks it. Patch from Gisle Vanem. - Clean up some code issues that prevented Tor from building on older BSDs. Fixes bug 3894; reported by "grarpamp". - Search for a platform-specific version of "ar" when cross-compiling. Should fix builds on iOS. Resolves bug 3909, found by Marco Bonetti. Changes in version 0.2.2.32 - 2011-08-27 The Tor 0.2.2 release series is dedicated to the memory of Andreas Pfitzmann (1958-2010), a pioneer in anonymity and privacy research, a founder of the PETS community, a leader in our field, a mentor, and a friend. He left us with these words: "I had the possibility to contribute to this world that is not as it should be. I hope I could help in some areas to make the world a better place, and that I could also encourage other people to be engaged in improving the world. Please, stay engaged. This world needs you, your love, your initiative -- now I cannot be part of that anymore." Tor 0.2.2.32, the first stable release in the 0.2.2 branch, is finally ready. More than two years in the making, this release features improved client performance and hidden service reliability, better compatibility for Android, correct behavior for bridges that listen on more than one address, more extensible and flexible directory object handling, better reporting of network statistics, improved code security, and many many other features and bugfixes. o Major features (client performance): - When choosing which cells to relay first, relays now favor circuits that have been quiet recently, to provide lower latency for low-volume circuits. By default, relays enable or disable this feature based on a setting in the consensus. They can override this default by using the new "CircuitPriorityHalflife" config option. Design and code by Ian Goldberg, Can Tang, and Chris Alexander. - Directory authorities now compute consensus weightings that instruct clients how to weight relays flagged as Guard, Exit, Guard+Exit, and no flag. Clients use these weightings to distribute network load more evenly across these different relay types. The weightings are in the consensus so we can change them globally in the future. Extra thanks to "outofwords" for finding some nasty security bugs in the first implementation of this feature. o Major features (client performance, circuit build timeout): - Tor now tracks how long it takes to build client-side circuits over time, and adapts its timeout to local network performance. Since a circuit that takes a long time to build will also provide bad performance, we get significant latency improvements by discarding the slowest 20% of circuits. Specifically, Tor creates circuits more aggressively than usual until it has enough data points for a good timeout estimate. Implements proposal 151. - Circuit build timeout constants can be controlled by consensus parameters. We set good defaults for these parameters based on experimentation on broadband and simulated high-latency links. - Circuit build time learning can be disabled via consensus parameter or by the client via a LearnCircuitBuildTimeout config option. We also automatically disable circuit build time calculation if either AuthoritativeDirectory is set, or if we fail to write our state file. Implements ticket 1296. o Major features (relays use their capacity better): - Set SO_REUSEADDR socket option on all sockets, not just listeners. This should help busy exit nodes avoid running out of useable ports just because all the ports have been used in the near past. Resolves issue 2850. - Relays now save observed peak bandwidth throughput rates to their state file (along with total usage, which was already saved), so that they can determine their correct estimated bandwidth on restart. Resolves bug 1863, where Tor relays would reset their estimated bandwidth to 0 after restarting. - Lower the maximum weighted-fractional-uptime cutoff to 98%. This should give us approximately 40-50% more Guard-flagged nodes, improving the anonymity the Tor network can provide and also decreasing the dropoff in throughput that relays experience when they first get the Guard flag. - Directory authorities now take changes in router IP address and ORPort into account when determining router stability. Previously, if a router changed its IP or ORPort, the authorities would not treat it as having any downtime for the purposes of stability calculation, whereas clients would experience downtime since the change would take a while to propagate to them. Resolves issue 1035. - New AccelName and AccelDir options add support for dynamic OpenSSL hardware crypto acceleration engines. o Major features (relays control their load better): - Exit relays now try harder to block exit attempts from unknown relays, to make it harder for people to use them as one-hop proxies a la tortunnel. Controlled by the refuseunknownexits consensus parameter (currently enabled), or you can override it on your relay with the RefuseUnknownExits torrc option. Resolves bug 1751; based on a variant of proposal 163. - Add separate per-conn write limiting to go with the per-conn read limiting. We added a global write limit in Tor 0.1.2.5-alpha, but never per-conn write limits. - New consensus params "bwconnrate" and "bwconnburst" to let us rate-limit client connections as they enter the network. It's controlled in the consensus so we can turn it on and off for experiments. It's starting out off. Based on proposal 163. o Major features (controllers): - Export GeoIP information on bridge usage to controllers even if we have not yet been running for 24 hours. Now Vidalia bridge operators can get more accurate and immediate feedback about their contributions to the network. - Add an __OwningControllerProcess configuration option and a TAKEOWNERSHIP control-port command. Now a Tor controller can ensure that when it exits, Tor will shut down. Implements feature 3049. o Major features (directory authorities): - Directory authorities now create, vote on, and serve multiple parallel formats of directory data as part of their voting process. Partially implements Proposal 162: "Publish the consensus in multiple flavors". - Directory authorities now agree on and publish small summaries of router information that clients can use in place of regular server descriptors. This transition will allow Tor 0.2.3 clients to use far less bandwidth for downloading information about the network. Begins the implementation of Proposal 158: "Clients download consensus + microdescriptors". - The directory voting system is now extensible to use multiple hash algorithms for signatures and resource selection. Newer formats are signed with SHA256, with a possibility for moving to a better hash algorithm in the future. - Directory authorities can now vote on arbitary integer values as part of the consensus process. This is designed to help set network-wide parameters. Implements proposal 167. o Major features and bugfixes (node selection): - Revise and reconcile the meaning of the ExitNodes, EntryNodes, ExcludeEntryNodes, ExcludeExitNodes, ExcludeNodes, and Strict*Nodes options. Previously, we had been ambiguous in describing what counted as an "exit" node, and what operations exactly "StrictNodes 0" would permit. This created confusion when people saw nodes built through unexpected circuits, and made it hard to tell real bugs from surprises. Now the intended behavior is: . "Exit", in the context of ExitNodes and ExcludeExitNodes, means a node that delivers user traffic outside the Tor network. . "Entry", in the context of EntryNodes, means a node used as the first hop of a multihop circuit. It doesn't include direct connections to directory servers. . "ExcludeNodes" applies to all nodes. . "StrictNodes" changes the behavior of ExcludeNodes only. When StrictNodes is set, Tor should avoid all nodes listed in ExcludeNodes, even when it will make user requests fail. When StrictNodes is *not* set, then Tor should follow ExcludeNodes whenever it can, except when it must use an excluded node to perform self-tests, connect to a hidden service, provide a hidden service, fulfill a .exit request, upload directory information, or fetch directory information. Collectively, the changes to implement the behavior fix bug 1090. - If EntryNodes, ExitNodes, ExcludeNodes, or ExcludeExitNodes change during a config reload, mark and discard all our origin circuits. This fix should address edge cases where we change the config options and but then choose a circuit that we created before the change. - Make EntryNodes config option much more aggressive even when StrictNodes is not set. Before it would prepend your requested entrynodes to your list of guard nodes, but feel free to use others after that. Now it chooses only from your EntryNodes if any of those are available, and only falls back to others if a) they're all down and b) StrictNodes is not set. - Now we refresh your entry guards from EntryNodes at each consensus fetch -- rather than just at startup and then they slowly rot as the network changes. - Add support for the country code "{??}" in torrc options like ExcludeNodes, to indicate all routers of unknown country. Closes bug 1094. - ExcludeNodes now takes precedence over EntryNodes and ExitNodes: if a node is listed in both, it's treated as excluded. - ExcludeNodes now applies to directory nodes -- as a preference if StrictNodes is 0, or an absolute requirement if StrictNodes is 1. Don't exclude all the directory authorities and set StrictNodes to 1 unless you really want your Tor to break. - ExcludeNodes and ExcludeExitNodes now override exit enclaving. - ExcludeExitNodes now overrides .exit requests. - We don't use bridges listed in ExcludeNodes. - When StrictNodes is 1: . We now apply ExcludeNodes to hidden service introduction points and to rendezvous points selected by hidden service users. This can make your hidden service less reliable: use it with caution! . If we have used ExcludeNodes on ourself, do not try relay reachability self-tests. . If we have excluded all the directory authorities, we will not even try to upload our descriptor if we're a relay. . Do not honor .exit requests to an excluded node. - When the set of permitted nodes changes, we now remove any mappings introduced via TrackExitHosts to now-excluded nodes. Bugfix on 0.1.0.1-rc. - We never cannibalize a circuit that had excluded nodes on it, even if StrictNodes is 0. Bugfix on 0.1.0.1-rc. - Improve log messages related to excluded nodes. o Major features (misc): - Numerous changes, bugfixes, and workarounds from Nathan Freitas to help Tor build correctly for Android phones. - The options SocksPort, ControlPort, and so on now all accept a value "auto" that opens a socket on an OS-selected port. A new ControlPortWriteToFile option tells Tor to write its actual control port or ports to a chosen file. If the option ControlPortFileGroupReadable is set, the file is created as group-readable. Now users can run two Tor clients on the same system without needing to manually mess with parameters. Resolves part of ticket 3076. - Tor now supports tunneling all of its outgoing connections over a SOCKS proxy, using the SOCKS4Proxy and/or SOCKS5Proxy configuration options. Code by Christopher Davis. o Code security improvements: - Replace all potentially sensitive memory comparison operations with versions whose runtime does not depend on the data being compared. This will help resist a class of attacks where an adversary can use variations in timing information to learn sensitive data. Fix for one case of bug 3122. (Safe memcmp implementation by Robert Ransom based partially on code by DJB.) - Enable Address Space Layout Randomization (ASLR) and Data Execution Prevention (DEP) by default on Windows to make it harder for attackers to exploit vulnerabilities. Patch from John Brooks. - New "--enable-gcc-hardening" ./configure flag (off by default) to turn on gcc compile time hardening options. It ensures that signed ints have defined behavior (-fwrapv), enables -D_FORTIFY_SOURCE=2 (requiring -O2), adds stack smashing protection with canaries (-fstack-protector-all), turns on ASLR protection if supported by the kernel (-fPIE, -pie), and adds additional security related warnings. Verified to work on Mac OS X and Debian Lenny. - New "--enable-linker-hardening" ./configure flag (off by default) to turn on ELF specific hardening features (relro, now). This does not work with Mac OS X or any other non-ELF binary format. - Always search the Windows system directory for system DLLs, and nowhere else. Bugfix on 0.1.1.23; fixes bug 1954. - New DisableAllSwap option. If set to 1, Tor will attempt to lock all current and future memory pages via mlockall(). On supported platforms (modern Linux and probably BSD but not Windows or OS X), this should effectively disable any and all attempts to page out memory. This option requires that you start your Tor as root -- if you use DisableAllSwap, please consider using the User option to properly reduce the privileges of your Tor. o Major bugfixes (crashes): - Fix crash bug on platforms where gmtime and localtime can return NULL. Windows 7 users were running into this one. Fixes part of bug 2077. Bugfix on all versions of Tor. Found by boboper. - Introduce minimum/maximum values that clients will believe from the consensus. Now we'll have a better chance to avoid crashes or worse when a consensus param has a weird value. - Fix a rare crash bug that could occur when a client was configured with a large number of bridges. Fixes bug 2629; bugfix on 0.2.1.2-alpha. Bugfix by trac user "shitlei". - Do not crash when our configuration file becomes unreadable, for example due to a permissions change, between when we start up and when a controller calls SAVECONF. Fixes bug 3135; bugfix on 0.0.9pre6. - If we're in the pathological case where there's no exit bandwidth but there is non-exit bandwidth, or no guard bandwidth but there is non-guard bandwidth, don't crash during path selection. Bugfix on 0.2.0.3-alpha. - Fix a crash bug when trying to initialize the evdns module in Libevent 2. Bugfix on 0.2.1.16-rc. o Major bugfixes (stability): - Fix an assert in parsing router descriptors containing IPv6 addresses. This one took down the directory authorities when somebody tried some experimental code. Bugfix on 0.2.1.3-alpha. - Fix an uncommon assertion failure when running with DNSPort under heavy load. Fixes bug 2933; bugfix on 0.2.0.1-alpha. - Treat an unset $HOME like an empty $HOME rather than triggering an assert. Bugfix on 0.0.8pre1; fixes bug 1522. - More gracefully handle corrupt state files, removing asserts in favor of saving a backup and resetting state. - Instead of giving an assertion failure on an internal mismatch on estimated freelist size, just log a BUG warning and try later. Mitigates but does not fix bug 1125. - Fix an assert that got triggered when using the TestingTorNetwork configuration option and then issuing a GETINFO config-text control command. Fixes bug 2250; bugfix on 0.2.1.2-alpha. - If the cached cert file is unparseable, warn but don't exit. o Privacy fixes (relays/bridges): - Don't list Windows capabilities in relay descriptors. We never made use of them, and maybe it's a bad idea to publish them. Bugfix on 0.1.1.8-alpha. - If the Nickname configuration option isn't given, Tor would pick a nickname based on the local hostname as the nickname for a relay. Because nicknames are not very important in today's Tor and the "Unnamed" nickname has been implemented, this is now problematic behavior: It leaks information about the hostname without being useful at all. Fixes bug 2979; bugfix on 0.1.2.2-alpha, which introduced the Unnamed nickname. Reported by tagnaq. - Maintain separate TLS contexts and certificates for incoming and outgoing connections in bridge relays. Previously we would use the same TLS contexts and certs for incoming and outgoing connections. Bugfix on 0.2.0.3-alpha; addresses bug 988. - Maintain separate identity keys for incoming and outgoing TLS contexts in bridge relays. Previously we would use the same identity keys for incoming and outgoing TLS contexts. Bugfix on 0.2.0.3-alpha; addresses the other half of bug 988. - Make the bridge directory authority refuse to answer directory requests for "all descriptors". It used to include bridge descriptors in its answer, which was a major information leak. Found by "piebeer". Bugfix on 0.2.0.3-alpha. o Privacy fixes (clients): - When receiving a hidden service descriptor, check that it is for the hidden service we wanted. Previously, Tor would store any hidden service descriptors that a directory gave it, whether it wanted them or not. This wouldn't have let an attacker impersonate a hidden service, but it did let directories pre-seed a client with descriptors that it didn't want. Bugfix on 0.0.6. - Start the process of disabling ".exit" address notation, since it can be used for a variety of esoteric application-level attacks on users. To reenable it, set "AllowDotExit 1" in your torrc. Fix on 0.0.9rc5. - Reject attempts at the client side to open connections to private IP addresses (like 127.0.0.1, 10.0.0.1, and so on) with a randomly chosen exit node. Attempts to do so are always ill-defined, generally prevented by exit policies, and usually in error. This will also help to detect loops in transparent proxy configurations. You can disable this feature by setting "ClientRejectInternalAddresses 0" in your torrc. - Log a notice when we get a new control connection. Now it's easier for security-conscious users to recognize when a local application is knocking on their controller door. Suggested by bug 1196. o Privacy fixes (newnym): - Avoid linkability based on cached hidden service descriptors: forget all hidden service descriptors cached as a client when processing a SIGNAL NEWNYM command. Fixes bug 3000; bugfix on 0.0.6. - On SIGHUP, do not clear out all TrackHostExits mappings, client DNS cache entries, and virtual address mappings: that's what NEWNYM is for. Fixes bug 1345; bugfix on 0.1.0.1-rc. - Don't attach new streams to old rendezvous circuits after SIGNAL NEWNYM. Previously, we would keep using an existing rendezvous circuit if it remained open (i.e. if it were kept open by a long-lived stream, or if a new stream were attached to it before Tor could notice that it was old and no longer in use). Bugfix on 0.1.1.15-rc; fixes bug 3375. o Major bugfixes (relay bandwidth accounting): - Fix a bug that could break accounting on 64-bit systems with large time_t values, making them hibernate for impossibly long intervals. Fixes bug 2146. Bugfix on 0.0.9pre6; fix by boboper. - Fix a bug in bandwidth accounting that could make us use twice the intended bandwidth when our interval start changes due to daylight saving time. Now we tolerate skew in stored vs computed interval starts: if the start of the period changes by no more than 50% of the period's duration, we remember bytes that we transferred in the old period. Fixes bug 1511; bugfix on 0.0.9pre5. o Major bugfixes (bridges): - Bridges now use "reject *:*" as their default exit policy. Bugfix on 0.2.0.3-alpha. Fixes bug 1113. - If you configure your bridge with a known identity fingerprint, and the bridge authority is unreachable (as it is in at least one country now), fall back to directly requesting the descriptor from the bridge. Finishes the feature started in 0.2.0.10-alpha; closes bug 1138. - Fix a bug where bridge users who configure the non-canonical address of a bridge automatically switch to its canonical address. If a bridge listens at more than one address, it should be able to advertise those addresses independently and any non-blocked addresses should continue to work. Bugfix on Tor 0.2.0.3-alpha. Fixes bug 2510. - If you configure Tor to use bridge A, and then quit and configure Tor to use bridge B instead (or if you change Tor to use bridge B via the controller), it would happily continue to use bridge A if it's still reachable. While this behavior is a feature if your goal is connectivity, in some scenarios it's a dangerous bug. Bugfix on Tor 0.2.0.1-alpha; fixes bug 2511. - When the controller configures a new bridge, don't wait 10 to 60 seconds before trying to fetch its descriptor. Bugfix on 0.2.0.3-alpha; fixes bug 3198 (suggested by 2355). o Major bugfixes (directory authorities): - Many relays have been falling out of the consensus lately because not enough authorities know about their descriptor for them to get a majority of votes. When we deprecated the v2 directory protocol, we got rid of the only way that v3 authorities can hear from each other about other descriptors. Now authorities examine every v3 vote for new descriptors, and fetch them from that authority. Bugfix on 0.2.1.23. - Authorities could be tricked into giving out the Exit flag to relays that didn't allow exiting to any ports. This bug could screw with load balancing and stats. Bugfix on 0.1.1.6-alpha; fixes bug 1238. Bug discovered by Martin Kowalczyk. - If all authorities restart at once right before a consensus vote, nobody will vote about "Running", and clients will get a consensus with no usable relays. Instead, authorities refuse to build a consensus if this happens. Bugfix on 0.2.0.10-alpha; fixes bug 1066. o Major bugfixes (stream-level fairness): - When receiving a circuit-level SENDME for a blocked circuit, try to package cells fairly from all the streams that had previously been blocked on that circuit. Previously, we had started with the oldest stream, and allowed each stream to potentially exhaust the circuit's package window. This gave older streams on any given circuit priority over newer ones. Fixes bug 1937. Detected originally by Camilo Viecco. This bug was introduced before the first Tor release, in svn commit r152: it is the new winner of the longest-lived bug prize. - Fix a stream fairness bug that would cause newer streams on a given circuit to get preference when reading bytes from the origin or destination. Fixes bug 2210. Fix by Mashael AlSabah. This bug was introduced before the first Tor release, in svn revision r152. - When the exit relay got a circuit-level sendme cell, it started reading on the exit streams, even if had 500 cells queued in the circuit queue already, so the circuit queue just grew and grew in some cases. We fix this by not re-enabling reading on receipt of a sendme cell when the cell queue is blocked. Fixes bug 1653. Bugfix on 0.2.0.1-alpha. Detected by Mashael AlSabah. Original patch by "yetonetime". - Newly created streams were allowed to read cells onto circuits, even if the circuit's cell queue was blocked and waiting to drain. This created potential unfairness, as older streams would be blocked, but newer streams would gladly fill the queue completely. We add code to detect this situation and prevent any stream from getting more than one free cell. Bugfix on 0.2.0.1-alpha. Partially fixes bug 1298. o Major bugfixes (hidden services): - Apply circuit timeouts to opened hidden-service-related circuits based on the correct start time. Previously, we would apply the circuit build timeout based on time since the circuit's creation; it was supposed to be applied based on time since the circuit entered its current state. Bugfix on 0.0.6; fixes part of bug 1297. - Improve hidden service robustness: When we find that we have extended a hidden service's introduction circuit to a relay not listed as an introduction point in the HS descriptor we currently have, retry with an introduction point from the current descriptor. Previously we would just give up. Fixes bugs 1024 and 1930; bugfix on 0.2.0.10-alpha. - Directory authorities now use data collected from their own uptime observations when choosing whether to assign the HSDir flag to relays, instead of trusting the uptime value the relay reports in its descriptor. This change helps prevent an attack where a small set of nodes with frequently-changing identity keys can blackhole a hidden service. (Only authorities need upgrade; others will be fine once they do.) Bugfix on 0.2.0.10-alpha; fixes bug 2709. - Stop assigning the HSDir flag to relays that disable their DirPort (and thus will refuse to answer directory requests). This fix should dramatically improve the reachability of hidden services: hidden services and hidden service clients pick six HSDir relays to store and retrieve the hidden service descriptor, and currently about half of the HSDir relays will refuse to work. Bugfix on 0.2.0.10-alpha; fixes part of bug 1693. o Major bugfixes (misc): - Clients now stop trying to use an exit node associated with a given destination by TrackHostExits if they fail to reach that exit node. Fixes bug 2999. Bugfix on 0.2.0.20-rc. - Fix a regression that caused Tor to rebind its ports if it receives SIGHUP while hibernating. Bugfix in 0.1.1.6-alpha; closes bug 919. - Remove an extra pair of quotation marks around the error message in control-port STATUS_GENERAL BUG events. Bugfix on 0.1.2.6-alpha; fixes bug 3732. o Minor features (relays): - Ensure that no empty [dirreq-](read|write)-history lines are added to an extrainfo document. Implements ticket 2497. - When bandwidth accounting is enabled, be more generous with how much bandwidth we'll use up before entering "soft hibernation". Previously, we'd refuse new connections and circuits once we'd used up 95% of our allotment. Now, we use up 95% of our allotment, AND make sure that we have no more than 500MB (or 3 hours of expected traffic, whichever is lower) remaining before we enter soft hibernation. - Relays now log the reason for publishing a new relay descriptor, so we have a better chance of hunting down instances of bug 1810. Resolves ticket 3252. - Log a little more clearly about the times at which we're no longer accepting new connections (e.g. due to hibernating). Resolves bug 2181. - When AllowSingleHopExits is set, print a warning to explain to the relay operator why most clients are avoiding her relay. - Send END_STREAM_REASON_NOROUTE in response to EHOSTUNREACH errors. Clients before 0.2.1.27 didn't handle NOROUTE correctly, but such clients are already deprecated because of security bugs. o Minor features (network statistics): - Directory mirrors that set "DirReqStatistics 1" write statistics about directory requests to disk every 24 hours. As compared to the "--enable-geoip-stats" ./configure flag in 0.2.1.x, there are a few improvements: 1) stats are written to disk exactly every 24 hours; 2) estimated shares of v2 and v3 requests are determined as mean values, not at the end of a measurement period; 3) unresolved requests are listed with country code '??'; 4) directories also measure download times. - Exit nodes that set "ExitPortStatistics 1" write statistics on the number of exit streams and transferred bytes per port to disk every 24 hours. - Relays that set "CellStatistics 1" write statistics on how long cells spend in their circuit queues to disk every 24 hours. - Entry nodes that set "EntryStatistics 1" write statistics on the rough number and origins of connecting clients to disk every 24 hours. - Relays that write any of the above statistics to disk and set "ExtraInfoStatistics 1" include the past 24 hours of statistics in their extra-info documents. Implements proposal 166. o Minor features (GeoIP and statistics): - Provide a log message stating which geoip file we're parsing instead of just stating that we're parsing the geoip file. Implements ticket 2432. - Make sure every relay writes a state file at least every 12 hours. Previously, a relay could go for weeks without writing its state file, and on a crash could lose its bandwidth history, capacity estimates, client country statistics, and so on. Addresses bug 3012. - Relays report the number of bytes spent on answering directory requests in extra-info descriptors similar to {read,write}-history. Implements enhancement 1790. - Report only the top 10 ports in exit-port stats in order not to exceed the maximum extra-info descriptor length of 50 KB. Implements task 2196. - If writing the state file to disk fails, wait up to an hour before retrying again, rather than trying again each second. Fixes bug 2346; bugfix on Tor 0.1.1.3-alpha. - Delay geoip stats collection by bridges for 6 hours, not 2 hours, when we switch from being a public relay to a bridge. Otherwise there will still be clients that see the relay in their consensus, and the stats will end up wrong. Bugfix on 0.2.1.15-rc; fixes bug 932. - Update to the August 2 2011 Maxmind GeoLite Country database. o Minor features (clients): - When expiring circuits, use microsecond timers rather than one-second timers. This can avoid an unpleasant situation where a circuit is launched near the end of one second and expired right near the beginning of the next, and prevent fluctuations in circuit timeout values. - If we've configured EntryNodes and our network goes away and/or all our entrynodes get marked down, optimistically retry them all when a new socks application request appears. Fixes bug 1882. - Always perform router selections using weighted relay bandwidth, even if we don't need a high capacity circuit at the time. Non-fast circuits now only differ from fast ones in that they can use relays not marked with the Fast flag. This "feature" could turn out to be a horrible bug; we should investigate more before it goes into a stable release. - When we run out of directory information such that we can't build circuits, but then get enough that we can build circuits, log when we actually construct a circuit, so the user has a better chance of knowing what's going on. Fixes bug 1362. - Log SSL state transitions at debug level during handshake, and include SSL states in error messages. This may help debug future SSL handshake issues. o Minor features (directory authorities): - When a router changes IP address or port, authorities now launch a new reachability test for it. Implements ticket 1899. - Directory authorities now reject relays running any versions of Tor between 0.2.1.3-alpha and 0.2.1.18 inclusive; they have known bugs that keep RELAY_EARLY cells from working on rendezvous circuits. Followup to fix for bug 2081. - Directory authorities now reject relays running any version of Tor older than 0.2.0.26-rc. That version is the earliest that fetches current directory information correctly. Fixes bug 2156. - Directory authorities now do an immediate reachability check as soon as they hear about a new relay. This change should slightly reduce the time between setting up a relay and getting listed as running in the consensus. It should also improve the time between setting up a bridge and seeing use by bridge users. - Directory authorities no longer launch a TLS connection to every relay as they startup. Now that we have 2k+ descriptors cached, the resulting network hiccup is becoming a burden. Besides, authorities already avoid voting about Running for the first half hour of their uptime. - Directory authorities now log the source of a rejected POSTed v3 networkstatus vote, so we can track failures better. - Backport code from 0.2.3.x that allows directory authorities to clean their microdescriptor caches. Needed to resolve bug 2230. o Minor features (hidden services): - Use computed circuit-build timeouts to decide when to launch parallel introduction circuits for hidden services. (Previously, we would retry after 15 seconds.) - Don't allow v0 hidden service authorities to act as clients. Required by fix for bug 3000. - Ignore SIGNAL NEWNYM commands on relay-only Tor instances. Required by fix for bug 3000. - Make hidden services work better in private Tor networks by not requiring any uptime to join the hidden service descriptor DHT. Implements ticket 2088. - Log (at info level) when purging pieces of hidden-service-client state because of SIGNAL NEWNYM. o Minor features (controller interface): - New "GETINFO net/listeners/(type)" controller command to return a list of addresses and ports that are bound for listeners for a given connection type. This is useful when the user has configured "SocksPort auto" and the controller needs to know which port got chosen. Resolves another part of ticket 3076. - Have the controller interface give a more useful message than "Internal Error" in response to failed GETINFO requests. - Add a TIMEOUT_RATE keyword to the BUILDTIMEOUT_SET control port event, to give information on the current rate of circuit timeouts over our stored history. - The 'EXTENDCIRCUIT' control port command can now be used with a circ id of 0 and no path. This feature will cause Tor to build a new 'fast' general purpose circuit using its own path selection algorithms. - Added a BUILDTIMEOUT_SET controller event to describe changes to the circuit build timeout. - New controller command "getinfo config-text". It returns the contents that Tor would write if you send it a SAVECONF command, so the controller can write the file to disk itself. o Minor features (controller protocol): - Add a new ControlSocketsGroupWritable configuration option: when it is turned on, ControlSockets are group-writeable by the default group of the current user. Patch by Jérémy Bobbio; implements ticket 2972. - Tor now refuses to create a ControlSocket in a directory that is world-readable (or group-readable if ControlSocketsGroupWritable is 0). This is necessary because some operating systems do not enforce permissions on an AF_UNIX sockets. Permissions on the directory holding the socket, however, seems to work everywhere. - Warn when CookieAuthFileGroupReadable is set but CookieAuthFile is not. This would lead to a cookie that is still not group readable. Closes bug 1843. Suggested by katmagic. - Future-proof the controller protocol a bit by ignoring keyword arguments we do not recognize. o Minor features (more useful logging): - Revise most log messages that refer to nodes by nickname to instead use the "$key=nickname at address" format. This should be more useful, especially since nicknames are less and less likely to be unique. Resolves ticket 3045. - When an HTTPS proxy reports "403 Forbidden", we now explain what it means rather than calling it an unexpected status code. Closes bug 2503. Patch from Michael Yakubovich. - Rate-limit a warning about failures to download v2 networkstatus documents. Resolves part of bug 1352. - Rate-limit the "your application is giving Tor only an IP address" warning. Addresses bug 2000; bugfix on 0.0.8pre2. - Rate-limit "Failed to hand off onionskin" warnings. - When logging a rate-limited warning, we now mention how many messages got suppressed since the last warning. - Make the formerly ugly "2 unknown, 7 missing key, 0 good, 0 bad, 2 no signature, 4 required" messages about consensus signatures easier to read, and make sure they get logged at the same severity as the messages explaining which keys are which. Fixes bug 1290. - Don't warn when we have a consensus that we can't verify because of missing certificates, unless those certificates are ones that we have been trying and failing to download. Fixes bug 1145. o Minor features (log domains): - Add documentation for configuring logging at different severities in different log domains. We've had this feature since 0.2.1.1-alpha, but for some reason it never made it into the manpage. Fixes bug 2215. - Make it simpler to specify "All log domains except for A and B". Previously you needed to say "[*,~A,~B]". Now you can just say "[~A,~B]". - Add a "LogMessageDomains 1" option to include the domains of log messages along with the messages. Without this, there's no way to use log domains without reading the source or doing a lot of guessing. - Add a new "Handshake" log domain for activities that happen during the TLS handshake. o Minor features (build process): - Make compilation with clang possible when using "--enable-gcc-warnings" by removing two warning options that clang hasn't implemented yet and by fixing a few warnings. Resolves ticket 2696. - Detect platforms that brokenly use a signed size_t, and refuse to build there. Found and analyzed by doorss and rransom. - Fix a bunch of compile warnings revealed by mingw with gcc 4.5. Resolves bug 2314. - Add support for statically linking zlib by specifying "--enable-static-zlib", to go with our support for statically linking openssl and libevent. Resolves bug 1358. - Instead of adding the svn revision to the Tor version string, report the git commit (when we're building from a git checkout). - Rename the "log.h" header to "torlog.h" so as to conflict with fewer system headers. - New --digests command-line switch to output the digests of the source files Tor was built with. - Generate our manpage and HTML documentation using Asciidoc. This change should make it easier to maintain the documentation, and produce nicer HTML. The build process fails if asciidoc cannot be found and building with asciidoc isn't disabled (via the "--disable-asciidoc" argument to ./configure. Skipping the manpage speeds up the build considerably. o Minor features (options / torrc): - Warn when the same option is provided more than once in a torrc file, on the command line, or in a single SETCONF statement, and the option is one that only accepts a single line. Closes bug 1384. - Warn when the user configures two HiddenServiceDir lines that point to the same directory. Bugfix on 0.0.6 (the version introducing HiddenServiceDir); fixes bug 3289. - Add new "perconnbwrate" and "perconnbwburst" consensus params to do individual connection-level rate limiting of clients. The torrc config options with the same names trump the consensus params, if both are present. Replaces the old "bwconnrate" and "bwconnburst" consensus params which were broken from 0.2.2.7-alpha through 0.2.2.14-alpha. Closes bug 1947. - New config option "WarnUnsafeSocks 0" disables the warning that occurs whenever Tor receives a socks handshake using a version of the socks protocol that can only provide an IP address (rather than a hostname). Setups that do DNS locally over Tor are fine, and we shouldn't spam the logs in that case. - New config option "CircuitStreamTimeout" to override our internal timeout schedule for how many seconds until we detach a stream from a circuit and try a new circuit. If your network is particularly slow, you might want to set this to a number like 60. - New options for SafeLogging to allow scrubbing only log messages generated while acting as a relay. Specify "SafeLogging relay" if you want to ensure that only messages known to originate from client use of the Tor process will be logged unsafely. - Time and memory units in the configuration file can now be set to fractional units. For example, "2.5 GB" is now a valid value for AccountingMax. - Support line continuations in the torrc config file. If a line ends with a single backslash character, the newline is ignored, and the configuration value is treated as continuing on the next line. Resolves bug 1929. o Minor features (unit tests): - Revise our unit tests to use the "tinytest" framework, so we can run tests in their own processes, have smarter setup/teardown code, and so on. The unit test code has moved to its own subdirectory, and has been split into multiple modules. - Add a unit test for cross-platform directory-listing code. - Add some forgotten return value checks during unit tests. Found by coverity. - Use GetTempDir to find the proper temporary directory location on Windows when generating temporary files for the unit tests. Patch by Gisle Vanem. o Minor features (misc): - The "torify" script now uses torsocks where available. - Make Libevent log messages get delivered to controllers later, and not from inside the Libevent log handler. This prevents unsafe reentrant Libevent calls while still letting the log messages get through. - Certain Tor clients (such as those behind check.torproject.org) may want to fetch the consensus in an extra early manner. To enable this a user may now set FetchDirInfoExtraEarly to 1. This also depends on setting FetchDirInfoEarly to 1. Previous behavior will stay the same as only certain clients who must have this information sooner should set this option. - Expand homedirs passed to tor-checkkey. This should silence a coverity complaint about passing a user-supplied string into open() without checking it. - Make sure to disable DirPort if running as a bridge. DirPorts aren't used on bridges, and it makes bridge scanning somewhat easier. - Create the /var/run/tor directory on startup on OpenSUSE if it is not already created. Patch from Andreas Stieger. Fixes bug 2573. o Minor bugfixes (relays): - When a relay decides that its DNS is too broken for it to serve as an exit server, it advertised itself as a non-exit, but continued to act as an exit. This could create accidental partitioning opportunities for users. Instead, if a relay is going to advertise reject *:* as its exit policy, it should really act with exit policy "reject *:*". Fixes bug 2366. Bugfix on Tor 0.1.2.5-alpha. Bugfix by user "postman" on trac. - Publish a router descriptor even if generating an extra-info descriptor fails. Previously we would not publish a router descriptor without an extra-info descriptor; this can cause fast exit relays collecting exit-port statistics to drop from the consensus. Bugfix on 0.1.2.9-rc; fixes bug 2195. - When we're trying to guess whether we know our IP address as a relay, we would log various ways that we failed to guess our address, but never log that we ended up guessing it successfully. Now add a log line to help confused and anxious relay operators. Bugfix on 0.1.2.1-alpha; fixes bug 1534. - For bandwidth accounting, calculate our expected bandwidth rate based on the time during which we were active and not in soft-hibernation during the last interval. Previously, we were also considering the time spent in soft-hibernation. If this was a long time, we would wind up underestimating our bandwidth by a lot, and skewing our wakeup time towards the start of the accounting interval. Fixes bug 1789. Bugfix on 0.0.9pre5. - Demote a confusing TLS warning that relay operators might get when someone tries to talk to their ORPort. It is not the operator's fault, nor can they do anything about it. Fixes bug 1364; bugfix on 0.2.0.14-alpha. - Change "Application request when we're believed to be offline." notice to "Application request when we haven't used client functionality lately.", to clarify that it's not an error. Bugfix on 0.0.9.3; fixes bug 1222. o Minor bugfixes (bridges): - When a client starts or stops using bridges, never use a circuit that was built before the configuration change. This behavior could put at risk a user who uses bridges to ensure that her traffic only goes to the chosen addresses. Bugfix on 0.2.0.3-alpha; fixes bug 3200. - Do not reset the bridge descriptor download status every time we re-parse our configuration or get a configuration change. Fixes bug 3019; bugfix on 0.2.0.3-alpha. - Users couldn't configure a regular relay to be their bridge. It didn't work because when Tor fetched the bridge descriptor, it found that it already had it, and didn't realize that the purpose of the descriptor had changed. Now we replace routers with a purpose other than bridge with bridge descriptors when fetching them. Bugfix on 0.1.1.9-alpha. Fixes bug 1776. - In the special case where you configure a public exit relay as your bridge, Tor would be willing to use that exit relay as the last hop in your circuit as well. Now we fail that circuit instead. Bugfix on 0.2.0.12-alpha. Fixes bug 2403. Reported by "piebeer". o Minor bugfixes (clients): - We now ask the other side of a stream (the client or the exit) for more data on that stream when the amount of queued data on that stream dips low enough. Previously, we wouldn't ask the other side for more data until either it sent us more data (which it wasn't supposed to do if it had exhausted its window!) or we had completely flushed all our queued data. This flow control fix should improve throughput. Fixes bug 2756; bugfix on the earliest released versions of Tor (svn commit r152). - When a client finds that an origin circuit has run out of 16-bit stream IDs, we now mark it as unusable for new streams. Previously, we would try to close the entire circuit. Bugfix on 0.0.6. - Make it explicit that we don't cannibalize one-hop circuits. This happens in the wild, but doesn't turn out to be a problem because we fortunately don't use those circuits. Many thanks to outofwords for the initial analysis and to swissknife who confirmed that two-hop circuits are actually created. - Resolve an edge case in path weighting that could make us misweight our relay selection. Fixes bug 1203; bugfix on 0.0.8rc1. - Make the DNSPort option work with libevent 2.x. Don't alter the behaviour for libevent 1.x. Fixes bug 1143. Found by SwissTorExit. o Minor bugfixes (directory authorities): - Make directory authorities more accurate at recording when relays that have failed several reachability tests became unreachable, so we can provide more accuracy at assigning Stable, Guard, HSDir, etc flags. Bugfix on 0.2.0.6-alpha. Resolves bug 2716. - Directory authorities are now more robust to hops back in time when calculating router stability. Previously, if a run of uptime or downtime appeared to be negative, the calculation could give incorrect results. Bugfix on 0.2.0.6-alpha; noticed when fixing bug 1035. - Directory authorities will now attempt to download consensuses if their own efforts to make a live consensus have failed. This change means authorities that restart will fetch a valid consensus, and it means authorities that didn't agree with the current consensus will still fetch and serve it if it has enough signatures. Bugfix on 0.2.0.9-alpha; fixes bug 1300. - Never vote for a server as "Running" if we have a descriptor for it claiming to be hibernating, and that descriptor was published more recently than our last contact with the server. Bugfix on 0.2.0.3-alpha; fixes bug 911. - Directory authorities no longer change their opinion of, or vote on, whether a router is Running, unless they have themselves been online long enough to have some idea. Bugfix on 0.2.0.6-alpha. Fixes bug 1023. o Minor bugfixes (hidden services): - Log malformed requests for rendezvous descriptors as protocol warnings, not warnings. Also, use a more informative log message in case someone sees it at log level warning without prior info-level messages. Fixes bug 2748; bugfix on 0.2.0.10-alpha. - Accept hidden service descriptors if we think we might be a hidden service directory, regardless of what our consensus says. This helps robustness, since clients and hidden services can sometimes have a more up-to-date view of the network consensus than we do, and if they think that the directory authorities list us a HSDir, we might actually be one. Related to bug 2732; bugfix on 0.2.0.10-alpha. - Correct the warning displayed when a rendezvous descriptor exceeds the maximum size. Fixes bug 2750; bugfix on 0.2.1.5-alpha. Found by John Brooks. - Clients and hidden services now use HSDir-flagged relays for hidden service descriptor downloads and uploads even if the relays have no DirPort set and the client has disabled TunnelDirConns. This will eventually allow us to give the HSDir flag to relays with no DirPort. Fixes bug 2722; bugfix on 0.2.1.6-alpha. - Only limit the lengths of single HS descriptors, even when multiple HS descriptors are published to an HSDir relay in a single POST operation. Fixes bug 2948; bugfix on 0.2.1.5-alpha. Found by hsdir. o Minor bugfixes (controllers): - Allow GETINFO fingerprint to return a fingerprint even when we have not yet built a router descriptor. Fixes bug 3577; bugfix on 0.2.0.1-alpha. - Send a SUCCEEDED stream event to the controller when a reverse resolve succeeded. Fixes bug 3536; bugfix on 0.0.8pre1. Issue discovered by katmagic. - Remove a trailing asterisk from "exit-policy/default" in the output of the control port command "GETINFO info/names". Bugfix on 0.1.2.5-alpha. - Make the SIGNAL DUMP controller command work on FreeBSD. Fixes bug 2917. Bugfix on 0.1.1.1-alpha. - When we restart our relay, we might get a successful connection from the outside before we've started our reachability tests, triggering a warning: "ORPort found reachable, but I have no routerinfo yet. Failing to inform controller of success." This bug was harmless unless Tor is running under a controller like Vidalia, in which case the controller would never get a REACHABILITY_SUCCEEDED status event. Bugfix on 0.1.2.6-alpha; fixes bug 1172. - When a controller changes TrackHostExits, remove mappings for hosts that should no longer have their exits tracked. Bugfix on 0.1.0.1-rc. - When a controller changes VirtualAddrNetwork, remove any mappings for hosts that were automapped to the old network. Bugfix on 0.1.1.19-rc. - When a controller changes one of the AutomapHosts* options, remove any mappings for hosts that should no longer be automapped. Bugfix on 0.2.0.1-alpha. - Fix an off-by-one error in calculating some controller command argument lengths. Fortunately, this mistake is harmless since the controller code does redundant NUL termination too. Found by boboper. Bugfix on 0.1.1.1-alpha. - Fix a bug in the controller interface where "GETINFO ns/asdaskljkl" would return "551 Internal error" rather than "552 Unrecognized key ns/asdaskljkl". Bugfix on 0.1.2.3-alpha. - Don't spam the controller with events when we have no file descriptors available. Bugfix on 0.2.1.5-alpha. (Rate-limiting for log messages was already solved from bug 748.) - Emit a GUARD DROPPED controller event for a case we missed. - Ensure DNS requests launched by "RESOLVE" commands from the controller respect the __LeaveStreamsUnattached setconf options. The same goes for requests launched via DNSPort or transparent proxying. Bugfix on 0.2.0.1-alpha; fixes bug 1525. o Minor bugfixes (config options): - Tor used to limit HttpProxyAuthenticator values to 48 characters. Change the limit to 512 characters by removing base64 newlines. Fixes bug 2752. Fix by Michael Yakubovich. - Complain if PublishServerDescriptor is given multiple arguments that include 0 or 1. This configuration will be rejected in the future. Bugfix on 0.2.0.1-alpha; closes bug 1107. - Disallow BridgeRelay 1 and ORPort 0 at once in the configuration. Bugfix on 0.2.0.13-alpha; closes bug 928. o Minor bugfixes (log subsystem fixes): - When unable to format an address as a string, report its value as "???" rather than reusing the last formatted address. Bugfix on 0.2.1.5-alpha. - Be more consistent in our treatment of file system paths. "~" should get expanded to the user's home directory in the Log config option. Fixes bug 2971; bugfix on 0.2.0.1-alpha, which introduced the feature for the -f and --DataDirectory options. o Minor bugfixes (memory management): - Don't stack-allocate the list of supplementary GIDs when we're about to log them. Stack-allocating NGROUPS_MAX gid_t elements could take up to 256K, which is way too much stack. Found by Coverity; CID #450. Bugfix on 0.2.1.7-alpha. - Save a couple bytes in memory allocation every time we escape certain characters in a string. Patch from Florian Zumbiehl. o Minor bugfixes (protocol correctness): - When checking for 1024-bit keys, check for 1024 bits, not 128 bytes. This allows Tor to correctly discard keys of length 1017 through 1023. Bugfix on 0.0.9pre5. - Require that introduction point keys and onion handshake keys have a public exponent of 65537. Starts to fix bug 3207; bugfix on 0.2.0.10-alpha. - Handle SOCKS messages longer than 128 bytes long correctly, rather than waiting forever for them to finish. Fixes bug 2330; bugfix on 0.2.0.16-alpha. Found by doorss. - Never relay a cell for a circuit we have already destroyed. Between marking a circuit as closeable and finally closing it, it may have been possible for a few queued cells to get relayed, even though they would have been immediately dropped by the next OR in the circuit. Fixes bug 1184; bugfix on 0.2.0.1-alpha. - Never queue a cell for a circuit that's already been marked for close. - Fix a spec conformance issue: the network-status-version token must be the first token in a v3 consensus or vote. Discovered by "parakeep". Bugfix on 0.2.0.3-alpha. - A networkstatus vote must contain exactly one signature. Spec conformance issue. Bugfix on 0.2.0.3-alpha. - When asked about a DNS record type we don't support via a client DNSPort, reply with NOTIMPL rather than an empty reply. Patch by intrigeri. Fixes bug 3369; bugfix on 2.0.1-alpha. - Make more fields in the controller protocol case-insensitive, since control-spec.txt said they were. o Minor bugfixes (log messages): - Fix a log message that said "bits" while displaying a value in bytes. Found by wanoskarnet. Fixes bug 3318; bugfix on 0.2.0.1-alpha. - Downgrade "no current certificates known for authority" message from Notice to Info. Fixes bug 2899; bugfix on 0.2.0.10-alpha. - Correctly describe errors that occur when generating a TLS object. Previously we would attribute them to a failure while generating a TLS context. Patch by Robert Ransom. Bugfix on 0.1.0.4-rc; fixes bug 1994. - Fix an instance where a Tor directory mirror might accidentally log the IP address of a misbehaving Tor client. Bugfix on 0.1.0.1-rc. - Stop logging at severity 'warn' when some other Tor client tries to establish a circuit with us using weak DH keys. It's a protocol violation, but that doesn't mean ordinary users need to hear about it. Fixes the bug part of bug 1114. Bugfix on 0.1.0.13. - If your relay can't keep up with the number of incoming create cells, it would log one warning per failure into your logs. Limit warnings to 1 per minute. Bugfix on 0.0.2pre10; fixes bug 1042. o Minor bugfixes (build fixes): - Fix warnings from GCC 4.6's "-Wunused-but-set-variable" option. - When warning about missing zlib development packages during compile, give the correct package names. Bugfix on 0.2.0.1-alpha. - Fix warnings that newer versions of autoconf produce during ./autogen.sh. These warnings appear to be harmless in our case, but they were extremely verbose. Fixes bug 2020. - Squash a compile warning on OpenBSD. Reported by Tas; fixes bug 1848. o Minor bugfixes (portability): - Write several files in text mode, on OSes that distinguish text mode from binary mode (namely, Windows). These files are: 'buffer-stats', 'dirreq-stats', and 'entry-stats' on relays that collect those statistics; 'client_keys' and 'hostname' for hidden services that use authentication; and (in the tor-gencert utility) newly generated identity and signing keys. Previously, we wouldn't specify text mode or binary mode, leading to an assertion failure. Fixes bug 3607. Bugfix on 0.2.1.1-alpha (when the DirRecordUsageByCountry option which would have triggered the assertion failure was added), although this assertion failure would have occurred in tor-gencert on Windows in 0.2.0.1-alpha. - Selectively disable deprecation warnings on OS X because Lion started deprecating the shipped copy of openssl. Fixes bug 3643. - Use a wide type to hold sockets when built for 64-bit Windows. Fixes bug 3270. - Fix an issue that prevented static linking of libevent on some platforms (notably Linux). Fixes bug 2698; bugfix on 0.2.1.23, where we introduced the "--with-static-libevent" configure option. - Fix a bug with our locking implementation on Windows that couldn't correctly detect when a file was already locked. Fixes bug 2504, bugfix on 0.2.1.6-alpha. - Build correctly on OSX with zlib 1.2.4 and higher with all warnings enabled. - Fix IPv6-related connect() failures on some platforms (BSD, OS X). Bugfix on 0.2.0.3-alpha; fixes first part of bug 2660. Patch by "piebeer". o Minor bugfixes (code correctness): - Always NUL-terminate the sun_path field of a sockaddr_un before passing it to the kernel. (Not a security issue: kernels are smart enough to reject bad sockaddr_uns.) Found by Coverity; CID #428. Bugfix on Tor 0.2.0.3-alpha. - Make connection_printf_to_buf()'s behaviour sane. Its callers expect it to emit a CRLF iff the format string ends with CRLF; it actually emitted a CRLF iff (a) the format string ended with CRLF or (b) the resulting string was over 1023 characters long or (c) the format string did not end with CRLF *and* the resulting string was 1021 characters long or longer. Bugfix on 0.1.1.9-alpha; fixes part of bug 3407. - Make send_control_event_impl()'s behaviour sane. Its callers expect it to always emit a CRLF at the end of the string; it might have emitted extra control characters as well. Bugfix on 0.1.1.9-alpha; fixes another part of bug 3407. - Make crypto_rand_int() check the value of its input correctly. Previously, it accepted values up to UINT_MAX, but could return a negative number if given a value above INT_MAX+1. Found by George Kadianakis. Fixes bug 3306; bugfix on 0.2.2pre14. - Fix a potential null-pointer dereference while computing a consensus. Bugfix on tor-0.2.0.3-alpha, found with the help of clang's analyzer. - If we fail to compute the identity digest of a v3 legacy keypair, warn, and don't use a buffer-full of junk instead. Bugfix on 0.2.1.1-alpha; fixes bug 3106. - Resolve an untriggerable issue in smartlist_string_num_isin(), where if the function had ever in the future been used to check for the presence of a too-large number, it would have given an incorrect result. (Fortunately, we only used it for 16-bit values.) Fixes bug 3175; bugfix on 0.1.0.1-rc. - Be more careful about reporting the correct error from a failed connect() system call. Under some circumstances, it was possible to look at an incorrect value for errno when sending the end reason. Bugfix on 0.1.0.1-rc. - Correctly handle an "impossible" overflow cases in connection byte counting, where we write or read more than 4GB on an edge connection in a single second. Bugfix on 0.1.2.8-beta. - Avoid a double mark-for-free warning when failing to attach a transparent proxy connection. Bugfix on 0.1.2.1-alpha. Fixes bug 2279. - Correctly detect failure to allocate an OpenSSL BIO. Fixes bug 2378; found by "cypherpunks". This bug was introduced before the first Tor release, in svn commit r110. - Fix a bug in bandwidth history state parsing that could have been triggered if a future version of Tor ever changed the timing granularity at which bandwidth history is measured. Bugfix on Tor 0.1.1.11-alpha. - Add assertions to check for overflow in arguments to base32_encode() and base32_decode(); fix a signed-unsigned comparison there too. These bugs are not actually reachable in Tor, but it's good to prevent future errors too. Found by doorss. - Avoid a bogus overlapped memcpy in tor_addr_copy(). Reported by "memcpyfail". - Set target port in get_interface_address6() correctly. Bugfix on 0.1.1.4-alpha and 0.2.0.3-alpha; fixes second part of bug 2660. - Fix an impossible-to-actually-trigger buffer overflow in relay descriptor generation. Bugfix on 0.1.0.15. - Fix numerous small code-flaws found by Coverity Scan Rung 3. o Minor bugfixes (code improvements): - After we free an internal connection structure, overwrite it with a different memory value than we use for overwriting a freed internal circuit structure. Should help with debugging. Suggested by bug 1055. - If OpenSSL fails to make a duplicate of a private or public key, log an error message and try to exit cleanly. May help with debugging if bug 1209 ever remanifests. - Some options used different conventions for uppercasing of acronyms when comparing manpage and source. Fix those in favor of the manpage, as it makes sense to capitalize acronyms. - Take a first step towards making or.h smaller by splitting out function definitions for all source files in src/or/. Leave structures and defines in or.h for now. - Remove a few dead assignments during router parsing. Found by coverity. - Don't use 1-bit wide signed bit fields. Found by coverity. - Avoid signed/unsigned comparisons by making SIZE_T_CEILING unsigned. None of the cases where we did this before were wrong, but by making this change we avoid warnings. Fixes bug 2475; bugfix on 0.2.1.28. - The memarea code now uses a sentinel value at the end of each area to make sure nothing writes beyond the end of an area. This might help debug some conceivable causes of bug 930. - Always treat failure to allocate an RSA key as an unrecoverable allocation error. - Add some more defensive programming for architectures that can't handle unaligned integer accesses. We don't know of any actual bugs right now, but that's the best time to fix them. Fixes bug 1943. o Minor bugfixes (misc): - Fix a rare bug in rend_fn unit tests: we would fail a test when a randomly generated port is 0. Diagnosed by Matt Edman. Bugfix on 0.2.0.10-alpha; fixes bug 1808. - Where available, use Libevent 2.0's periodic timers so that our once-per-second cleanup code gets called even more closely to once per second than it would otherwise. Fixes bug 943. - Ignore OutboundBindAddress when connecting to localhost. Connections to localhost need to come _from_ localhost, or else local servers (like DNS and outgoing HTTP/SOCKS proxies) will often refuse to listen. - Update our OpenSSL 0.9.8l fix so that it works with OpenSSL 0.9.8m too. - If any of the v3 certs we download are unparseable, we should actually notice the failure so we don't retry indefinitely. Bugfix on 0.2.0.x; reported by "rotator". - When Tor fails to parse a descriptor of any kind, dump it to disk. Might help diagnosing bug 1051. - Make our 'torify' script more portable; if we have only one of 'torsocks' or 'tsocks' installed, don't complain to the user; and explain our warning about tsocks better. - Fix some urls in the exit notice file and make it XHTML1.1 strict compliant. Based on a patch from Christian Kujau. o Documentation changes: - Modernize the doxygen configuration file slightly. Fixes bug 2707. - Resolve all doxygen warnings except those for missing documentation. Fixes bug 2705. - Add doxygen documentation for more functions, fields, and types. - Convert the HACKING file to asciidoc, and add a few new sections to it, explaining how we use Git, how we make changelogs, and what should go in a patch. - Document the default socks host and port (127.0.0.1:9050) for tor-resolve. - Removed some unnecessary files from the source distribution. The AUTHORS file has now been merged into the people page on the website. The roadmaps and design doc can now be found in the projects directory in svn. o Deprecated and removed features (config): - Remove the torrc.complete file. It hasn't been kept up to date and users will have better luck checking out the manpage. - Remove the HSAuthorityRecordStats option that version 0 hidden service authorities could use to track statistics of overall v0 hidden service usage. - Remove the obsolete "NoPublish" option; it has been flagged as obsolete and has produced a warning since 0.1.1.18-rc. - Caches no longer download and serve v2 networkstatus documents unless FetchV2Networkstatus flag is set: these documents haven't haven't been used by clients or relays since 0.2.0.x. Resolves bug 3022. o Deprecated and removed features (controller): - The controller no longer accepts the old obsolete "addr-mappings/" or "unregistered-servers-" GETINFO values. - The EXTENDED_EVENTS and VERBOSE_NAMES controller features are now always on; using them is necessary for correct forward-compatible controllers. o Deprecated and removed features (misc): - Hidden services no longer publish version 0 descriptors, and clients do not request or use version 0 descriptors. However, the old hidden service authorities still accept and serve version 0 descriptors when contacted by older hidden services/clients. - Remove undocumented option "-F" from tor-resolve: it hasn't done anything since 0.2.1.16-rc. - Remove everything related to building the expert bundle for OS X. It has confused many users, doesn't work right on OS X 10.6, and is hard to get rid of once installed. Resolves bug 1274. - Remove support for .noconnect style addresses. Nobody was using them, and they provided another avenue for detecting Tor users via application-level web tricks. - When we fixed bug 1038 we had to put in a restriction not to send RELAY_EARLY cells on rend circuits. This was necessary as long as relays using Tor 0.2.1.3-alpha through 0.2.1.18-alpha were active. Now remove this obsolete check. Resolves bug 2081. - Remove workaround code to handle directory responses from servers that had bug 539 (they would send HTTP status 503 responses _and_ send a body too). Since only server versions before 0.2.0.16-alpha/0.1.2.19 were affected, there is no longer reason to keep the workaround in place. - Remove the old 'fuzzy time' logic. It was supposed to be used for handling calculations where we have a known amount of clock skew and an allowed amount of unknown skew. But we only used it in three places, and we never adjusted the known/unknown skew values. This is still something we might want to do someday, but if we do, we'll want to do it differently. - Remove the "--enable-iphone" option to ./configure. According to reports from Marco Bonetti, Tor builds fine without any special tweaking on recent iPhone SDK versions. Changes in version 0.2.1.30 - 2011-02-23 Tor 0.2.1.30 fixes a variety of less critical bugs. The main other change is a slight tweak to Tor's TLS handshake that makes relays and bridges that run this new version reachable from Iran again. We don't expect this tweak will win the arms race long-term, but it buys us time until we roll out a better solution. o Major bugfixes: - Stop sending a CLOCK_SKEW controller status event whenever we fetch directory information from a relay that has a wrong clock. Instead, only inform the controller when it's a trusted authority that claims our clock is wrong. Bugfix on 0.1.2.6-alpha; fixes the rest of bug 1074. - Fix a bounds-checking error that could allow an attacker to remotely crash a directory authority. Bugfix on 0.2.1.5-alpha. Found by "piebeer". - If relays set RelayBandwidthBurst but not RelayBandwidthRate, Tor would ignore their RelayBandwidthBurst setting, potentially using more bandwidth than expected. Bugfix on 0.2.0.1-alpha. Reported by Paul Wouters. Fixes bug 2470. - Ignore and warn if the user mistakenly sets "PublishServerDescriptor hidserv" in her torrc. The 'hidserv' argument never controlled publication of hidden service descriptors. Bugfix on 0.2.0.1-alpha. o Minor features: - Adjust our TLS Diffie-Hellman parameters to match those used by Apache's mod_ssl. - Update to the February 1 2011 Maxmind GeoLite Country database. o Minor bugfixes: - Check for and reject overly long directory certificates and directory tokens before they have a chance to hit any assertions. Bugfix on 0.2.1.28. Found by "doorss". - Bring the logic that gathers routerinfos and assesses the acceptability of circuits into line. This prevents a Tor OP from getting locked in a cycle of choosing its local OR as an exit for a path (due to a .exit request) and then rejecting the circuit because its OR is not listed yet. It also prevents Tor clients from using an OR running in the same instance as an exit (due to a .exit request) if the OR does not meet the same requirements expected of an OR running elsewhere. Fixes bug 1859; bugfix on 0.1.0.1-rc. o Packaging changes: - Stop shipping the Tor specs files and development proposal documents in the tarball. They are now in a separate git repository at git://git.torproject.org/torspec.git - Do not include Git version tags as though they are SVN tags when generating a tarball from inside a repository that has switched between branches. Bugfix on 0.2.1.15-rc; fixes bug 2402. Changes in version 0.2.1.29 - 2011-01-15 Tor 0.2.1.29 continues our recent code security audit work. The main fix resolves a remote heap overflow vulnerability that can allow remote code execution. Other fixes address a variety of assert and crash bugs, most of which we think are hard to exploit remotely. o Major bugfixes (security): - Fix a heap overflow bug where an adversary could cause heap corruption. This bug probably allows remote code execution attacks. Reported by "debuger". Fixes CVE-2011-0427. Bugfix on 0.1.2.10-rc. - Prevent a denial-of-service attack by disallowing any zlib-compressed data whose compression factor is implausibly high. Fixes part of bug 2324; reported by "doorss". - Zero out a few more keys in memory before freeing them. Fixes bug 2384 and part of bug 2385. These key instances found by "cypherpunks", based on Andrew Case's report about being able to find sensitive data in Tor's memory space if you have enough permissions. Bugfix on 0.0.2pre9. o Major bugfixes (crashes): - Prevent calls to Libevent from inside Libevent log handlers. This had potential to cause a nasty set of crashes, especially if running Libevent with debug logging enabled, and running Tor with a controller watching for low-severity log messages. Bugfix on 0.1.0.2-rc. Fixes bug 2190. - Add a check for SIZE_T_MAX to tor_realloc() to try to avoid underflow errors there too. Fixes the other part of bug 2324. - Fix a bug where we would assert if we ever had a cached-descriptors.new file (or another file read directly into memory) of exactly SIZE_T_CEILING bytes. Fixes bug 2326; bugfix on 0.2.1.25. Found by doorss. - Fix some potential asserts and parsing issues with grossly malformed router caches. Fixes bug 2352; bugfix on Tor 0.2.1.27. Found by doorss. o Minor bugfixes (other): - Fix a bug with handling misformed replies to reverse DNS lookup requests in DNSPort. Bugfix on Tor 0.2.0.1-alpha. Related to a bug reported by doorss. - Fix compilation on mingw when a pthreads compatibility library has been installed. (We don't want to use it, so we shouldn't be including pthread.h.) Fixes bug 2313; bugfix on 0.1.0.1-rc. - Fix a bug where we would declare that we had run out of virtual addresses when the address space was only half-exhausted. Bugfix on 0.1.2.1-alpha. - Correctly handle the case where AutomapHostsOnResolve is set but no virtual addresses are available. Fixes bug 2328; bugfix on 0.1.2.1-alpha. Bug found by doorss. - Correctly handle wrapping around when we run out of virtual address space. Found by cypherpunks; bugfix on 0.2.0.5-alpha. o Minor features: - Update to the January 1 2011 Maxmind GeoLite Country database. - Introduce output size checks on all of our decryption functions. o Build changes: - Tor does not build packages correctly with Automake 1.6 and earlier; added a check to Makefile.am to make sure that we're building with Automake 1.7 or later. - The 0.2.1.28 tarball was missing src/common/OpenBSD_malloc_Linux.c because we built it with a too-old version of automake. Thus that release broke ./configure --enable-openbsd-malloc, which is popular among really fast exit relays on Linux. Changes in version 0.2.1.28 - 2010-12-17 Tor 0.2.1.28 does some code cleanup to reduce the risk of remotely exploitable bugs. We also took this opportunity to change the IP address for one of our directory authorities, and to update the geoip database we ship. o Major bugfixes: - Fix a remotely exploitable bug that could be used to crash instances of Tor remotely by overflowing on the heap. Remote-code execution hasn't been confirmed, but can't be ruled out. Everyone should upgrade. Bugfix on the 0.1.1 series and later. o Directory authority changes: - Change IP address and ports for gabelmoo (v3 directory authority). o Minor features: - Update to the December 1 2010 Maxmind GeoLite Country database. Changes in version 0.2.1.27 - 2010-11-23 Yet another OpenSSL security patch broke its compatibility with Tor: Tor 0.2.1.27 makes relays work with openssl 0.9.8p and 1.0.0.b. We also took this opportunity to fix several crash bugs, integrate a new directory authority, and update the bundled GeoIP database. o Major bugfixes: - Resolve an incompatibility with OpenSSL 0.9.8p and OpenSSL 1.0.0b: No longer set the tlsext_host_name extension on server SSL objects; but continue to set it on client SSL objects. Our goal in setting it was to imitate a browser, not a vhosting server. Fixes bug 2204; bugfix on 0.2.1.1-alpha. - Do not log messages to the controller while shrinking buffer freelists. Doing so would sometimes make the controller connection try to allocate a buffer chunk, which would mess up the internals of the freelist and cause an assertion failure. Fixes bug 1125; fixed by Robert Ransom. Bugfix on 0.2.0.16-alpha. - Learn our external IP address when we're a relay or bridge, even if we set PublishServerDescriptor to 0. Bugfix on 0.2.0.3-alpha, where we introduced bridge relays that don't need to publish to be useful. Fixes bug 2050. - Do even more to reject (and not just ignore) annotations on router descriptors received anywhere but from the cache. Previously we would ignore such annotations at first, but cache them to disk anyway. Bugfix on 0.2.0.8-alpha. Found by piebeer. - When you're using bridges and your network goes away and your bridges get marked as down, recover when you attempt a new socks connection (if the network is back), rather than waiting up to an hour to try fetching new descriptors for your bridges. Bugfix on 0.2.0.3-alpha; fixes bug 1981. o Major features: - Move to the November 2010 Maxmind GeoLite country db (rather than the June 2009 ip-to-country GeoIP db) for our statistics that count how many users relays are seeing from each country. Now we'll have more accurate data, especially for many African countries. o New directory authorities: - Set up maatuska (run by Linus Nordberg) as the eighth v3 directory authority. o Minor bugfixes: - Fix an assertion failure that could occur in directory caches or bridge users when using a very short voting interval on a testing network. Diagnosed by Robert Hogan. Fixes bug 1141; bugfix on 0.2.0.8-alpha. - Enforce multiplicity rules when parsing annotations. Bugfix on 0.2.0.8-alpha. Found by piebeer. - Allow handshaking OR connections to take a full KeepalivePeriod seconds to handshake. Previously, we would close them after IDLE_OR_CONN_TIMEOUT (180) seconds, the same timeout as if they were open. Bugfix on 0.2.1.26; fixes bug 1840. Thanks to mingw-san for analysis help. - When building with --enable-gcc-warnings on OpenBSD, disable warnings in system headers. This makes --enable-gcc-warnings pass on OpenBSD 4.8. o Minor features: - Exit nodes didn't recognize EHOSTUNREACH as a plausible error code, and so sent back END_STREAM_REASON_MISC. Clients now recognize a new stream ending reason for this case: END_STREAM_REASON_NOROUTE. Servers can start sending this code when enough clients recognize it. Bugfix on 0.1.0.1-rc; fixes part of bug 1793. - Build correctly on mingw with more recent versions of OpenSSL 0.9.8. Patch from mingw-san. o Removed files: - Remove the old debian/ directory from the main Tor distribution. The official Tor-for-debian git repository lives at the URL https://git.torproject.org/debian/tor.git - Stop shipping the old doc/website/ directory in the tarball. We changed the website format in late 2010, and what we shipped in 0.2.1.26 really wasn't that useful anyway. Changes in version 0.2.1.26 - 2010-05-02 Tor 0.2.1.26 addresses the recent connection and memory overload problems we've been seeing on relays, especially relays with their DirPort open. If your relay has been crashing, or you turned it off because it used too many resources, give this release a try. This release also fixes yet another instance of broken OpenSSL libraries that was causing some relays to drop out of the consensus. o Major bugfixes: - Teach relays to defend themselves from connection overload. Relays now close idle circuits early if it looks like they were intended for directory fetches. Relays are also more aggressive about closing TLS connections that have no circuits on them. Such circuits are unlikely to be re-used, and tens of thousands of them were piling up at the fast relays, causing the relays to run out of sockets and memory. Bugfix on 0.2.0.22-rc (where clients started tunneling their directory fetches over TLS). - Fix SSL renegotiation behavior on OpenSSL versions like on Centos that claim to be earlier than 0.9.8m, but which have in reality backported huge swaths of 0.9.8m or 0.9.8n renegotiation behavior. Possible fix for some cases of bug 1346. - Directory mirrors were fetching relay descriptors only from v2 directory authorities, rather than v3 authorities like they should. Only 2 v2 authorities remain (compared to 7 v3 authorities), leading to a serious bottleneck. Bugfix on 0.2.0.9-alpha. Fixes bug 1324. o Minor bugfixes: - Finally get rid of the deprecated and now harmful notion of "clique mode", where directory authorities maintain TLS connections to every other relay. o Testsuite fixes: - In the util/threads test, no longer free the test_mutex before all worker threads have finished. Bugfix on 0.2.1.6-alpha. - The master thread could starve the worker threads quite badly on certain systems, causing them to run only partially in the allowed window. This resulted in test failures. Now the master thread sleeps occasionally for a few microseconds while the two worker-threads compete for the mutex. Bugfix on 0.2.0.1-alpha. Changes in version 0.2.1.25 - 2010-03-16 Tor 0.2.1.25 fixes a regression introduced in 0.2.1.23 that could prevent relays from guessing their IP address correctly. It also fixes several minor potential security bugs. o Major bugfixes: - Fix a regression from our patch for bug 1244 that caused relays to guess their IP address incorrectly if they didn't set Address in their torrc and/or their address fails to resolve. Bugfix on 0.2.1.23; fixes bug 1269. - When freeing a session key, zero it out completely. We only zeroed the first ptrsize bytes. Bugfix on 0.0.2pre8. Discovered and patched by ekir. Fixes bug 1254. o Minor bugfixes: - Fix a dereference-then-NULL-check sequence when publishing descriptors. Bugfix on 0.2.1.5-alpha. Discovered by ekir; fixes bug 1255. - Fix another dereference-then-NULL-check sequence. Bugfix on 0.2.1.14-rc. Discovered by ekir; fixes bug 1256. - Make sure we treat potentially not NUL-terminated strings correctly. Bugfix on 0.1.1.13-alpha. Discovered by rieo; fixes bug 1257. Changes in version 0.2.1.24 - 2010-02-21 Tor 0.2.1.24 makes Tor work again on the latest OS X -- this time for sure! o Minor bugfixes: - Work correctly out-of-the-box with even more vendor-patched versions of OpenSSL. In particular, make it so Debian and OS X don't need customized patches to run/build. Changes in version 0.2.1.23 - 2010-02-13 Tor 0.2.1.23 fixes a huge client-side performance bug, makes Tor work again on the latest OS X, and updates the location of a directory authority. o Major bugfixes (performance): - We were selecting our guards uniformly at random, and then weighting which of our guards we'd use uniformly at random. This imbalance meant that Tor clients were severely limited on throughput (and probably latency too) by the first hop in their circuit. Now we select guards weighted by currently advertised bandwidth. We also automatically discard guards picked using the old algorithm. Fixes bug 1217; bugfix on 0.2.1.3-alpha. Found by Mike Perry. o Major bugfixes: - Make Tor work again on the latest OS X: when deciding whether to use strange flags to turn TLS renegotiation on, detect the OpenSSL version at run-time, not compile time. We need to do this because Apple doesn't update its dev-tools headers when it updates its libraries in a security patch. - Fix a potential buffer overflow in lookup_last_hid_serv_request() that could happen on 32-bit platforms with 64-bit time_t. Also fix a memory leak when requesting a hidden service descriptor we've requested before. Fixes bug 1242, bugfix on 0.2.0.18-alpha. Found by aakova. o Minor bugfixes: - Refactor resolve_my_address() to not use gethostbyname() anymore. Fixes bug 1244; bugfix on 0.0.2pre25. Reported by Mike Mestnik. o Minor features: - Avoid a mad rush at the beginning of each month when each client rotates half of its guards. Instead we spread the rotation out throughout the month, but we still avoid leaving a precise timestamp in the state file about when we first picked the guard. Improves over the behavior introduced in 0.1.2.17. Changes in version 0.2.1.22 - 2010-01-19 Tor 0.2.1.22 fixes a critical privacy problem in bridge directory authorities -- it would tell you its whole history of bridge descriptors if you make the right directory request. This stable update also rotates two of the seven v3 directory authority keys and locations. o Directory authority changes: - Rotate keys (both v3 identity and relay identity) for moria1 and gabelmoo. o Major bugfixes: - Stop bridge directory authorities from answering dbg-stability.txt directory queries, which would let people fetch a list of all bridge identities they track. Bugfix on 0.2.1.6-alpha. Changes in version 0.2.1.21 - 2009-12-21 Tor 0.2.1.21 fixes an incompatibility with the most recent OpenSSL library. If you use Tor on Linux / Unix and you're getting SSL renegotiation errors, upgrading should help. We also recommend an upgrade if you're an exit relay. o Major bugfixes: - Work around a security feature in OpenSSL 0.9.8l that prevents our handshake from working unless we explicitly tell OpenSSL that we are using SSL renegotiation safely. We are, of course, but OpenSSL 0.9.8l won't work unless we say we are. - Avoid crashing if the client is trying to upload many bytes and the circuit gets torn down at the same time, or if the flip side happens on the exit relay. Bugfix on 0.2.0.1-alpha; fixes bug 1150. o Minor bugfixes: - Do not refuse to learn about authority certs and v2 networkstatus documents that are older than the latest consensus. This bug might have degraded client bootstrapping. Bugfix on 0.2.0.10-alpha. Spotted and fixed by xmux. - Fix a couple of very-hard-to-trigger memory leaks, and one hard-to- trigger platform-specific option misparsing case found by Coverity Scan. - Fix a compilation warning on Fedora 12 by removing an impossible-to- trigger assert. Fixes bug 1173. Changes in version 0.2.1.20 - 2009-10-15 Tor 0.2.1.20 fixes a crash bug when you're accessing many hidden services at once, prepares for more performance improvements, and fixes a bunch of smaller bugs. The Windows and OS X bundles also include a more recent Vidalia, and switch from Privoxy to Polipo. The OS X installers are now drag and drop. It's best to un-install Tor/Vidalia and then install this new bundle, rather than upgrade. If you want to upgrade, you'll need to update the paths for Tor and Polipo in the Vidalia Settings window. o Major bugfixes: - Send circuit or stream sendme cells when our window has decreased by 100 cells, not when it has decreased by 101 cells. Bug uncovered by Karsten when testing the "reduce circuit window" performance patch. Bugfix on the 54th commit on Tor -- from July 2002, before the release of Tor 0.0.0. This is the new winner of the oldest-bug prize. - Fix a remotely triggerable memory leak when a consensus document contains more than one signature from the same voter. Bugfix on 0.2.0.3-alpha. - Avoid segfault in rare cases when finishing an introduction circuit as a client and finding out that we don't have an introduction key for it. Fixes bug 1073. Reported by Aaron Swartz. o Major features: - Tor now reads the "circwindow" parameter out of the consensus, and uses that value for its circuit package window rather than the default of 1000 cells. Begins the implementation of proposal 168. o New directory authorities: - Set up urras (run by Jacob Appelbaum) as the seventh v3 directory authority. - Move moria1 and tonga to alternate IP addresses. o Minor bugfixes: - Fix a signed/unsigned compile warning in 0.2.1.19. - Fix possible segmentation fault on directory authorities. Bugfix on 0.2.1.14-rc. - Fix an extremely rare infinite recursion bug that could occur if we tried to log a message after shutting down the log subsystem. Found by Matt Edman. Bugfix on 0.2.0.16-alpha. - Fix an obscure bug where hidden services on 64-bit big-endian systems might mis-read the timestamp in v3 introduce cells, and refuse to connect back to the client. Discovered by "rotor". Bugfix on 0.2.1.6-alpha. - We were triggering a CLOCK_SKEW controller status event whenever we connect via the v2 connection protocol to any relay that has a wrong clock. Instead, we should only inform the controller when it's a trusted authority that claims our clock is wrong. Bugfix on 0.2.0.20-rc; starts to fix bug 1074. Reported by SwissTorExit. - We were telling the controller about CHECKING_REACHABILITY and REACHABILITY_FAILED status events whenever we launch a testing circuit or notice that one has failed. Instead, only tell the controller when we want to inform the user of overall success or overall failure. Bugfix on 0.1.2.6-alpha. Fixes bug 1075. Reported by SwissTorExit. - Don't warn when we're using a circuit that ends with a node excluded in ExcludeExitNodes, but the circuit is not used to access the outside world. This should help fix bug 1090. Bugfix on 0.2.1.6-alpha. - Work around a small memory leak in some versions of OpenSSL that stopped the memory used by the hostname TLS extension from being freed. o Minor features: - Add a "getinfo status/accepted-server-descriptor" controller command, which is the recommended way for controllers to learn whether our server descriptor has been successfully received by at least on directory authority. Un-recommend good-server-descriptor getinfo and status events until we have a better design for them. Changes in version 0.2.1.19 - 2009-07-28 Tor 0.2.1.19 fixes a major bug with accessing and providing hidden services. o Major bugfixes: - Make accessing hidden services on 0.2.1.x work right again. Bugfix on 0.2.1.3-alpha; workaround for bug 1038. Diagnosis and part of patch provided by "optimist". o Minor features: - When a relay/bridge is writing out its identity key fingerprint to the "fingerprint" file and to its logs, write it without spaces. Now it will look like the fingerprints in our bridges documentation, and confuse fewer users. o Minor bugfixes: - Relays no longer publish a new server descriptor if they change their MaxAdvertisedBandwidth config option but it doesn't end up changing their advertised bandwidth numbers. Bugfix on 0.2.0.28-rc; fixes bug 1026. Patch from Sebastian. - Avoid leaking memory every time we get a create cell but we have so many already queued that we refuse it. Bugfix on 0.2.0.19-alpha; fixes bug 1034. Reported by BarkerJr. Changes in version 0.2.1.18 - 2009-07-24 Tor 0.2.1.18 lays the foundations for performance improvements, adds status events to help users diagnose bootstrap problems, adds optional authentication/authorization for hidden services, fixes a variety of potential anonymity problems, and includes a huge pile of other features and bug fixes. o Major features (clients): - Start sending "bootstrap phase" status events to the controller, so it can keep the user informed of progress fetching directory information and establishing circuits. Also inform the controller if we think we're stuck at a particular bootstrap phase. Implements proposal 137. - Clients replace entry guards that were chosen more than a few months ago. This change should significantly improve client performance, especially once more people upgrade, since relays that have been a guard for a long time are currently overloaded. - Network status consensus documents and votes now contain bandwidth information for each relay. Clients use the bandwidth values in the consensus, rather than the bandwidth values in each relay descriptor. This approach opens the door to more accurate bandwidth estimates once the directory authorities start doing active measurements. Implements part of proposal 141. o Major features (relays): - Disable and refactor some debugging checks that forced a linear scan over the whole server-side DNS cache. These accounted for over 50% of CPU time on a relatively busy exit node's gprof profile. Also, disable some debugging checks that appeared in exit node profile data. Found by Jacob. - New DirPortFrontPage option that takes an html file and publishes it as "/" on the DirPort. Now relay operators can provide a disclaimer without needing to set up a separate webserver. There's a sample disclaimer in contrib/tor-exit-notice.html. o Major features (hidden services): - Make it possible to build hidden services that only certain clients are allowed to connect to. This is enforced at several points, so that unauthorized clients are unable to send INTRODUCE cells to the service, or even (depending on the type of authentication) to learn introduction points. This feature raises the bar for certain kinds of active attacks against hidden services. Design and code by Karsten Loesing. Implements proposal 121. - Relays now store and serve v2 hidden service descriptors by default, i.e., the new default value for HidServDirectoryV2 is 1. This is the last step in proposal 114, which aims to make hidden service lookups more reliable. o Major features (path selection): - ExitNodes and Exclude*Nodes config options now allow you to restrict by country code ("{US}") or IP address or address pattern ("255.128.0.0/16"). Patch from Robert Hogan. It still needs some refinement to decide what config options should take priority if you ask to both use a particular node and exclude it. o Major features (misc): - When building a consensus, do not include routers that are down. This cuts down 30% to 40% on consensus size. Implements proposal 138. - New TestingTorNetwork config option to allow adjustment of previously constant values that could slow bootstrapping. Implements proposal 135. Patch from Karsten. - Convert many internal address representations to optionally hold IPv6 addresses. Generate and accept IPv6 addresses in many protocol elements. Make resolver code handle nameservers located at IPv6 addresses. - More work on making our TLS handshake blend in: modify the list of ciphers advertised by OpenSSL in client mode to even more closely resemble a common web browser. We cheat a little so that we can advertise ciphers that the locally installed OpenSSL doesn't know about. - Use the TLS1 hostname extension to more closely resemble browser behavior. o Security fixes (anonymity/entropy): - Never use a connection with a mismatched address to extend a circuit, unless that connection is canonical. A canonical connection is one whose address is authenticated by the router's identity key, either in a NETINFO cell or in a router descriptor. - Implement most of proposal 110: The first K cells to be sent along a circuit are marked as special "early" cells; only K "early" cells will be allowed. Once this code is universal, we can block certain kinds of denial-of-service attack by requiring that EXTEND commands must be sent using an "early" cell. - Resume using OpenSSL's RAND_poll() for better (and more portable) cross-platform entropy collection again. We used to use it, then stopped using it because of a bug that could crash systems that called RAND_poll when they had a lot of fds open. It looks like the bug got fixed in late 2006. Our new behavior is to call RAND_poll() at startup, and to call RAND_poll() when we reseed later only if we have a non-buggy OpenSSL version. - When the client is choosing entry guards, now it selects at most one guard from a given relay family. Otherwise we could end up with all of our entry points into the network run by the same operator. Suggested by Camilo Viecco. Fix on 0.1.1.11-alpha. - Do not use or believe expired v3 authority certificates. Patch from Karsten. Bugfix in 0.2.0.x. Fixes bug 851. - Drop begin cells to a hidden service if they come from the middle of a circuit. Patch from lark. - When we erroneously receive two EXTEND cells for the same circuit ID on the same connection, drop the second. Patch from lark. - Authorities now vote for the Stable flag for any router whose weighted MTBF is at least 5 days, regardless of the mean MTBF. - Clients now never report any stream end reason except 'MISC'. Implements proposal 148. o Major bugfixes (crashes): - Parse dates and IPv4 addresses in a locale- and libc-independent manner, to avoid platform-dependent behavior on malformed input. - Fix a crash that occurs on exit nodes when a nameserver request timed out. Bugfix on 0.1.2.1-alpha; our CLEAR debugging code had been suppressing the bug since 0.1.2.10-alpha. Partial fix for bug 929. - Do not assume that a stack-allocated character array will be 64-bit aligned on platforms that demand that uint64_t access is aligned. Possible fix for bug 604. - Resolve a very rare crash bug that could occur when the user forced a nameserver reconfiguration during the middle of a nameserver probe. Fixes bug 526. Bugfix on 0.1.2.1-alpha. - Avoid a "0 divided by 0" calculation when calculating router uptime at directory authorities. Bugfix on 0.2.0.8-alpha. - Fix an assertion bug in parsing policy-related options; possible fix for bug 811. - Rate-limit too-many-sockets messages: when they happen, they happen a lot and end up filling up the disk. Resolves bug 748. - Fix a race condition that could cause crashes or memory corruption when running as a server with a controller listening for log messages. - Avoid crashing when we have a policy specified in a DirPolicy or SocksPolicy or ReachableAddresses option with ports set on it, and we re-load the policy. May fix bug 996. - Fix an assertion failure on 64-bit platforms when we allocated memory right up to the end of a memarea, then realigned the memory one step beyond the end. Fixes a possible cause of bug 930. - Protect the count of open sockets with a mutex, so we can't corrupt it when two threads are closing or opening sockets at once. Fix for bug 939. Bugfix on 0.2.0.1-alpha. o Major bugfixes (clients): - Discard router descriptors as we load them if they are more than five days old. Otherwise if Tor is off for a long time and then starts with cached descriptors, it will try to use the onion keys in those obsolete descriptors when building circuits. Fixes bug 887. - When we choose to abandon a new entry guard because we think our older ones might be better, close any circuits pending on that new entry guard connection. This fix should make us recover much faster when our network is down and then comes back. Bugfix on 0.1.2.8-beta; found by lodger. - When Tor clients restart after 1-5 days, they discard all their cached descriptors as too old, but they still use the cached consensus document. This approach is good for robustness, but bad for performance: since they don't know any bandwidths, they end up choosing at random rather than weighting their choice by speed. Fixed by the above feature of putting bandwidths in the consensus. o Major bugfixes (relays): - Relays were falling out of the networkstatus consensus for part of a day if they changed their local config but the authorities discarded their new descriptor as "not sufficiently different". Now directory authorities accept a descriptor as changed if BandwidthRate or BandwidthBurst changed. Partial fix for bug 962; patch by Sebastian. - Ensure that two circuits can never exist on the same connection with the same circuit ID, even if one is marked for close. This is conceivably a bugfix for bug 779; fixes a bug on 0.1.0.4-rc. - Directory authorities were neglecting to mark relays down in their internal histories if the relays fall off the routerlist without ever being found unreachable. So there were relays in the histories that haven't been seen for eight months, and are listed as being up for eight months. This wreaked havoc on the "median wfu" and "median mtbf" calculations, in turn making Guard and Stable flags wrong, hurting network performance. Fixes bugs 696 and 969. Bugfix on 0.2.0.6-alpha. o Major bugfixes (hidden services): - When establishing a hidden service, introduction points that originate from cannibalized circuits were completely ignored and not included in rendezvous service descriptors. This might have been another reason for delay in making a hidden service available. Bugfix from long ago (0.0.9.x?) o Major bugfixes (memory and resource management): - Fixed some memory leaks -- some quite frequent, some almost impossible to trigger -- based on results from Coverity. - Speed up parsing and cut down on memory fragmentation by using stack-style allocations for parsing directory objects. Previously, this accounted for over 40% of allocations from within Tor's code on a typical directory cache. - Use a Bloom filter rather than a digest-based set to track which descriptors we need to keep around when we're cleaning out old router descriptors. This speeds up the computation significantly, and may reduce fragmentation. o New/changed config options: - Now NodeFamily and MyFamily config options allow spaces in identity fingerprints, so it's easier to paste them in. Suggested by Lucky Green. - Allow ports 465 and 587 in the default exit policy again. We had rejected them in 0.1.0.15, because back in 2005 they were commonly misconfigured and ended up as spam targets. We hear they are better locked down these days. - Make TrackHostExit mappings expire a while after their last use, not after their creation. Patch from Robert Hogan. - Add an ExcludeExitNodes option so users can list a set of nodes that should be be excluded from the exit node position, but allowed elsewhere. Implements proposal 151. - New --hush command-line option similar to --quiet. While --quiet disables all logging to the console on startup, --hush limits the output to messages of warning and error severity. - New configure/torrc options (--enable-geoip-stats, DirRecordUsageByCountry) to record how many IPs we've served directory info to in each country code, how many status documents total we've sent to each country code, and what share of the total directory requests we should expect to see. - Make outbound DNS packets respect the OutboundBindAddress setting. Fixes the bug part of bug 798. Bugfix on 0.1.2.2-alpha. - Allow separate log levels to be configured for different logging domains. For example, this allows one to log all notices, warnings, or errors, plus all memory management messages of level debug or higher, with: Log [MM] debug-err [*] notice-err file /var/log/tor. - Update to the "June 3 2009" ip-to-country file. o Minor features (relays): - Raise the minimum rate limiting to be a relay from 20000 bytes to 20480 bytes (aka 20KB/s), to match our documentation. Also update directory authorities so they always assign the Fast flag to relays with 20KB/s of capacity. Now people running relays won't suddenly find themselves not seeing any use, if the network gets faster on average. - If we're a relay and we change our IP address, be more verbose about the reason that made us change. Should help track down further bugs for relays on dynamic IP addresses. - Exit servers can now answer resolve requests for ip6.arpa addresses. - Implement most of Proposal 152: allow specialized servers to permit single-hop circuits, and clients to use those servers to build single-hop circuits when using a specialized controller. Patch from Josh Albrecht. Resolves feature request 768. - When relays do their initial bandwidth measurement, don't limit to just our entry guards for the test circuits. Otherwise we tend to have multiple test circuits going through a single entry guard, which makes our bandwidth test less accurate. Fixes part of bug 654; patch contributed by Josh Albrecht. o Minor features (directory authorities): - Try not to open more than one descriptor-downloading connection to an authority at once. This should reduce load on directory authorities. Fixes bug 366. - Add cross-certification to newly generated certificates, so that a signing key is enough information to look up a certificate. Start serving certificates by pairs. Implements proposal 157. - When a directory authority downloads a descriptor that it then immediately rejects, do not retry downloading it right away. Should save some bandwidth on authorities. Fix for bug 888. Patch by Sebastian Hahn. - Directory authorities now serve a /tor/dbg-stability.txt URL to help debug WFU and MTBF calculations. - In directory authorities' approved-routers files, allow fingerprints with or without space. o Minor features (directory mirrors): - When a download gets us zero good descriptors, do not notify Tor that new directory information has arrived. - Servers support a new URL scheme for consensus downloads that allows the client to specify which authorities are trusted. The server then only sends the consensus if the client will trust it. Otherwise a 404 error is sent back. Clients use this new scheme when the server supports it (meaning it's running 0.2.1.1-alpha or later). Implements proposal 134. o Minor features (bridges): - If the bridge config line doesn't specify a port, assume 443. This makes bridge lines a bit smaller and easier for users to understand. - If we're using bridges and our network goes away, be more willing to forgive our bridges and try again when we get an application request. o Minor features (hidden services): - When the client launches an introduction circuit, retry with a new circuit after 30 seconds rather than 60 seconds. - Launch a second client-side introduction circuit in parallel after a delay of 15 seconds (based on work by Christian Wilms). - Hidden services start out building five intro circuits rather than three, and when the first three finish they publish a service descriptor using those. Now we publish our service descriptor much faster after restart. - Drop the requirement to have an open dir port for storing and serving v2 hidden service descriptors. o Minor features (build and packaging): - On Linux, use the prctl call to re-enable core dumps when the User option is set. - Try to make sure that the version of Libevent we're running with is binary-compatible with the one we built with. May address bug 897 and others. - Add a new --enable-local-appdata configuration switch to change the default location of the datadir on win32 from APPDATA to LOCAL_APPDATA. In the future, we should migrate to LOCAL_APPDATA entirely. Patch from coderman. - Build correctly against versions of OpenSSL 0.9.8 or later that are built without support for deprecated functions. - On platforms with a maximum syslog string length, truncate syslog messages to that length ourselves, rather than relying on the system to do it for us. - Automatically detect MacOSX versions earlier than 10.4.0, and disable kqueue from inside Tor when running with these versions. We previously did this from the startup script, but that was no help to people who didn't use the startup script. Resolves bug 863. - Build correctly when configured to build outside the main source path. Patch from Michael Gold. - Disable GCC's strict alias optimization by default, to avoid the likelihood of its introducing subtle bugs whenever our code violates the letter of C99's alias rules. - Change the contrib/tor.logrotate script so it makes the new logs as "_tor:_tor" rather than the default, which is generally "root:wheel". Fixes bug 676, reported by Serge Koksharov. - Change our header file guard macros to be less likely to conflict with system headers. Adam Langley noticed that we were conflicting with log.h on Android. - Add a couple of extra warnings to --enable-gcc-warnings for GCC 4.3, and stop using a warning that had become unfixably verbose under GCC 4.3. - Use a lockfile to make sure that two Tor processes are not simultaneously running with the same datadir. - Allow OpenSSL to use dynamic locks if it wants. - Add LIBS=-lrt to Makefile.am so the Tor RPMs use a static libevent. o Minor features (controllers): - When generating circuit events with verbose nicknames for controllers, try harder to look up nicknames for routers on a circuit. (Previously, we would look in the router descriptors we had for nicknames, but not in the consensus.) Partial fix for bug 941. - New controller event NEWCONSENSUS that lists the networkstatus lines for every recommended relay. Now controllers like Torflow can keep up-to-date on which relays they should be using. - New controller event "clients_seen" to report a geoip-based summary of which countries we've seen clients from recently. Now controllers like Vidalia can show bridge operators that they're actually making a difference. - Add a 'getinfo status/clients-seen' controller command, in case controllers want to hear clients_seen events but connect late. - New CONSENSUS_ARRIVED event to note when a new consensus has been fetched and validated. - Add an internal-use-only __ReloadTorrcOnSIGHUP option for controllers to prevent SIGHUP from reloading the configuration. Fixes bug 856. - Return circuit purposes in response to GETINFO circuit-status. Fixes bug 858. - Serve the latest v3 networkstatus consensus via the control port. Use "getinfo dir/status-vote/current/consensus" to fetch it. - Add a "GETINFO /status/bootstrap-phase" controller option, so the controller can query our current bootstrap state in case it attaches partway through and wants to catch up. - Provide circuit purposes along with circuit events to the controller. o Minor features (tools): - Do not have tor-resolve automatically refuse all .onion addresses; if AutomapHostsOnResolve is set in your torrc, this will work fine. - Add a -p option to tor-resolve for specifying the SOCKS port: some people find host:port too confusing. - Print the SOCKS5 error message string as well as the error code when a tor-resolve request fails. Patch from Jacob. o Minor bugfixes (memory and resource management): - Clients no longer cache certificates for authorities they do not recognize. Bugfix on 0.2.0.9-alpha. - Do not use C's stdio library for writing to log files. This will improve logging performance by a minute amount, and will stop leaking fds when our disk is full. Fixes bug 861. - Stop erroneous use of O_APPEND in cases where we did not in fact want to re-seek to the end of a file before every last write(). - Fix a small alignment and memory-wasting bug on buffer chunks. Spotted by rovv. - Add a malloc_good_size implementation to OpenBSD_malloc_linux.c, to avoid unused RAM in buffer chunks and memory pools. - Reduce the default smartlist size from 32 to 16; it turns out that most smartlists hold around 8-12 elements tops. - Make dumpstats() log the fullness and size of openssl-internal buffers. - If the user has applied the experimental SSL_MODE_RELEASE_BUFFERS patch to their OpenSSL, turn it on to save memory on servers. This patch will (with any luck) get included in a mainline distribution before too long. - Fix a memory leak when v3 directory authorities load their keys and cert from disk. Bugfix on 0.2.0.1-alpha. - Stop using malloc_usable_size() to use more area than we had actually allocated: it was safe, but made valgrind really unhappy. - Make the assert_circuit_ok() function work correctly on circuits that have already been marked for close. - Fix uninitialized size field for memory area allocation: may improve memory performance during directory parsing. o Minor bugfixes (clients): - Stop reloading the router list from disk for no reason when we run out of reachable directory mirrors. Once upon a time reloading it would set the 'is_running' flag back to 1 for them. It hasn't done that for a long time. - When we had picked an exit node for a connection, but marked it as "optional", and it turned out we had no onion key for the exit, stop wanting that exit and try again. This situation may not be possible now, but will probably become feasible with proposal 158. Spotted by rovv. Fixes another case of bug 752. - Fix a bug in address parsing that was preventing bridges or hidden service targets from being at IPv6 addresses. - Do not remove routers as too old if we do not have any consensus document. Bugfix on 0.2.0.7-alpha. - When an exit relay resolves a stream address to a local IP address, do not just keep retrying that same exit relay over and over. Instead, just close the stream. Addresses bug 872. Bugfix on 0.2.0.32. Patch from rovv. - Made Tor a little less aggressive about deleting expired certificates. Partial fix for bug 854. - Treat duplicate certificate fetches as failures, so that we do not try to re-fetch an expired certificate over and over and over. - Do not say we're fetching a certificate when we'll in fact skip it because of a pending download. - If we have correct permissions on $datadir, we complain to stdout and fail to start. But dangerous permissions on $datadir/cached-status/ would cause us to open a log and complain there. Now complain to stdout and fail to start in both cases. Fixes bug 820, reported by seeess. o Minor bugfixes (bridges): - When we made bridge authorities stop serving bridge descriptors over unencrypted links, we also broke DirPort reachability testing for bridges. So bridges with a non-zero DirPort were printing spurious warns to their logs. Bugfix on 0.2.0.16-alpha. Fixes bug 709. - Don't allow a bridge to publish its router descriptor to a non-bridge directory authority. Fixes part of bug 932. - When we change to or from being a bridge, reset our counts of client usage by country. Fixes bug 932. o Minor bugfixes (relays): - Log correct error messages for DNS-related network errors on Windows. - Actually return -1 in the error case for read_bandwidth_usage(). Harmless bug, since we currently don't care about the return value anywhere. Bugfix on 0.2.0.9-alpha. - Provide a more useful log message if bug 977 (related to buffer freelists) ever reappears, and do not crash right away. - We were already rejecting relay begin cells with destination port of 0. Now also reject extend cells with destination port or address of 0. Suggested by lark. - When we can't transmit a DNS request due to a network error, retry it after a while, and eventually transmit a failing response to the RESOLVED cell. Bugfix on 0.1.2.5-alpha. - Solve a bug that kept hardware crypto acceleration from getting enabled when accounting was turned on. Fixes bug 907. Bugfix on 0.0.9pre6. - When a canonical connection appears later in our internal list than a noncanonical one for a given OR ID, always use the canonical one. Bugfix on 0.2.0.12-alpha. Fixes bug 805. Spotted by rovv. - Avoid some nasty corner cases in the logic for marking connections as too old or obsolete or noncanonical for circuits. Partial bugfix on bug 891. - Fix another interesting corner-case of bug 891 spotted by rovv: Previously, if two hosts had different amounts of clock drift, and one of them created a new connection with just the wrong timing, the other might decide to deprecate the new connection erroneously. Bugfix on 0.1.1.13-alpha. - If one win32 nameserver fails to get added, continue adding the rest, and don't automatically fail. - Fix a bug where an unreachable relay would establish enough reachability testing circuits to do a bandwidth test -- if we already have a connection to the middle hop of the testing circuit, then it could establish the last hop by using the existing connection. Bugfix on 0.1.2.2-alpha, exposed when we made testing circuits no longer use entry guards in 0.2.1.3-alpha. o Minor bugfixes (directory authorities): - Limit uploaded directory documents to be 16M rather than 500K. The directory authorities were refusing v3 consensus votes from other authorities, since the votes are now 504K. Fixes bug 959; bugfix on 0.0.2pre17 (where we raised it from 50K to 500K ;). - Directory authorities should never send a 503 "busy" response to requests for votes or keys. Bugfix on 0.2.0.8-alpha; exposed by bug 959. - Fix code so authorities _actually_ send back X-Descriptor-Not-New headers. Bugfix on 0.2.0.10-alpha. o Minor bugfixes (hidden services): - When we can't find an intro key for a v2 hidden service descriptor, fall back to the v0 hidden service descriptor and log a bug message. Workaround for bug 1024. - In very rare situations new hidden service descriptors were published earlier than 30 seconds after the last change to the service. (We currently think that a hidden service descriptor that's been stable for 30 seconds is worth publishing.) - If a hidden service sends us an END cell, do not consider retrying the connection; just close it. Patch from rovv. - If we are not using BEGIN_DIR cells, don't attempt to contact hidden service directories if they have no advertised dir port. Bugfix on 0.2.0.10-alpha. o Minor bugfixes (tools): - In the torify(1) manpage, mention that tsocks will leak your DNS requests. o Minor bugfixes (controllers): - If the controller claimed responsibility for a stream, but that stream never finished making its connection, it would live forever in circuit_wait state. Now we close it after SocksTimeout seconds. Bugfix on 0.1.2.7-alpha; reported by Mike Perry. - Make DNS resolved controller events into "CLOSED", not "FAILED". Bugfix on 0.1.2.5-alpha. Fix by Robert Hogan. Resolves bug 807. - The control port would close the connection before flushing long replies, such as the network consensus, if a QUIT command was issued before the reply had completed. Now, the control port flushes all pending replies before closing the connection. Also fix a spurious warning when a QUIT command is issued after a malformed or rejected AUTHENTICATE command, but before the connection was closed. Patch by Marcus Griep. Fixes bugs 1015 and 1016. - Fix a bug that made stream bandwidth get misreported to the controller. o Deprecated and removed features: - The old "tor --version --version" command, which would print out the subversion "Id" of most of the source files, is now removed. It turned out to be less useful than we'd expected, and harder to maintain. - RedirectExits has been removed. It was deprecated since 0.2.0.3-alpha. - Finally remove deprecated "EXTENDED_FORMAT" controller feature. It has been called EXTENDED_EVENTS since 0.1.2.4-alpha. - Cell pools are now always enabled; --disable-cell-pools is ignored. - Directory mirrors no longer fetch the v1 directory or running-routers files. They are obsolete, and nobody asks for them anymore. This is the first step to making v1 authorities obsolete. - Take out the TestVia config option, since it was a workaround for a bug that was fixed in Tor 0.1.1.21. - Mark RendNodes, RendExcludeNodes, HiddenServiceNodes, and HiddenServiceExcludeNodes as obsolete: they never worked properly, and nobody seems to be using them. Fixes bug 754. Bugfix on 0.1.0.1-rc. Patch from Christian Wilms. - Remove all backward-compatibility code for relays running versions of Tor so old that they no longer work at all on the Tor network. o Code simplifications and refactoring: - Tool-assisted documentation cleanup. Nearly every function or static variable in Tor should have its own documentation now. - Rename the confusing or_is_obsolete field to the more appropriate is_bad_for_new_circs, and move it to or_connection_t where it belongs. - Move edge-only flags from connection_t to edge_connection_t: not only is this better coding, but on machines of plausible alignment, it should save 4-8 bytes per connection_t. "Every little bit helps." - Rename ServerDNSAllowBrokenResolvConf to ServerDNSAllowBrokenConfig for consistency; keep old option working for backward compatibility. - Simplify the code for finding connections to use for a circuit. - Revise the connection_new functions so that a more typesafe variant exists. This will work better with Coverity, and let us find any actual mistakes we're making here. - Refactor unit testing logic so that dmalloc can be used sensibly with unit tests to check for memory leaks. - Move all hidden-service related fields from connection and circuit structure to substructures: this way they won't eat so much memory. - Squeeze 2-5% out of client performance (according to oprofile) by improving the implementation of some policy-manipulation functions. - Change the implementation of ExcludeNodes and ExcludeExitNodes to be more efficient. Formerly it was quadratic in the number of servers; now it should be linear. Fixes bug 509. - Save 16-22 bytes per open circuit by moving the n_addr, n_port, and n_conn_id_digest fields into a separate structure that's only needed when the circuit has not yet attached to an n_conn. - Optimize out calls to time(NULL) that occur for every IO operation, or for every cell. On systems like Windows where time() is a slow syscall, this fix will be slightly helpful. Changes in version 0.2.0.35 - 2009-06-24 o Security fix: - Avoid crashing in the presence of certain malformed descriptors. Found by lark, and by automated fuzzing. - Fix an edge case where a malicious exit relay could convince a controller that the client's DNS question resolves to an internal IP address. Bug found and fixed by "optimist"; bugfix on 0.1.2.8-beta. o Major bugfixes: - Finally fix the bug where dynamic-IP relays disappear when their IP address changes: directory mirrors were mistakenly telling them their old address if they asked via begin_dir, so they never got an accurate answer about their new address, so they just vanished after a day. For belt-and-suspenders, relays that don't set Address in their config now avoid using begin_dir for all direct connections. Should fix bugs 827, 883, and 900. - Fix a timing-dependent, allocator-dependent, DNS-related crash bug that would occur on some exit nodes when DNS failures and timeouts occurred in certain patterns. Fix for bug 957. o Minor bugfixes: - When starting with a cache over a few days old, do not leak memory for the obsolete router descriptors in it. Bugfix on 0.2.0.33; fixes bug 672. - Hidden service clients didn't use a cached service descriptor that was older than 15 minutes, but wouldn't fetch a new one either, because there was already one in the cache. Now, fetch a v2 descriptor unless the same descriptor was added to the cache within the last 15 minutes. Fixes bug 997; reported by Marcus Griep. Changes in version 0.2.0.34 - 2009-02-08 Tor 0.2.0.34 features several more security-related fixes. You should upgrade, especially if you run an exit relay (remote crash) or a directory authority (remote infinite loop), or you're on an older (pre-XP) or not-recently-patched Windows (remote exploit). This release marks end-of-life for Tor 0.1.2.x. Those Tor versions have many known flaws, and nobody should be using them. You should upgrade. If you're using a Linux or BSD and its packages are obsolete, stop using those packages and upgrade anyway. o Security fixes: - Fix an infinite-loop bug on handling corrupt votes under certain circumstances. Bugfix on 0.2.0.8-alpha. - Fix a temporary DoS vulnerability that could be performed by a directory mirror. Bugfix on 0.2.0.9-alpha; reported by lark. - Avoid a potential crash on exit nodes when processing malformed input. Remote DoS opportunity. Bugfix on 0.2.0.33. - Do not accept incomplete ipv4 addresses (like 192.168.0) as valid. Spec conformance issue. Bugfix on Tor 0.0.2pre27. o Minor bugfixes: - Fix compilation on systems where time_t is a 64-bit integer. Patch from Matthias Drochner. - Don't consider expiring already-closed client connections. Fixes bug 893. Bugfix on 0.0.2pre20. Changes in version 0.2.0.33 - 2009-01-21 Tor 0.2.0.33 fixes a variety of bugs that were making relays less useful to users. It also finally fixes a bug where a relay or client that's been off for many days would take a long time to bootstrap. This update also fixes an important security-related bug reported by Ilja van Sprundel. You should upgrade. (We'll send out more details about the bug once people have had some time to upgrade.) o Security fixes: - Fix a heap-corruption bug that may be remotely triggerable on some platforms. Reported by Ilja van Sprundel. o Major bugfixes: - When a stream at an exit relay is in state "resolving" or "connecting" and it receives an "end" relay cell, the exit relay would silently ignore the end cell and not close the stream. If the client never closes the circuit, then the exit relay never closes the TCP connection. Bug introduced in Tor 0.1.2.1-alpha; reported by "wood". - When sending CREATED cells back for a given circuit, use a 64-bit connection ID to find the right connection, rather than an addr:port combination. Now that we can have multiple OR connections between the same ORs, it is no longer possible to use addr:port to uniquely identify a connection. - Bridge relays that had DirPort set to 0 would stop fetching descriptors shortly after startup, and then briefly resume after a new bandwidth test and/or after publishing a new bridge descriptor. Bridge users that try to bootstrap from them would get a recent networkstatus but would get descriptors from up to 18 hours earlier, meaning most of the descriptors were obsolete already. Reported by Tas; bugfix on 0.2.0.13-alpha. - Prevent bridge relays from serving their 'extrainfo' document to anybody who asks, now that extrainfo docs include potentially sensitive aggregated client geoip summaries. Bugfix on 0.2.0.13-alpha. - If the cached networkstatus consensus is more than five days old, discard it rather than trying to use it. In theory it could be useful because it lists alternate directory mirrors, but in practice it just means we spend many minutes trying directory mirrors that are long gone from the network. Also discard router descriptors as we load them if they are more than five days old, since the onion key is probably wrong by now. Bugfix on 0.2.0.x. Fixes bug 887. o Minor bugfixes: - Do not mark smartlist_bsearch_idx() function as ATTR_PURE. This bug could make gcc generate non-functional binary search code. Bugfix on 0.2.0.10-alpha. - Build correctly on platforms without socklen_t. - Compile without warnings on solaris. - Avoid potential crash on internal error during signature collection. Fixes bug 864. Patch from rovv. - Correct handling of possible malformed authority signing key certificates with internal signature types. Fixes bug 880. Bugfix on 0.2.0.3-alpha. - Fix a hard-to-trigger resource leak when logging credential status. CID 349. - When we can't initialize DNS because the network is down, do not automatically stop Tor from starting. Instead, we retry failed dns_init() every 10 minutes, and change the exit policy to reject *:* until one succeeds. Fixes bug 691. - Use 64 bits instead of 32 bits for connection identifiers used with the controller protocol, to greatly reduce risk of identifier reuse. - When we're choosing an exit node for a circuit, and we have no pending streams, choose a good general exit rather than one that supports "all the pending streams". Bugfix on 0.1.1.x. Fix by rovv. - Fix another case of assuming, when a specific exit is requested, that we know more than the user about what hosts it allows. Fixes one case of bug 752. Patch from rovv. - Clip the MaxCircuitDirtiness config option to a minimum of 10 seconds. Warn the user if lower values are given in the configuration. Bugfix on 0.1.0.1-rc. Patch by Sebastian. - Clip the CircuitBuildTimeout to a minimum of 30 seconds. Warn the user if lower values are given in the configuration. Bugfix on 0.1.1.17-rc. Patch by Sebastian. - Fix a memory leak when we decline to add a v2 rendezvous descriptor to the cache because we already had a v0 descriptor with the same ID. Bugfix on 0.2.0.18-alpha. - Fix a race condition when freeing keys shared between main thread and CPU workers that could result in a memory leak. Bugfix on 0.1.0.1-rc. Fixes bug 889. - Send a valid END cell back when a client tries to connect to a nonexistent hidden service port. Bugfix on 0.1.2.15. Fixes bug 840. Patch from rovv. - Check which hops rendezvous stream cells are associated with to prevent possible guess-the-streamid injection attacks from intermediate hops. Fixes another case of bug 446. Based on patch from rovv. - If a broken client asks a non-exit router to connect somewhere, do not even do the DNS lookup before rejecting the connection. Fixes another case of bug 619. Patch from rovv. - When a relay gets a create cell it can't decrypt (e.g. because it's using the wrong onion key), we were dropping it and letting the client time out. Now actually answer with a destroy cell. Fixes bug 904. Bugfix on 0.0.2pre8. o Minor bugfixes (hidden services): - Do not throw away existing introduction points on SIGHUP. Bugfix on 0.0.6pre1. Patch by Karsten. Fixes bug 874. o Minor features: - Report the case where all signatures in a detached set are rejected differently than the case where there is an error handling the detached set. - When we realize that another process has modified our cached descriptors, print out a more useful error message rather than triggering an assertion. Fixes bug 885. Patch from Karsten. - Implement the 0x20 hack to better resist DNS poisoning: set the case on outgoing DNS requests randomly, and reject responses that do not match the case correctly. This logic can be disabled with the ServerDNSRamdomizeCase setting, if you are using one of the 0.3% of servers that do not reliably preserve case in replies. See "Increased DNS Forgery Resistance through 0x20-Bit Encoding" for more info. - Check DNS replies for more matching fields to better resist DNS poisoning. - Never use OpenSSL compression: it wastes RAM and CPU trying to compress cells, which are basically all encrypted, compressed, or both. Changes in version 0.2.0.32 - 2008-11-20 Tor 0.2.0.32 fixes a major security problem in Debian and Ubuntu packages (and maybe other packages) noticed by Theo de Raadt, fixes a smaller security flaw that might allow an attacker to access local services, further improves hidden service performance, and fixes a variety of other issues. o Security fixes: - The "User" and "Group" config options did not clear the supplementary group entries for the Tor process. The "User" option is now more robust, and we now set the groups to the specified user's primary group. The "Group" option is now ignored. For more detailed logging on credential switching, set CREDENTIAL_LOG_LEVEL in common/compat.c to LOG_NOTICE or higher. Patch by Jacob Appelbaum and Steven Murdoch. Bugfix on 0.0.2pre14. Fixes bug 848 and 857. - The "ClientDNSRejectInternalAddresses" config option wasn't being consistently obeyed: if an exit relay refuses a stream because its exit policy doesn't allow it, we would remember what IP address the relay said the destination address resolves to, even if it's an internal IP address. Bugfix on 0.2.0.7-alpha; patch by rovv. o Major bugfixes: - Fix a DOS opportunity during the voting signature collection process at directory authorities. Spotted by rovv. Bugfix on 0.2.0.x. o Major bugfixes (hidden services): - When fetching v0 and v2 rendezvous service descriptors in parallel, we were failing the whole hidden service request when the v0 descriptor fetch fails, even if the v2 fetch is still pending and might succeed. Similarly, if the last v2 fetch fails, we were failing the whole hidden service request even if a v0 fetch is still pending. Fixes bug 814. Bugfix on 0.2.0.10-alpha. - When extending a circuit to a hidden service directory to upload a rendezvous descriptor using a BEGIN_DIR cell, almost 1/6 of all requests failed, because the router descriptor has not been downloaded yet. In these cases, do not attempt to upload the rendezvous descriptor, but wait until the router descriptor is downloaded and retry. Likewise, do not attempt to fetch a rendezvous descriptor from a hidden service directory for which the router descriptor has not yet been downloaded. Fixes bug 767. Bugfix on 0.2.0.10-alpha. o Minor bugfixes: - Fix several infrequent memory leaks spotted by Coverity. - When testing for libevent functions, set the LDFLAGS variable correctly. Found by Riastradh. - Avoid a bug where the FastFirstHopPK 0 option would keep Tor from bootstrapping with tunneled directory connections. Bugfix on 0.1.2.5-alpha. Fixes bug 797. Found by Erwin Lam. - When asked to connect to A.B.exit:80, if we don't know the IP for A and we know that server B rejects most-but-not all connections to port 80, we would previously reject the connection. Now, we assume the user knows what they were asking for. Fixes bug 752. Bugfix on 0.0.9rc5. Diagnosed by BarkerJr. - If we overrun our per-second write limits a little, count this as having used up our write allocation for the second, and choke outgoing directory writes. Previously, we had only counted this when we had met our limits precisely. Fixes bug 824. Patch from by rovv. Bugfix on 0.2.0.x (??). - Remove the old v2 directory authority 'lefkada' from the default list. It has been gone for many months. - Stop doing unaligned memory access that generated bus errors on sparc64. Bugfix on 0.2.0.10-alpha. Fixes bug 862. - Make USR2 log-level switch take effect immediately. Bugfix on 0.1.2.8-beta. o Minor bugfixes (controller): - Make DNS resolved events into "CLOSED", not "FAILED". Bugfix on 0.1.2.5-alpha. Fix by Robert Hogan. Resolves bug 807. Changes in version 0.2.0.31 - 2008-09-03 Tor 0.2.0.31 addresses two potential anonymity issues, starts to fix a big bug we're seeing where in rare cases traffic from one Tor stream gets mixed into another stream, and fixes a variety of smaller issues. o Major bugfixes: - Make sure that two circuits can never exist on the same connection with the same circuit ID, even if one is marked for close. This is conceivably a bugfix for bug 779. Bugfix on 0.1.0.4-rc. - Relays now reject risky extend cells: if the extend cell includes a digest of all zeroes, or asks to extend back to the relay that sent the extend cell, tear down the circuit. Ideas suggested by rovv. - If not enough of our entry guards are available so we add a new one, we might use the new one even if it overlapped with the current circuit's exit relay (or its family). Anonymity bugfix pointed out by rovv. o Minor bugfixes: - Recover 3-7 bytes that were wasted per memory chunk. Fixes bug 794; bug spotted by rovv. Bugfix on 0.2.0.1-alpha. - Correctly detect the presence of the linux/netfilter_ipv4.h header when building against recent kernels. Bugfix on 0.1.2.1-alpha. - Pick size of default geoip filename string correctly on windows. Fixes bug 806. Bugfix on 0.2.0.30. - Make the autoconf script accept the obsolete --with-ssl-dir option as an alias for the actually-working --with-openssl-dir option. Fix the help documentation to recommend --with-openssl-dir. Based on a patch by "Dave". Bugfix on 0.2.0.1-alpha. - When using the TransPort option on OpenBSD, and using the User option to change UID and drop privileges, make sure to open /dev/pf before dropping privileges. Fixes bug 782. Patch from Christopher Davis. Bugfix on 0.1.2.1-alpha. - Try to attach connections immediately upon receiving a RENDEZVOUS2 or RENDEZVOUS_ESTABLISHED cell. This can save a second or two on the client side when connecting to a hidden service. Bugfix on 0.0.6pre1. Found and fixed by Christian Wilms; resolves bug 743. - When closing an application-side connection because its circuit is getting torn down, generate the stream event correctly. Bugfix on 0.1.2.x. Anonymous patch. Changes in version 0.2.0.30 - 2008-07-15 This new stable release switches to a more efficient directory distribution design, adds features to make connections to the Tor network harder to block, allows Tor to act as a DNS proxy, adds separate rate limiting for relayed traffic to make it easier for clients to become relays, fixes a variety of potential anonymity problems, and includes the usual huge pile of other features and bug fixes. o New v3 directory design: - Tor now uses a new way to learn about and distribute information about the network: the directory authorities vote on a common network status document rather than each publishing their own opinion. Now clients and caches download only one networkstatus document to bootstrap, rather than downloading one for each authority. Clients only download router descriptors listed in the consensus. Implements proposal 101; see doc/spec/dir-spec.txt for details. - Set up moria1, tor26, and dizum as v3 directory authorities in addition to being v2 authorities. Also add three new ones: ides (run by Mike Perry), gabelmoo (run by Karsten Loesing), and dannenberg (run by CCC). - Switch to multi-level keys for directory authorities: now their long-term identity key can be kept offline, and they periodically generate a new signing key. Clients fetch the "key certificates" to keep up to date on the right keys. Add a standalone tool "tor-gencert" to generate key certificates. Implements proposal 103. - Add a new V3AuthUseLegacyKey config option to make it easier for v3 authorities to change their identity keys if another bug like Debian's OpenSSL RNG flaw appears. - Authorities and caches fetch the v2 networkstatus documents less often, now that v3 is recommended. o Make Tor connections stand out less on the wire: - Use an improved TLS handshake designed by Steven Murdoch in proposal 124, as revised in proposal 130. The new handshake is meant to be harder for censors to fingerprint, and it adds the ability to detect certain kinds of man-in-the-middle traffic analysis attacks. The new handshake format includes version negotiation for OR connections as described in proposal 105, which will allow us to improve Tor's link protocol more safely in the future. - Enable encrypted directory connections by default for non-relays, so censor tools that block Tor directory connections based on their plaintext patterns will no longer work. This means Tor works in certain censored countries by default again. - Stop including recognizeable strings in the commonname part of Tor's x509 certificates. o Implement bridge relays: - Bridge relays (or "bridges" for short) are Tor relays that aren't listed in the main Tor directory. Since there is no complete public list of them, even an ISP that is filtering connections to all the known Tor relays probably won't be able to block all the bridges. See doc/design-paper/blocking.pdf and proposal 125 for details. - New config option BridgeRelay that specifies you want to be a bridge relay rather than a normal relay. When BridgeRelay is set to 1, then a) you cache dir info even if your DirPort ins't on, and b) the default for PublishServerDescriptor is now "bridge" rather than "v2,v3". - New config option "UseBridges 1" for clients that want to use bridge relays instead of ordinary entry guards. Clients then specify bridge relays by adding "Bridge" lines to their config file. Users can learn about a bridge relay either manually through word of mouth, or by one of our rate-limited mechanisms for giving out bridge addresses without letting an attacker easily enumerate them all. See https://www.torproject.org/bridges for details. - Bridge relays behave like clients with respect to time intervals for downloading new v3 consensus documents -- otherwise they stand out. Bridge users now wait until the end of the interval, so their bridge relay will be sure to have a new consensus document. o Implement bridge directory authorities: - Bridge authorities are like normal directory authorities, except they don't serve a list of known bridges. Therefore users that know a bridge's fingerprint can fetch a relay descriptor for that bridge, including fetching updates e.g. if the bridge changes IP address, yet an attacker can't just fetch a list of all the bridges. - Set up Tonga as the default bridge directory authority. - Bridge authorities refuse to serve bridge descriptors or other bridge information over unencrypted connections (that is, when responding to direct DirPort requests rather than begin_dir cells.) - Bridge directory authorities do reachability testing on the bridges they know. They provide router status summaries to the controller via "getinfo ns/purpose/bridge", and also dump summaries to a file periodically, so we can keep internal stats about which bridges are functioning. - If bridge users set the UpdateBridgesFromAuthority config option, but the digest they ask for is a 404 on the bridge authority, they fall back to contacting the bridge directly. - Bridges always use begin_dir to publish their server descriptor to the bridge authority using an anonymous encrypted tunnel. - Early work on a "bridge community" design: if bridge authorities set the BridgePassword config option, they will serve a snapshot of known bridge routerstatuses from their DirPort to anybody who knows that password. Unset by default. - Tor now includes an IP-to-country GeoIP file, so bridge relays can report sanitized aggregated summaries in their extra-info documents privately to the bridge authority, listing which countries are able to reach them. We hope this mechanism will let us learn when certain countries start trying to block bridges. - Bridge authorities write bridge descriptors to disk, so they can reload them after a reboot. They can also export the descriptors to other programs, so we can distribute them to blocked users via the BridgeDB interface, e.g. via https://bridges.torproject.org/ and bridges@torproject.org. o Tor can be a DNS proxy: - The new client-side DNS proxy feature replaces the need for dns-proxy-tor: Just set "DNSPort 9999", and Tor will now listen for DNS requests on port 9999, use the Tor network to resolve them anonymously, and send the reply back like a regular DNS server. The code still only implements a subset of DNS. - Add a new AutomapHostsOnResolve option: when it is enabled, any resolve request for hosts matching a given pattern causes Tor to generate an internal virtual address mapping for that host. This allows DNSPort to work sensibly with hidden service users. By default, .exit and .onion addresses are remapped; the list of patterns can be reconfigured with AutomapHostsSuffixes. - Add an "-F" option to tor-resolve to force a resolve for a .onion address. Thanks to the AutomapHostsOnResolve option, this is no longer a completely silly thing to do. o Major features (relay usability): - New config options RelayBandwidthRate and RelayBandwidthBurst: a separate set of token buckets for relayed traffic. Right now relayed traffic is defined as answers to directory requests, and OR connections that don't have any local circuits on them. See proposal 111 for details. - Create listener connections before we setuid to the configured User and Group. Now non-Windows users can choose port values under 1024, start Tor as root, and have Tor bind those ports before it changes to another UID. (Windows users could already pick these ports.) - Added a new ConstrainedSockets config option to set SO_SNDBUF and SO_RCVBUF on TCP sockets. Hopefully useful for Tor servers running on "vserver" accounts. Patch from coderman. o Major features (directory authorities): - Directory authorities track weighted fractional uptime and weighted mean-time-between failures for relays. WFU is suitable for deciding whether a node is "usually up", while MTBF is suitable for deciding whether a node is "likely to stay up." We need both, because "usually up" is a good requirement for guards, while "likely to stay up" is a good requirement for long-lived connections. - Directory authorities use a new formula for selecting which relays to advertise as Guards: they must be in the top 7/8 in terms of how long we have known about them, and above the median of those nodes in terms of weighted fractional uptime. - Directory authorities use a new formula for selecting which relays to advertise as Stable: when we have 4 or more days of data, use median measured MTBF rather than median declared uptime. Implements proposal 108. - Directory authorities accept and serve "extra info" documents for routers. Routers now publish their bandwidth-history lines in the extra-info docs rather than the main descriptor. This step saves 60% (!) on compressed router descriptor downloads. Servers upload extra-info docs to any authority that accepts them; directory authorities now allow multiple router descriptors and/or extra info documents to be uploaded in a single go. Authorities, and caches that have been configured to download extra-info documents, download them as needed. Implements proposal 104. - Authorities now list relays who have the same nickname as a different named relay, but list them with a new flag: "Unnamed". Now we can make use of relays that happen to pick the same nickname as a server that registered two years ago and then disappeared. Implements proposal 122. - Store routers in a file called cached-descriptors instead of in cached-routers. Initialize cached-descriptors from cached-routers if the old format is around. The new format allows us to store annotations along with descriptors, to record the time we received each descriptor, its source, and its purpose: currently one of general, controller, or bridge. o Major features (other): - New config options WarnPlaintextPorts and RejectPlaintextPorts so Tor can warn and/or refuse connections to ports commonly used with vulnerable-plaintext protocols. Currently we warn on ports 23, 109, 110, and 143, but we don't reject any. Based on proposal 129 by Kevin Bauer and Damon McCoy. - Integrate Karsten Loesing's Google Summer of Code project to publish hidden service descriptors on a set of redundant relays that are a function of the hidden service address. Now we don't have to rely on three central hidden service authorities for publishing and fetching every hidden service descriptor. Implements proposal 114. - Allow tunnelled directory connections to ask for an encrypted "begin_dir" connection or an anonymized "uses a full Tor circuit" connection independently. Now we can make anonymized begin_dir connections for (e.g.) more secure hidden service posting and fetching. o Major bugfixes (crashes and assert failures): - Stop imposing an arbitrary maximum on the number of file descriptors used for busy servers. Bug reported by Olaf Selke; patch from Sebastian Hahn. - Avoid possible failures when generating a directory with routers with over-long versions strings, or too many flags set. - Fix a rare assert error when we're closing one of our threads: use a mutex to protect the list of logs, so we never write to the list as it's being freed. Fixes the very rare bug 575, which is kind of the revenge of bug 222. - Avoid segfault in the case where a badly behaved v2 versioning directory sends a signed networkstatus with missing client-versions. - When we hit an EOF on a log (probably because we're shutting down), don't try to remove the log from the list: just mark it as unusable. (Bulletproofs against bug 222.) o Major bugfixes (code security fixes): - Detect size overflow in zlib code. Reported by Justin Ferguson and Dan Kaminsky. - Rewrite directory tokenization code to never run off the end of a string. Fixes bug 455. Patch from croup. - Be more paranoid about overwriting sensitive memory on free(), as a defensive programming tactic to ensure forward secrecy. o Major bugfixes (anonymity fixes): - Reject requests for reverse-dns lookup of names that are in a private address space. Patch from lodger. - Never report that we've used more bandwidth than we're willing to relay: it leaks how much non-relay traffic we're using. Resolves bug 516. - As a client, do not believe any server that tells us that an address maps to an internal address space. - Warn about unsafe ControlPort configurations. - Directory authorities now call routers Fast if their bandwidth is at least 100KB/s, and consider their bandwidth adequate to be a Guard if it is at least 250KB/s, no matter the medians. This fix complements proposal 107. - Directory authorities now never mark more than 2 servers per IP as Valid and Running (or 5 on addresses shared by authorities). Implements proposal 109, by Kevin Bauer and Damon McCoy. - If we're a relay, avoid picking ourselves as an introduction point, a rendezvous point, or as the final hop for internal circuits. Bug reported by taranis and lodger. - Exit relays that are used as a client can now reach themselves using the .exit notation, rather than just launching an infinite pile of circuits. Fixes bug 641. Reported by Sebastian Hahn. - Fix a bug where, when we were choosing the 'end stream reason' to put in our relay end cell that we send to the exit relay, Tor clients on Windows were sometimes sending the wrong 'reason'. The anonymity problem is that exit relays may be able to guess whether the client is running Windows, thus helping partition the anonymity set. Down the road we should stop sending reasons to exit relays, or otherwise prevent future versions of this bug. - Only update guard status (usable / not usable) once we have enough directory information. This was causing us to discard all our guards on startup if we hadn't been running for a few weeks. Fixes bug 448. - When our directory information has been expired for a while, stop being willing to build circuits using it. Fixes bug 401. o Major bugfixes (peace of mind for relay operators) - Non-exit relays no longer answer "resolve" relay cells, so they can't be induced to do arbitrary DNS requests. (Tor clients already avoid using non-exit relays for resolve cells, but now servers enforce this too.) Fixes bug 619. Patch from lodger. - When we setconf ClientOnly to 1, close any current OR and Dir listeners. Reported by mwenge. o Major bugfixes (other): - If we only ever used Tor for hidden service lookups or posts, we would stop building circuits and start refusing connections after 24 hours, since we falsely believed that Tor was dormant. Reported by nwf. - Add a new __HashedControlSessionPassword option for controllers to use for one-off session password hashes that shouldn't get saved to disk by SAVECONF --- Vidalia users were accumulating a pile of HashedControlPassword lines in their torrc files, one for each time they had restarted Tor and then clicked Save. Make Tor automatically convert "HashedControlPassword" to this new option but only when it's given on the command line. Partial fix for bug 586. - Patch from "Andrew S. Lists" to catch when we contact a directory mirror at IP address X and he says we look like we're coming from IP address X. Otherwise this would screw up our address detection. - Reject uploaded descriptors and extrainfo documents if they're huge. Otherwise we'll cache them all over the network and it'll clog everything up. Suggested by Aljosha Judmayer. - When a hidden service was trying to establish an introduction point, and Tor *did* manage to reuse one of the preemptively built circuits, it didn't correctly remember which one it used, so it asked for another one soon after, until there were no more preemptive circuits, at which point it launched one from scratch. Bugfix on 0.0.9.x. o Rate limiting and load balancing improvements: - When we add data to a write buffer in response to the data on that write buffer getting low because of a flush, do not consider the newly added data as a candidate for immediate flushing, but rather make it wait until the next round of writing. Otherwise, we flush and refill recursively, and a single greedy TLS connection can eat all of our bandwidth. - When counting the number of bytes written on a TLS connection, look at the BIO actually used for writing to the network, not at the BIO used (sometimes) to buffer data for the network. Looking at different BIOs could result in write counts on the order of ULONG_MAX. Fixes bug 614. - If we change our MaxAdvertisedBandwidth and then reload torrc, Tor won't realize it should publish a new relay descriptor. Fixes bug 688, reported by mfr. - Avoid using too little bandwidth when our clock skips a few seconds. - Choose which bridge to use proportional to its advertised bandwidth, rather than uniformly at random. This should speed up Tor for bridge users. Also do this for people who set StrictEntryNodes. o Bootstrapping faster and building circuits more intelligently: - Fix bug 660 that was preventing us from knowing that we should preemptively build circuits to handle expected directory requests. - When we're checking if we have enough dir info for each relay to begin establishing circuits, make sure that we actually have the descriptor listed in the consensus, not just any descriptor. - Correctly notify one-hop connections when a circuit build has failed. Possible fix for bug 669. Found by lodger. - Clients now hold circuitless TLS connections open for 1.5 times MaxCircuitDirtiness (15 minutes), since it is likely that they'll rebuild a new circuit over them within that timeframe. Previously, they held them open only for KeepalivePeriod (5 minutes). o Performance improvements (memory): - Add OpenBSD malloc code from "phk" as an optional malloc replacement on Linux: some glibc libraries do very poorly with Tor's memory allocation patterns. Pass --enable-openbsd-malloc to ./configure to get the replacement malloc code. - Switch our old ring buffer implementation for one more like that used by free Unix kernels. The wasted space in a buffer with 1mb of data will now be more like 8k than 1mb. The new implementation also avoids realloc();realloc(); patterns that can contribute to memory fragmentation. - Change the way that Tor buffers data that it is waiting to write. Instead of queueing data cells in an enormous ring buffer for each client->OR or OR->OR connection, we now queue cells on a separate queue for each circuit. This lets us use less slack memory, and will eventually let us be smarter about prioritizing different kinds of traffic. - Reference-count and share copies of address policy entries; only 5% of them were actually distinct. - Tune parameters for cell pool allocation to minimize amount of RAM overhead used. - Keep unused 4k and 16k buffers on free lists, rather than wasting 8k for every single inactive connection_t. Free items from the 4k/16k-buffer free lists when they haven't been used for a while. - Make memory debugging information describe more about history of cell allocation, so we can help reduce our memory use. - Be even more aggressive about releasing RAM from small empty buffers. Thanks to our free-list code, this shouldn't be too performance-intensive. - Log malloc statistics from mallinfo() on platforms where it exists. - Use memory pools to allocate cells with better speed and memory efficiency, especially on platforms where malloc() is inefficient. - Add a --with-tcmalloc option to the configure script to link against tcmalloc (if present). Does not yet search for non-system include paths. o Performance improvements (socket management): - Count the number of open sockets separately from the number of active connection_t objects. This will let us avoid underusing our allocated connection limit. - We no longer use socket pairs to link an edge connection to an anonymous directory connection or a DirPort test connection. Instead, we track the link internally and transfer the data in-process. This saves two sockets per "linked" connection (at the client and at the server), and avoids the nasty Windows socketpair() workaround. - We were leaking a file descriptor if Tor started with a zero-length cached-descriptors file. Patch by "freddy77". o Performance improvements (CPU use): - Never walk through the list of logs if we know that no log target is interested in a given message. - Call routerlist_remove_old_routers() much less often. This should speed startup, especially on directory caches. - Base64 decoding was actually showing up on our profile when parsing the initial descriptor file; switch to an in-process all-at-once implementation that's about 3.5x times faster than calling out to OpenSSL. - Use a slightly simpler string hashing algorithm (copying Python's instead of Java's) and optimize our digest hashing algorithm to take advantage of 64-bit platforms and to remove some possibly-costly voodoo. - When implementing AES counter mode, update only the portions of the counter buffer that need to change, and don't keep separate network-order and host-order counters on big-endian hosts (where they are the same). - Add an in-place version of aes_crypt() so that we can avoid doing a needless memcpy() call on each cell payload. - Use Critical Sections rather than Mutexes for synchronizing threads on win32; Mutexes are heavier-weight, and designed for synchronizing between processes. o Performance improvements (bandwidth use): - Don't try to launch new descriptor downloads quite so often when we already have enough directory information to build circuits. - Version 1 directories are no longer generated in full. Instead, authorities generate and serve "stub" v1 directories that list no servers. This will stop Tor versions 0.1.0.x and earlier from working, but (for security reasons) nobody should be running those versions anyway. - Avoid going directly to the directory authorities even if you're a relay, if you haven't found yourself reachable yet or if you've decided not to advertise your dirport yet. Addresses bug 556. - If we've gone 12 hours since our last bandwidth check, and we estimate we have less than 50KB bandwidth capacity but we could handle more, do another bandwidth test. - Support "If-Modified-Since" when answering HTTP requests for directories, running-routers documents, and v2 and v3 networkstatus documents. (There's no need to support it for router descriptors, since those are downloaded by descriptor digest.) - Stop fetching directory info so aggressively if your DirPort is on but your ORPort is off; stop fetching v2 dir info entirely. You can override these choices with the new FetchDirInfoEarly config option. o Changed config option behavior (features): - Configuration files now accept C-style strings as values. This helps encode characters not allowed in the current configuration file format, such as newline or #. Addresses bug 557. - Add hidden services and DNSPorts to the list of things that make Tor accept that it has running ports. Change starting Tor with no ports from a fatal error to a warning; we might change it back if this turns out to confuse anybody. Fixes bug 579. - Make PublishServerDescriptor default to 1, so the default doesn't have to change as we invent new directory protocol versions. - Allow people to say PreferTunnelledDirConns rather than PreferTunneledDirConns, for those alternate-spellers out there. - Raise the default BandwidthRate/BandwidthBurst to 5MB/10MB, to accommodate the growing number of servers that use the default and are reaching it. - Make it possible to enable HashedControlPassword and CookieAuthentication at the same time. - When a TrackHostExits-chosen exit fails too many times in a row, stop using it. Fixes bug 437. o Changed config option behavior (bugfixes): - Do not read the configuration file when we've only been told to generate a password hash. Fixes bug 643. Bugfix on 0.0.9pre5. Fix based on patch from Sebastian Hahn. - Actually validate the options passed to AuthDirReject, AuthDirInvalid, AuthDirBadDir, and AuthDirBadExit. - Make "ClientOnly 1" config option disable directory ports too. - Don't stop fetching descriptors when FetchUselessDescriptors is set, even if we stop asking for circuits. Bug reported by tup and ioerror. - Servers used to decline to publish their DirPort if their BandwidthRate or MaxAdvertisedBandwidth were below a threshold. Now they look only at BandwidthRate and RelayBandwidthRate. - Treat "2gb" when given in torrc for a bandwidth as meaning 2gb, minus 1 byte: the actual maximum declared bandwidth. - Make "TrackHostExits ." actually work. Bugfix on 0.1.0.x. - Make the NodeFamilies config option work. (Reported by lodger -- it has never actually worked, even though we added it in Oct 2004.) - If Tor is invoked from something that isn't a shell (e.g. Vidalia), now we expand "-f ~/.tor/torrc" correctly. Suggested by Matt Edman. o New config options: - New configuration options AuthDirMaxServersPerAddr and AuthDirMaxServersperAuthAddr to override default maximum number of servers allowed on a single IP address. This is important for running a test network on a single host. - Three new config options (AlternateDirAuthority, AlternateBridgeAuthority, and AlternateHSAuthority) that let the user selectively replace the default directory authorities by type, rather than the all-or-nothing replacement that DirServer offers. - New config options AuthDirBadDir and AuthDirListBadDirs for authorities to mark certain relays as "bad directories" in the networkstatus documents. Also supports the "!baddir" directive in the approved-routers file. - New config option V2AuthoritativeDirectory that all v2 directory authorities must set. This lets v3 authorities choose not to serve v2 directory information. o Minor features (other): - When we're not serving v2 directory information, there is no reason to actually keep any around. Remove the obsolete files and directory on startup if they are very old and we aren't going to serve them. - When we negotiate a v2 link-layer connection (not yet implemented), accept RELAY_EARLY cells and turn them into RELAY cells if we've negotiated a v1 connection for their next step. Initial steps for proposal 110. - When we have no consensus, check FallbackNetworkstatusFile (defaults to $PREFIX/share/tor/fallback-consensus) for a consensus. This way we can start out knowing some directory caches. We don't ship with a fallback consensus by default though, because it was making bootstrapping take too long while we tried many down relays. - Authorities send back an X-Descriptor-Not-New header in response to an accepted-but-discarded descriptor upload. Partially implements fix for bug 535. - If we find a cached-routers file that's been sitting around for more than 28 days unmodified, then most likely it's a leftover from when we upgraded to 0.2.0.8-alpha. Remove it. It has no good routers anyway. - When we (as a cache) download a descriptor because it was listed in a consensus, remember when the consensus was supposed to expire, and don't expire the descriptor until then. - Optionally (if built with -DEXPORTMALLINFO) export the output of mallinfo via http, as tor/mallinfo.txt. Only accessible from localhost. - Tag every guard node in our state file with the version that we believe added it, or with our own version if we add it. This way, if a user temporarily runs an old version of Tor and then switches back to a new one, she doesn't automatically lose her guards. - When somebody requests a list of statuses or servers, and we have none of those, return a 404 rather than an empty 200. - Merge in some (as-yet-unused) IPv6 address manipulation code. (Patch from croup.) - Add an HSAuthorityRecordStats option that hidden service authorities can use to track statistics of overall hidden service usage without logging information that would be as useful to an attacker. - Allow multiple HiddenServicePort directives with the same virtual port; when they occur, the user is sent round-robin to one of the target ports chosen at random. Partially fixes bug 393 by adding limited ad-hoc round-robining. - Revamp file-writing logic so we don't need to have the entire contents of a file in memory at once before we write to disk. Tor, meet stdio. o Minor bugfixes (other): - Alter the code that tries to recover from unhandled write errors, to not try to flush onto a socket that's given us unhandled errors. - Directory mirrors no longer include a guess at the client's IP address if the connection appears to be coming from the same /24 network; it was producing too many wrong guesses. - If we're trying to flush the last bytes on a connection (for example, when answering a directory request), reset the time-to-give-up timeout every time we manage to write something on the socket. - Reject router descriptors with out-of-range bandwidthcapacity or bandwidthburst values. - If we can't expand our list of entry guards (e.g. because we're using bridges or we have StrictEntryNodes set), don't mark relays down when they fail a directory request. Otherwise we're too quick to mark all our entry points down. - Authorities no longer send back "400 you're unreachable please fix it" errors to Tor servers that aren't online all the time. We're supposed to tolerate these servers now. - Let directory authorities startup even when they can't generate a descriptor immediately, e.g. because they don't know their address. - Correctly enforce that elements of directory objects do not appear more often than they are allowed to appear. - Stop allowing hibernating servers to be "stable" or "fast". - On Windows, we were preventing other processes from reading cached-routers while Tor was running. (Reported by janbar) - Check return values from pthread_mutex functions. - When opening /dev/null in finish_daemonize(), do not pass the O_CREAT flag. Fortify was complaining, and correctly so. Fixes bug 742; fix from Michael Scherer. Bugfix on 0.0.2pre19. o Controller features: - The GETCONF command now escapes and quotes configuration values that don't otherwise fit into the torrc file. - The SETCONF command now handles quoted values correctly. - Add "GETINFO/desc-annotations/id/" so controllers can ask about source, timestamp of arrival, purpose, etc. We need something like this to help Vidalia not do GeoIP lookups on bridge addresses. - Allow multiple HashedControlPassword config lines, to support multiple controller passwords. - Accept LF instead of CRLF on controller, since some software has a hard time generating real Internet newlines. - Add GETINFO values for the server status events "REACHABILITY_SUCCEEDED" and "GOOD_SERVER_DESCRIPTOR". Patch from Robert Hogan. - There is now an ugly, temporary "desc/all-recent-extrainfo-hack" GETINFO for Torstat to use until it can switch to using extrainfos. - New config option CookieAuthFile to choose a new location for the cookie authentication file, and config option CookieAuthFileGroupReadable to make it group-readable. - Add a SOURCE_ADDR field to STREAM NEW events so that controllers can match requests to applications. Patch from Robert Hogan. - Add a RESOLVE command to launch hostname lookups. Original patch from Robert Hogan. - Add GETINFO status/enough-dir-info to let controllers tell whether Tor has downloaded sufficient directory information. Patch from Tup. - You can now use the ControlSocket option to tell Tor to listen for controller connections on Unix domain sockets on systems that support them. Patch from Peter Palfrader. - New "GETINFO address-mappings/*" command to get address mappings with expiry information. "addr-mappings/*" is now deprecated. Patch from Tup. - Add a new config option __DisablePredictedCircuits designed for use by the controller, when we don't want Tor to build any circuits preemptively. - Let the controller specify HOP=%d as an argument to ATTACHSTREAM, so we can exit from the middle of the circuit. - Implement "getinfo status/circuit-established". - Implement "getinfo status/version/..." so a controller can tell whether the current version is recommended, and whether any versions are good, and how many authorities agree. Patch from "shibz". - Controllers should now specify cache=no or cache=yes when using the +POSTDESCRIPTOR command. - Add a "PURPOSE=" argument to "STREAM NEW" events, as suggested by Robert Hogan. Fixes the first part of bug 681. - When reporting clock skew, and we know that the clock is _at least as skewed_ as some value, but we don't know the actual value, report the value as a "minimum skew." o Controller bugfixes: - Generate "STATUS_SERVER" events rather than misspelled "STATUS_SEVER" events. Caught by mwenge. - Reject controller commands over 1MB in length, so rogue processes can't run us out of memory. - Change the behavior of "getinfo status/good-server-descriptor" so it doesn't return failure when any authority disappears. - Send NAMESERVER_STATUS messages for a single failed nameserver correctly. - When the DANGEROUS_VERSION controller status event told us we're running an obsolete version, it used the string "OLD" to describe it. Yet the "getinfo" interface used the string "OBSOLETE". Now use "OBSOLETE" in both cases. - Respond to INT and TERM SIGNAL commands before we execute the signal, in case the signal shuts us down. We had a patch in 0.1.2.1-alpha that tried to do this by queueing the response on the connection's buffer before shutting down, but that really isn't the same thing at all. Bug located by Matt Edman. - Provide DNS expiry times in GMT, not in local time. For backward compatibility, ADDRMAP events only provide GMT expiry in an extended field. "GETINFO address-mappings" always does the right thing. - Use CRLF line endings properly in NS events. - Make 'getinfo fingerprint' return a 551 error if we're not a server, so we match what the control spec claims we do. Reported by daejees. - Fix a typo in an error message when extendcircuit fails that caused us to not follow the \r\n-based delimiter protocol. Reported by daejees. - When tunneling an encrypted directory connection, and its first circuit fails, do not leave it unattached and ask the controller to deal. Fixes the second part of bug 681. - Treat some 403 responses from directory servers as INFO rather than WARN-severity events. o Portability / building / compiling: - When building with --enable-gcc-warnings, check for whether Apple's warning "-Wshorten-64-to-32" is available. - Support compilation to target iPhone; patch from cjacker huang. To build for iPhone, pass the --enable-iphone option to configure. - Port Tor to build and run correctly on Windows CE systems, using the wcecompat library. Contributed by Valerio Lupi. - Detect non-ASCII platforms (if any still exist) and refuse to build there: some of our code assumes that 'A' is 65 and so on. - Clear up some MIPSPro compiler warnings. - Make autoconf search for libevent, openssl, and zlib consistently. - Update deprecated macros in configure.in. - When warning about missing headers, tell the user to let us know if the compile succeeds anyway, so we can downgrade the warning. - Include the current subversion revision as part of the version string: either fetch it directly if we're in an SVN checkout, do some magic to guess it if we're in an SVK checkout, or use the last-detected version if we're building from a .tar.gz. Use this version consistently in log messages. - Correctly report platform name on Windows 95 OSR2 and Windows 98 SE. - Read resolv.conf files correctly on platforms where read() returns partial results on small file reads. - Build without verbose warnings even on gcc 4.2 and 4.3. - On Windows, correctly detect errors when listing the contents of a directory. Fix from lodger. - Run 'make test' as part of 'make dist', so we stop releasing so many development snapshots that fail their unit tests. - Add support to detect Libevent versions in the 1.4.x series on mingw. - Add command-line arguments to unit-test executable so that we can invoke any chosen test from the command line rather than having to run the whole test suite at once; and so that we can turn on logging for the unit tests. - Do not automatically run configure from autogen.sh. This non-standard behavior tended to annoy people who have built other programs. - Fix a macro/CPP interaction that was confusing some compilers: some GCCs don't like #if/#endif pairs inside macro arguments. Fixes bug 707. - Fix macro collision between OpenSSL 0.9.8h and Windows headers. Fixes bug 704; fix from Steven Murdoch. - Correctly detect transparent proxy support on Linux hosts that require in.h to be included before netfilter_ipv4.h. Patch from coderman. o Logging improvements: - When we haven't had any application requests lately, don't bother logging that we have expired a bunch of descriptors. - When attempting to open a logfile fails, tell us why. - Only log guard node status when guard node status has changed. - Downgrade the 3 most common "INFO" messages to "DEBUG". This will make "INFO" 75% less verbose. - When SafeLogging is disabled, log addresses along with all TLS errors. - Report TLS "zero return" case as a "clean close" and "IO error" as a "close". Stop calling closes "unexpected closes": existing Tors don't use SSL_close(), so having a connection close without the TLS shutdown handshake is hardly unexpected. - When we receive a consensus from the future, warn about skew. - Make "not enough dir info yet" warnings describe *why* Tor feels it doesn't have enough directory info yet. - On the USR1 signal, when dmalloc is in use, log the top 10 memory consumers. (We already do this on HUP.) - Give more descriptive well-formedness errors for out-of-range hidden service descriptor/protocol versions. - Stop recommending that every server operator send mail to tor-ops. Resolves bug 597. Bugfix on 0.1.2.x. - Improve skew reporting: try to give the user a better log message about how skewed they are, and how much this matters. - New --quiet command-line option to suppress the default console log. Good in combination with --hash-password. - Don't complain that "your server has not managed to confirm that its ports are reachable" if we haven't been able to build any circuits yet. - Detect the reason for failing to mmap a descriptor file we just wrote, and give a more useful log message. Fixes bug 533. - Always prepend "Bug: " to any log message about a bug. - When dumping memory usage, list bytes used in buffer memory free-lists. - When running with dmalloc, dump more stats on hup and on exit. - Put a platform string (e.g. "Linux i686") in the startup log message, so when people paste just their logs, we know if it's OpenBSD or Windows or what. - When logging memory usage, break down memory used in buffers by buffer type. - When we are reporting the DirServer line we just parsed, we were logging the second stanza of the key fingerprint, not the first. - Even though Windows is equally happy with / and \ as path separators, try to use \ consistently on Windows and / consistently on Unix: it makes the log messages nicer. - On OSX, stop warning the user that kqueue support in libevent is "experimental", since it seems to have worked fine for ages. o Contributed scripts and tools: - Update linux-tor-prio.sh script to allow QoS based on the uid of the Tor process. Patch from Marco Bonetti with tweaks from Mike Perry. - Include the "tor-ctrl.sh" bash script by Stefan Behte to provide Unix users an easy way to script their Tor process (e.g. by adjusting bandwidth based on the time of the day). - In the exitlist script, only consider the most recently published server descriptor for each server. Also, when the user requests a list of servers that _reject_ connections to a given address, explicitly exclude the IPs that also have servers that accept connections to that address. Resolves bug 405. - Include a new contrib/tor-exit-notice.html file that exit relay operators can put on their website to help reduce abuse queries. o Newly deprecated features: - The status/version/num-versioning and status/version/num-concurring GETINFO controller options are no longer useful in the v3 directory protocol: treat them as deprecated, and warn when they're used. - The RedirectExits config option is now deprecated. o Removed features: - Drop the old code to choke directory connections when the corresponding OR connections got full: thanks to the cell queue feature, OR conns don't get full any more. - Remove the old "dns worker" server DNS code: it hasn't been default since 0.1.2.2-alpha, and all the servers are using the new eventdns code. - Remove the code to generate the oldest (v1) directory format. - Remove support for the old bw_accounting file: we've been storing bandwidth accounting information in the state file since 0.1.2.5-alpha. This may result in bandwidth accounting errors if you try to upgrade from 0.1.1.x or earlier, or if you try to downgrade to 0.1.1.x or earlier. - Drop support for OpenSSL version 0.9.6. Just about nobody was using it, it had no AES, and it hasn't seen any security patches since 2004. - Stop overloading the circuit_t.onionskin field for both "onionskin from a CREATE cell that we are waiting for a cpuworker to be assigned" and "onionskin from an EXTEND cell that we are going to send to an OR as soon as we are connected". Might help with bug 600. - Remove the tor_strpartition() function: its logic was confused, and it was only used for one thing that could be implemented far more easily. - Remove the contrib scripts ExerciseServer.py, PathDemo.py, and TorControl.py, as they use the old v0 controller protocol, and are obsoleted by TorFlow anyway. - Drop support for v1 rendezvous descriptors, since we never used them anyway, and the code has probably rotted by now. Based on patch from Karsten Loesing. - Stop allowing address masks that do not correspond to bit prefixes. We have warned about these for a really long time; now it's time to reject them. (Patch from croup.) - Remove an optimization in the AES counter-mode code that assumed that the counter never exceeded 2^68. When the counter can be set arbitrarily as an IV (as it is by Karsten's new hidden services code), this assumption no longer holds. - Disable the SETROUTERPURPOSE controller command: it is now obsolete. Changes in version 0.1.2.19 - 2008-01-17 Tor 0.1.2.19 fixes a huge memory leak on exit relays, makes the default exit policy a little bit more conservative so it's safer to run an exit relay on a home system, and fixes a variety of smaller issues. o Security fixes: - Exit policies now reject connections that are addressed to a relay's public (external) IP address too, unless ExitPolicyRejectPrivate is turned off. We do this because too many relays are running nearby to services that trust them based on network address. o Major bugfixes: - When the clock jumps forward a lot, do not allow the bandwidth buckets to become negative. Fixes bug 544. - Fix a memory leak on exit relays; we were leaking a cached_resolve_t on every successful resolve. Reported by Mike Perry. - Purge old entries from the "rephist" database and the hidden service descriptor database even when DirPort is zero. - Stop thinking that 0.1.2.x directory servers can handle "begin_dir" requests. Should ease bugs 406 and 419 where 0.1.2.x relays are crashing or mis-answering these requests. - When we decide to send a 503 response to a request for servers, do not then also send the server descriptors: this defeats the whole purpose. Fixes bug 539. o Minor bugfixes: - Changing the ExitPolicyRejectPrivate setting should cause us to rebuild our server descriptor. - Fix handling of hex nicknames when answering controller requests for networkstatus by name, or when deciding whether to warn about unknown routers in a config option. (Patch from mwenge.) - Fix a couple of hard-to-trigger autoconf problems that could result in really weird results on platforms whose sys/types.h files define nonstandard integer types. - Don't try to create the datadir when running --verify-config or --hash-password. Resolves bug 540. - If we were having problems getting a particular descriptor from the directory caches, and then we learned about a new descriptor for that router, we weren't resetting our failure count. Reported by lodger. - Although we fixed bug 539 (where servers would send HTTP status 503 responses _and_ send a body too), there are still servers out there that haven't upgraded. Therefore, make clients parse such bodies when they receive them. - Run correctly on systems where rlim_t is larger than unsigned long. This includes some 64-bit systems. - Run correctly on platforms (like some versions of OS X 10.5) where the real limit for number of open files is OPEN_FILES, not rlim_max from getrlimit(RLIMIT_NOFILES). - Avoid a spurious free on base64 failure. - Avoid segfaults on certain complex invocations of router_get_by_hexdigest(). - Fix rare bug on REDIRECTSTREAM control command when called with no port set: it could erroneously report an error when none had happened. Changes in version 0.1.2.18 - 2007-10-28 Tor 0.1.2.18 fixes many problems including crash bugs, problems with hidden service introduction that were causing huge delays, and a big bug that was causing some servers to disappear from the network status lists for a few hours each day. o Major bugfixes (crashes): - If a connection is shut down abruptly because of something that happened inside connection_flushed_some(), do not call connection_finished_flushing(). Should fix bug 451: "connection_stop_writing: Assertion conn->write_event failed" Bugfix on 0.1.2.7-alpha. - Fix possible segfaults in functions called from rend_process_relay_cell(). o Major bugfixes (hidden services): - Hidden services were choosing introduction points uniquely by hexdigest, but when constructing the hidden service descriptor they merely wrote the (potentially ambiguous) nickname. - Clients now use the v2 intro format for hidden service connections: they specify their chosen rendezvous point by identity digest rather than by (potentially ambiguous) nickname. These changes could speed up hidden service connections dramatically. o Major bugfixes (other): - Stop publishing a new server descriptor just because we get a HUP signal. This led (in a roundabout way) to some servers getting dropped from the networkstatus lists for a few hours each day. - When looking for a circuit to cannibalize, consider family as well as identity. Fixes bug 438. Bugfix on 0.1.0.x (which introduced circuit cannibalization). - When a router wasn't listed in a new networkstatus, we were leaving the flags for that router alone -- meaning it remained Named, Running, etc -- even though absence from the networkstatus means that it shouldn't be considered to exist at all anymore. Now we clear all the flags for routers that fall out of the networkstatus consensus. Fixes bug 529. o Minor bugfixes: - Don't try to access (or alter) the state file when running --list-fingerprint or --verify-config or --hash-password. Resolves bug 499. - When generating information telling us how to extend to a given router, do not try to include the nickname if it is absent. Resolves bug 467. - Fix a user-triggerable segfault in expand_filename(). (There isn't a way to trigger this remotely.) - When sending a status event to the controller telling it that an OR address is reachable, set the port correctly. (Previously we were reporting the dir port.) - Fix a minor memory leak whenever a controller sends the PROTOCOLINFO command. Bugfix on 0.1.2.17. - When loading bandwidth history, do not believe any information in the future. Fixes bug 434. - When loading entry guard information, do not believe any information in the future. - When we have our clock set far in the future and generate an onion key, then re-set our clock to be correct, we should not stop the onion key from getting rotated. - On some platforms, accept() can return a broken address. Detect this more quietly, and deal accordingly. Fixes bug 483. - It's not actually an error to find a non-pending entry in the DNS cache when canceling a pending resolve. Don't log unless stuff is fishy. Resolves bug 463. - Don't reset trusted dir server list when we set a configuration option. Patch from Robert Hogan. Changes in version 0.1.2.17 - 2007-08-30 Tor 0.1.2.17 features a new Vidalia version in the Windows and OS X bundles. Vidalia 0.0.14 makes authentication required for the ControlPort in the default configuration, which addresses important security risks. Everybody who uses Vidalia (or another controller) should upgrade. In addition, this Tor update fixes major load balancing problems with path selection, which should speed things up a lot once many people have upgraded. o Major bugfixes (security): - We removed support for the old (v0) control protocol. It has been deprecated since Tor 0.1.1.1-alpha, and keeping it secure has become more of a headache than it's worth. o Major bugfixes (load balancing): - When choosing nodes for non-guard positions, weight guards proportionally less, since they already have enough load. Patch from Mike Perry. - Raise the "max believable bandwidth" from 1.5MB/s to 10MB/s. This will allow fast Tor servers to get more attention. - When we're upgrading from an old Tor version, forget our current guards and pick new ones according to the new weightings. These three load balancing patches could raise effective network capacity by a factor of four. Thanks to Mike Perry for measurements. o Major bugfixes (stream expiration): - Expire not-yet-successful application streams in all cases if they've been around longer than SocksTimeout. Right now there are some cases where the stream will live forever, demanding a new circuit every 15 seconds. Fixes bug 454; reported by lodger. o Minor features (controller): - Add a PROTOCOLINFO controller command. Like AUTHENTICATE, it is valid before any authentication has been received. It tells a controller what kind of authentication is expected, and what protocol is spoken. Implements proposal 119. o Minor bugfixes (performance): - Save on most routerlist_assert_ok() calls in routerlist.c, thus greatly speeding up loading cached-routers from disk on startup. - Disable sentinel-based debugging for buffer code: we squashed all the bugs that this was supposed to detect a long time ago, and now its only effect is to change our buffer sizes from nice powers of two (which platform mallocs tend to like) to values slightly over powers of two (which make some platform mallocs sad). o Minor bugfixes (misc): - If exit bandwidth ever exceeds one third of total bandwidth, then use the correct formula to weight exit nodes when choosing paths. Based on patch from Mike Perry. - Choose perfectly fairly among routers when choosing by bandwidth and weighting by fraction of bandwidth provided by exits. Previously, we would choose with only approximate fairness, and correct ourselves if we ran off the end of the list. - If we require CookieAuthentication but we fail to write the cookie file, we would warn but not exit, and end up in a state where no controller could authenticate. Now we exit. - If we require CookieAuthentication, stop generating a new cookie every time we change any piece of our config. - Refuse to start with certain directory authority keys, and encourage people using them to stop. - Terminate multi-line control events properly. Original patch from tup. - Fix a minor memory leak when we fail to find enough suitable servers to choose a circuit. - Stop leaking part of the descriptor when we run into a particularly unparseable piece of it. Changes in version 0.1.2.16 - 2007-08-01 Tor 0.1.2.16 fixes a critical security vulnerability that allows a remote attacker in certain situations to rewrite the user's torrc configuration file. This can completely compromise anonymity of users in most configurations, including those running the Vidalia bundles, TorK, etc. Or worse. o Major security fixes: - Close immediately after missing authentication on control port; do not allow multiple authentication attempts. Changes in version 0.1.2.15 - 2007-07-17 Tor 0.1.2.15 fixes several crash bugs, fixes some anonymity-related problems, fixes compilation on BSD, and fixes a variety of other bugs. Everybody should upgrade. o Major bugfixes (compilation): - Fix compile on FreeBSD/NetBSD/OpenBSD. Oops. o Major bugfixes (crashes): - Try even harder not to dereference the first character after an mmap(). Reported by lodger. - Fix a crash bug in directory authorities when we re-number the routerlist while inserting a new router. - When the cached-routers file is an even multiple of the page size, don't run off the end and crash. (Fixes bug 455; based on idea from croup.) - Fix eventdns.c behavior on Solaris: It is critical to include orconfig.h _before_ sys/types.h, so that we can get the expected definition of _FILE_OFFSET_BITS. o Major bugfixes (security): - Fix a possible buffer overrun when using BSD natd support. Bug found by croup. - When sending destroy cells from a circuit's origin, don't include the reason for tearing down the circuit. The spec says we didn't, and now we actually don't. Reported by lodger. - Keep streamids from different exits on a circuit separate. This bug may have allowed other routers on a given circuit to inject cells into streams. Reported by lodger; fixes bug 446. - If there's a never-before-connected-to guard node in our list, never choose any guards past it. This way we don't expand our guard list unless we need to. o Minor bugfixes (guard nodes): - Weight guard selection by bandwidth, so that low-bandwidth nodes don't get overused as guards. o Minor bugfixes (directory): - Correctly count the number of authorities that recommend each version. Previously, we were under-counting by 1. - Fix a potential crash bug when we load many server descriptors at once and some of them make others of them obsolete. Fixes bug 458. o Minor bugfixes (hidden services): - Stop tearing down the whole circuit when the user asks for a connection to a port that the hidden service didn't configure. Resolves bug 444. o Minor bugfixes (misc): - On Windows, we were preventing other processes from reading cached-routers while Tor was running. Reported by janbar. - Fix a possible (but very unlikely) bug in picking routers by bandwidth. Add a log message to confirm that it is in fact unlikely. Patch from lodger. - Backport a couple of memory leak fixes. - Backport miscellaneous cosmetic bugfixes. Changes in version 0.1.2.14 - 2007-05-25 Tor 0.1.2.14 changes the addresses of two directory authorities (this change especially affects those who serve or use hidden services), and fixes several other crash- and security-related bugs. o Directory authority changes: - Two directory authorities (moria1 and moria2) just moved to new IP addresses. This change will particularly affect those who serve or use hidden services. o Major bugfixes (crashes): - If a directory server runs out of space in the connection table as it's processing a begin_dir request, it will free the exit stream but leave it attached to the circuit, leading to unpredictable behavior. (Reported by seeess, fixes bug 425.) - Fix a bug in dirserv_remove_invalid() that would cause authorities to corrupt memory under some really unlikely scenarios. - Tighten router parsing rules. (Bugs reported by Benedikt Boss.) - Avoid segfaults when reading from mmaped descriptor file. (Reported by lodger.) o Major bugfixes (security): - When choosing an entry guard for a circuit, avoid using guards that are in the same family as the chosen exit -- not just guards that are exactly the chosen exit. (Reported by lodger.) o Major bugfixes (resource management): - If a directory authority is down, skip it when deciding where to get networkstatus objects or descriptors. Otherwise we keep asking every 10 seconds forever. Fixes bug 384. - Count it as a failure if we fetch a valid network-status but we don't want to keep it. Otherwise we'll keep fetching it and keep not wanting to keep it. Fixes part of bug 422. - If all of our dirservers have given us bad or no networkstatuses lately, then stop hammering them once per minute even when we think they're failed. Fixes another part of bug 422. o Minor bugfixes: - Actually set the purpose correctly for descriptors inserted with purpose=controller. - When we have k non-v2 authorities in our DirServer config, we ignored the last k authorities in the list when updating our network-statuses. - Correctly back-off from requesting router descriptors that we are having a hard time downloading. - Read resolv.conf files correctly on platforms where read() returns partial results on small file reads. - Don't rebuild the entire router store every time we get 32K of routers: rebuild it when the journal gets very large, or when the gaps in the store get very large. o Minor features: - When routers publish SVN revisions in their router descriptors, authorities now include those versions correctly in networkstatus documents. - Warn when using a version of libevent before 1.3b to run a server on OSX or BSD: these versions interact badly with userspace threads. Changes in version 0.1.2.13 - 2007-04-24 This release features some major anonymity fixes, such as safer path selection; better client performance; faster bootstrapping, better address detection, and better DNS support for servers; write limiting as well as read limiting to make servers easier to run; and a huge pile of other features and bug fixes. The bundles also ship with Vidalia 0.0.11. Tor 0.1.2.13 is released in memory of Rob Levin (1955-2006), aka lilo of the Freenode IRC network, remembering his patience and vision for free speech on the Internet. o Major features, client performance: - Weight directory requests by advertised bandwidth. Now we can let servers enable write limiting but still allow most clients to succeed at their directory requests. (We still ignore weights when choosing a directory authority; I hope this is a feature.) - Stop overloading exit nodes -- avoid choosing them for entry or middle hops when the total bandwidth available from non-exit nodes is much higher than the total bandwidth available from exit nodes. - Rather than waiting a fixed amount of time between retrying application connections, we wait only 10 seconds for the first, 10 seconds for the second, and 15 seconds for each retry after that. Hopefully this will improve the expected user experience. - Sometimes we didn't bother sending a RELAY_END cell when an attempt to open a stream fails; now we do in more cases. This should make clients able to find a good exit faster in some cases, since unhandleable requests will now get an error rather than timing out. o Major features, client functionality: - Implement BEGIN_DIR cells, so we can connect to a directory server via TLS to do encrypted directory requests rather than plaintext. Enable via the TunnelDirConns and PreferTunneledDirConns config options if you like. For now, this feature only works if you already have a descriptor for the destination dirserver. - Add support for transparent application connections: this basically bundles the functionality of trans-proxy-tor into the Tor mainline. Now hosts with compliant pf/netfilter implementations can redirect TCP connections straight to Tor without diverting through SOCKS. (Based on patch from tup.) - Add support for using natd; this allows FreeBSDs earlier than 5.1.2 to have ipfw send connections through Tor without using SOCKS. (Patch from Zajcev Evgeny with tweaks from tup.) o Major features, servers: - Setting up a dyndns name for your server is now optional: servers with no hostname or IP address will learn their IP address by asking the directory authorities. This code only kicks in when you would normally have exited with a "no address" error. Nothing's authenticated, so use with care. - Directory servers now spool server descriptors, v1 directories, and v2 networkstatus objects to buffers as needed rather than en masse. They also mmap the cached-routers files. These steps save lots of memory. - Stop requiring clients to have well-formed certificates, and stop checking nicknames in certificates. (Clients have certificates so that they can look like Tor servers, but in the future we might want to allow them to look like regular TLS clients instead. Nicknames in certificates serve no purpose other than making our protocol easier to recognize on the wire.) Implements proposal 106. o Improvements on DNS support: - Add "eventdns" asynchronous dns library originally based on code from Adam Langley. Now we can discard the old rickety dnsworker concept, and support a wider variety of DNS functions. Allows multithreaded builds on NetBSD and OpenBSD again. - Add server-side support for "reverse" DNS lookups (using PTR records so clients can determine the canonical hostname for a given IPv4 address). Only supported by servers using eventdns; servers now announce in their descriptors if they don't support eventdns. - Workaround for name servers (like Earthlink's) that hijack failing DNS requests and replace the no-such-server answer with a "helpful" redirect to an advertising-driven search portal. Also work around DNS hijackers who "helpfully" decline to hijack known-invalid RFC2606 addresses. Config option "ServerDNSDetectHijacking 0" lets you turn it off. - Servers now check for the case when common DNS requests are going to wildcarded addresses (i.e. all getting the same answer), and change their exit policy to reject *:* if it's happening. - When asked to resolve a hostname, don't use non-exit servers unless requested to do so. This allows servers with broken DNS to be useful to the network. - Start passing "ipv4" hints to getaddrinfo(), so servers don't do useless IPv6 DNS resolves. - Specify and implement client-side SOCKS5 interface for reverse DNS lookups (see doc/socks-extensions.txt). Also cache them. - When we change nameservers or IP addresses, reset and re-launch our tests for DNS hijacking. o Improvements on reachability testing: - Servers send out a burst of long-range padding cells once they've established that they're reachable. Spread them over 4 circuits, so hopefully a few will be fast. This exercises bandwidth and bootstraps them into the directory more quickly. - When we find our DirPort to be reachable, publish a new descriptor so we'll tell the world (reported by pnx). - Directory authorities now only decide that routers are reachable if their identity keys are as expected. - Do DirPort reachability tests less often, since a single test chews through many circuits before giving up. - Avoid some false positives during reachability testing: don't try to test via a server that's on the same /24 network as us. - Start publishing one minute or so after we find our ORPort to be reachable. This will help reduce the number of descriptors we have for ourselves floating around, since it's quite likely other things (e.g. DirPort) will change during that minute too. - Routers no longer try to rebuild long-term connections to directory authorities, and directory authorities no longer try to rebuild long-term connections to all servers. We still don't hang up connections in these two cases though -- we need to look at it more carefully to avoid flapping, and we likely need to wait til 0.1.1.x is obsolete. o Improvements on rate limiting: - Enable write limiting as well as read limiting. Now we sacrifice capacity if we're pushing out lots of directory traffic, rather than overrunning the user's intended bandwidth limits. - Include TLS overhead when counting bandwidth usage; previously, we would count only the bytes sent over TLS, but not the bytes used to send them. - Servers decline directory requests much more aggressively when they're low on bandwidth. Otherwise they end up queueing more and more directory responses, which can't be good for latency. - But never refuse directory requests from local addresses. - Be willing to read or write on local connections (e.g. controller connections) even when the global rate limiting buckets are empty. - Flush local controller connection buffers periodically as we're writing to them, so we avoid queueing 4+ megabytes of data before trying to flush. - Revise and clean up the torrc.sample that we ship with; add a section for BandwidthRate and BandwidthBurst. o Major features, NT services: - Install as NT_AUTHORITY\LocalService rather than as SYSTEM; add a command-line flag so that admins can override the default by saying "tor --service install --user "SomeUser"". This will not affect existing installed services. Also, warn the user that the service will look for its configuration file in the service user's %appdata% directory. (We can't do the "hardwire the user's appdata directory" trick any more, since we may not have read access to that directory.) - Support running the Tor service with a torrc not in the same directory as tor.exe and default to using the torrc located in the %appdata%\Tor\ of the user who installed the service. Patch from Matt Edman. - Add an --ignore-missing-torrc command-line option so that we can get the "use sensible defaults if the configuration file doesn't exist" behavior even when specifying a torrc location on the command line. - When stopping an NT service, wait up to 10 sec for it to actually stop. (Patch from Matt Edman; resolves bug 295.) o Directory authority improvements: - Stop letting hibernating or obsolete servers affect uptime and bandwidth cutoffs. - Stop listing hibernating servers in the v1 directory. - Authorities no longer recommend exits as guards if this would shift too much load to the exit nodes. - Authorities now specify server versions in networkstatus. This adds about 2% to the size of compressed networkstatus docs, and allows clients to tell which servers support BEGIN_DIR and which don't. The implementation is forward-compatible with a proposed future protocol version scheme not tied to Tor versions. - DirServer configuration lines now have an orport= option so clients can open encrypted tunnels to the authorities without having downloaded their descriptors yet. Enabled for moria1, moria2, tor26, and lefkada now in the default configuration. - Add a BadDirectory flag to network status docs so that authorities can (eventually) tell clients about caches they believe to be broken. Not used yet. - Allow authorities to list nodes as bad exits in their approved-routers file by fingerprint or by address. If most authorities set a BadExit flag for a server, clients don't think of it as a general-purpose exit. Clients only consider authorities that advertise themselves as listing bad exits. - Patch from Steve Hildrey: Generate network status correctly on non-versioning dirservers. - Have directory authorities allow larger amounts of drift in uptime without replacing the server descriptor: previously, a server that restarted every 30 minutes could have 48 "interesting" descriptors per day. - Reserve the nickname "Unnamed" for routers that can't pick a hostname: any router can call itself Unnamed; directory authorities will never allocate Unnamed to any particular router; clients won't believe that any router is the canonical Unnamed. o Directory mirrors and clients: - Discard any v1 directory info that's over 1 month old (for directories) or over 1 week old (for running-routers lists). - Clients track responses with status 503 from dirservers. After a dirserver has given us a 503, we try not to use it until an hour has gone by, or until we have no dirservers that haven't given us a 503. - When we get a 503 from a directory, and we're not a server, we no longer count the failure against the total number of failures allowed for the object we're trying to download. - Prepare for servers to publish descriptors less often: never discard a descriptor simply for being too old until either it is recommended by no authorities, or until we get a better one for the same router. Make caches consider retaining old recommended routers for even longer. - Directory servers now provide 'Pragma: no-cache' and 'Expires' headers for content, so that we can work better in the presence of caching HTTP proxies. - Stop fetching descriptors if you're not a dir mirror and you haven't tried to establish any circuits lately. (This currently causes some dangerous behavior, because when you start up again you'll use your ancient server descriptors.) o Major fixes, crashes: - Stop crashing when the controller asks us to resetconf more than one config option at once. (Vidalia 0.0.11 does this.) - Fix a longstanding obscure crash bug that could occur when we run out of DNS worker processes, if we're not using eventdns. (Resolves bug 390.) - Fix an assert that could trigger if a controller quickly set then cleared EntryNodes. (Bug found by Udo van den Heuvel.) - Avoid crash when telling controller about stream-status and a stream is detached. - Avoid sending junk to controllers or segfaulting when a controller uses EVENT_NEW_DESC with verbose nicknames. - Stop triggering asserts if the controller tries to extend hidden service circuits (reported by mwenge). - If we start a server with ClientOnly 1, then set ClientOnly to 0 and hup, stop triggering an assert based on an empty onion_key. - Mask out all signals in sub-threads; only the libevent signal handler should be processing them. This should prevent some crashes on some machines using pthreads. (Patch from coderman.) - Disable kqueue on OS X 10.3 and earlier, to fix bug 371. o Major fixes, anonymity/security: - Automatically avoid picking more than one node from the same /16 network when constructing a circuit. Add an "EnforceDistinctSubnets" option to let people disable it if they want to operate private test networks on a single subnet. - When generating bandwidth history, round down to the nearest 1k. When storing accounting data, round up to the nearest 1k. - When we're running as a server, remember when we last rotated onion keys, so that we will rotate keys once they're a week old even if we never stay up for a week ourselves. - If a client asked for a server by name, and there's a named server in our network-status but we don't have its descriptor yet, we could return an unnamed server instead. - Reject (most) attempts to use Tor circuits with length one. (If many people start using Tor as a one-hop proxy, exit nodes become a more attractive target for compromise.) - Just because your DirPort is open doesn't mean people should be able to remotely teach you about hidden service descriptors. Now only accept rendezvous posts if you've got HSAuthoritativeDir set. - Fix a potential race condition in the rpm installer. Found by Stefan Nordhausen. - Do not log IPs with TLS failures for incoming TLS connections. (Fixes bug 382.) o Major fixes, other: - If our system clock jumps back in time, don't publish a negative uptime in the descriptor. - When we start during an accounting interval before it's time to wake up, remember to wake up at the correct time. (May fix bug 342.) - Previously, we would cache up to 16 old networkstatus documents indefinitely, if they came from nontrusted authorities. Now we discard them if they are more than 10 days old. - When we have a state file we cannot parse, tell the user and move it aside. Now we avoid situations where the user starts Tor in 1904, Tor writes a state file with that timestamp in it, the user fixes her clock, and Tor refuses to start. - Publish a new descriptor after we hup/reload. This is important if our config has changed such that we'll want to start advertising our DirPort now, etc. - If we are using an exit enclave and we can't connect, e.g. because its webserver is misconfigured to not listen on localhost, then back off and try connecting from somewhere else before we fail. o New config options or behaviors: - When EntryNodes are configured, rebuild the guard list to contain, in order: the EntryNodes that were guards before; the rest of the EntryNodes; the nodes that were guards before. - Do not warn when individual nodes in the configuration's EntryNodes, ExitNodes, etc are down: warn only when all possible nodes are down. (Fixes bug 348.) - Put a lower-bound on MaxAdvertisedBandwidth. - Start using the state file to store bandwidth accounting data: the bw_accounting file is now obsolete. We'll keep generating it for a while for people who are still using 0.1.2.4-alpha. - Try to batch changes to the state file so that we do as few disk writes as possible while still storing important things in a timely fashion. - The state file and the bw_accounting file get saved less often when the AvoidDiskWrites config option is set. - Make PIDFile work on Windows. - Add internal descriptions for a bunch of configuration options: accessible via controller interface and in comments in saved options files. - Reject *:563 (NNTPS) in the default exit policy. We already reject NNTP by default, so this seems like a sensible addition. - Clients now reject hostnames with invalid characters. This should avoid some inadvertent info leaks. Add an option AllowNonRFC953Hostnames to disable this behavior, in case somebody is running a private network with hosts called @, !, and #. - Check for addresses with invalid characters at the exit as well, and warn less verbosely when they fail. You can override this by setting ServerDNSAllowNonRFC953Addresses to 1. - Remove some options that have been deprecated since at least 0.1.0.x: AccountingMaxKB, LogFile, DebugLogFile, LogLevel, and SysLog. Use AccountingMax instead of AccountingMaxKB, and use Log to set log options. Mark PathlenCoinWeight as obsolete. - Stop accepting certain malformed ports in configured exit policies. - When the user uses bad syntax in the Log config line, stop suggesting other bad syntax as a replacement. - Add new config option "ResolvConf" to let the server operator choose an alternate resolve.conf file when using eventdns. - If one of our entry guards is on the ExcludeNodes list, or the directory authorities don't think it's a good guard, treat it as if it were unlisted: stop using it as a guard, and throw it off the guards list if it stays that way for a long time. - Allow directory authorities to be marked separately as authorities for the v1 directory protocol, the v2 directory protocol, and as hidden service directories, to make it easier to retire old authorities. V1 authorities should set "HSAuthoritativeDir 1" to continue being hidden service authorities too. - Remove 8888 as a LongLivedPort, and add 6697 (IRCS). - Make TrackExitHosts case-insensitive, and fix the behavior of ".suffix" TrackExitHosts items to avoid matching in the middle of an address. - New DirPort behavior: if you have your dirport set, you download descriptors aggressively like a directory mirror, whether or not your ORPort is set. o Docs: - Create a new file ReleaseNotes which was the old ChangeLog. The new ChangeLog file now includes the notes for all development versions too. - Add a new address-spec.txt document to describe our special-case addresses: .exit, .onion, and .noconnnect. - Fork the v1 directory protocol into its own spec document, and mark dir-spec.txt as the currently correct (v2) spec. o Packaging, porting, and contrib - "tor --verify-config" now exits with -1(255) or 0 depending on whether the config options are bad or good. - The Debian package now uses --verify-config when (re)starting, to distinguish configuration errors from other errors. - Adapt a patch from goodell to let the contrib/exitlist script take arguments rather than require direct editing. - Prevent the contrib/exitlist script from printing the same result more than once. - Add support to tor-resolve tool for reverse lookups and SOCKS5. - In the hidden service example in torrc.sample, stop recommending esoteric and discouraged hidden service options. - Patch from Michael Mohr to contrib/cross.sh, so it checks more values before failing, and always enables eventdns. - Try to detect Windows correctly when cross-compiling. - Libevent-1.2 exports, but does not define in its headers, strlcpy. Try to fix this in configure.in by checking for most functions before we check for libevent. - Update RPMs to require libevent 1.2. - Experimentally re-enable kqueue on OSX when using libevent 1.1b or later. Log when we are doing this, so we can diagnose it when it fails. (Also, recommend libevent 1.1b for kqueue and win32 methods; deprecate libevent 1.0b harder; make libevent recommendation system saner.) - Build with recent (1.3+) libevents on platforms that do not define the nonstandard types "u_int8_t" and friends. - Remove architecture from OS X builds. The official builds are now universal binaries. - Run correctly on OS X platforms with case-sensitive filesystems. - Correctly set maximum connection limit on Cygwin. (This time for sure!) - Start compiling on MinGW on Windows (patches from Mike Chiussi and many others). - Start compiling on MSVC6 on Windows (patches from Frediano Ziglio). - Finally fix the openssl warnings from newer gccs that believe that ignoring a return value is okay, but casting a return value and then ignoring it is a sign of madness. - On architectures where sizeof(int)>4, still clamp declarable bandwidth to INT32_MAX. o Minor features, controller: - Warn the user when an application uses the obsolete binary v0 control protocol. We're planning to remove support for it during the next development series, so it's good to give people some advance warning. - Add STREAM_BW events to report per-entry-stream bandwidth use. (Patch from Robert Hogan.) - Rate-limit SIGNEWNYM signals in response to controllers that impolitely generate them for every single stream. (Patch from mwenge; closes bug 394.) - Add a REMAP status to stream events to note that a stream's address has changed because of a cached address or a MapAddress directive. - Make REMAP stream events have a SOURCE (cache or exit), and make them generated in every case where we get a successful connected or resolved cell. - Track reasons for OR connection failure; make these reasons available via the controller interface. (Patch from Mike Perry.) - Add a SOCKS_BAD_HOSTNAME client status event so controllers can learn when clients are sending malformed hostnames to Tor. - Specify and implement some of the controller status events. - Have GETINFO dir/status/* work on hosts with DirPort disabled. - Reimplement GETINFO so that info/names stays in sync with the actual keys. - Implement "GETINFO fingerprint". - Implement "SETEVENTS GUARD" so controllers can get updates on entry guard status as it changes. - Make all connections to addresses of the form ".noconnect" immediately get closed. This lets application/controller combos successfully test whether they're talking to the same Tor by watching for STREAM events. - Add a REASON field to CIRC events; for backward compatibility, this field is sent only to controllers that have enabled the extended event format. Also, add additional reason codes to explain why a given circuit has been destroyed or truncated. (Patches from Mike Perry) - Add a REMOTE_REASON field to extended CIRC events to tell the controller why a remote OR told us to close a circuit. - Stream events also now have REASON and REMOTE_REASON fields, working much like those for circuit events. - There's now a GETINFO ns/... field so that controllers can ask Tor about the current status of a router. - A new event type "NS" to inform a controller when our opinion of a router's status has changed. - Add a GETINFO events/names and GETINFO features/names so controllers can tell which events and features are supported. - A new CLEARDNSCACHE signal to allow controllers to clear the client-side DNS cache without expiring circuits. - Fix CIRC controller events so that controllers can learn the identity digests of non-Named servers used in circuit paths. - Let controllers ask for more useful identifiers for servers. Instead of learning identity digests for un-Named servers and nicknames for Named servers, the new identifiers include digest, nickname, and indication of Named status. Off by default; see control-spec.txt for more information. - Add a "getinfo address" controller command so it can display Tor's best guess to the user. - New controller event to alert the controller when our server descriptor has changed. - Give more meaningful errors on controller authentication failure. - Export the default exit policy via the control port, so controllers don't need to guess what it is / will be later. o Minor bugfixes, controller: - When creating a circuit via the controller, send a 'launched' event when we're done, so we follow the spec better. - Correct the control spec to match how the code actually responds to 'getinfo addr-mappings/*'. Reported by daejees. - The control spec described a GUARDS event, but the code implemented a GUARD event. Standardize on GUARD, but let people ask for GUARDS too. Reported by daejees. - Give the controller END_STREAM_REASON_DESTROY events _before_ we clear the corresponding on_circuit variable, and remember later that we don't need to send a redundant CLOSED event. (Resolves part 3 of bug 367.) - Report events where a resolve succeeded or where we got a socks protocol error correctly, rather than calling both of them "INTERNAL". - Change reported stream target addresses to IP consistently when we finally get the IP from an exit node. - Send log messages to the controller even if they happen to be very long. - Flush ERR-level controller status events just like we currently flush ERR-level log events, so that a Tor shutdown doesn't prevent the controller from learning about current events. - Report the circuit number correctly in STREAM CLOSED events. Bug reported by Mike Perry. - Do not report bizarre values for results of accounting GETINFOs when the last second's write or read exceeds the allotted bandwidth. - Report "unrecognized key" rather than an empty string when the controller tries to fetch a networkstatus that doesn't exist. - When the controller does a "GETINFO network-status", tell it about even those routers whose descriptors are very old, and use long nicknames where appropriate. - Fix handling of verbose nicknames with ORCONN controller events: make them show up exactly when requested, rather than exactly when not requested. - Controller signals now work on non-Unix platforms that don't define SIGUSR1 and SIGUSR2 the way we expect. - Respond to SIGNAL command before we execute the signal, in case the signal shuts us down. Suggested by Karsten Loesing. - Handle reporting OR_CONN_EVENT_NEW events to the controller. o Minor features, code performance: - Major performance improvement on inserting descriptors: change algorithm from O(n^2) to O(n). - Do not rotate onion key immediately after setting it for the first time. - Call router_have_min_dir_info half as often. (This is showing up in some profiles, but not others.) - When using GCC, make log_debug never get called at all, and its arguments never get evaluated, when no debug logs are configured. (This is showing up in some profiles, but not others.) - Statistics dumped by -USR2 now include a breakdown of public key operations, for profiling. - Make the common memory allocation path faster on machines where malloc(0) returns a pointer. - Split circuit_t into origin_circuit_t and or_circuit_t, and split connection_t into edge, or, dir, control, and base structs. These will save quite a bit of memory on busy servers, and they'll also help us track down bugs in the code and bugs in the spec. - Use OpenSSL's AES implementation on platforms where it's faster. This could save us as much as 10% CPU usage. o Minor features, descriptors and descriptor handling: - Avoid duplicate entries on MyFamily line in server descriptor. - When Tor receives a router descriptor that it asked for, but no longer wants (because it has received fresh networkstatuses in the meantime), do not warn the user. Cache the descriptor if we're a cache; drop it if we aren't. - Servers no longer ever list themselves in their "family" line, even if configured to do so. This makes it easier to configure family lists conveniently. o Minor fixes, confusing/misleading log messages: - Display correct results when reporting which versions are recommended, and how recommended they are. (Resolves bug 383.) - Inform the server operator when we decide not to advertise a DirPort due to AccountingMax enabled or a low BandwidthRate. - Only include function names in log messages for info/debug messages. For notice/warn/err, the content of the message should be clear on its own, and printing the function name only confuses users. - Remove even more protocol-related warnings from Tor server logs, such as bad TLS handshakes and malformed begin cells. - Fix bug 314: Tor clients issued "unsafe socks" warnings even when the IP address is mapped through MapAddress to a hostname. - Fix misleading log messages: an entry guard that is "unlisted", as well as not known to be "down" (because we've never heard of it), is not therefore "up". o Minor fixes, old/obsolete behavior: - Start assuming we can use a create_fast cell if we don't know what version a router is running. - We no longer look for identity and onion keys in "identity.key" and "onion.key" -- these were replaced by secret_id_key and secret_onion_key in 0.0.8pre1. - We no longer require unrecognized directory entries to be preceded by "opt". - Drop compatibility with obsolete Tors that permit create cells to have the wrong circ_id_type. - Remove code to special-case "-cvs" ending, since it has not actually mattered since 0.0.9. - Don't re-write the fingerprint file every restart, unless it has changed. o Minor fixes, misc client-side behavior: - Always remove expired routers and networkstatus docs before checking whether we have enough information to build circuits. (Fixes bug 373.) - When computing clock skew from directory HTTP headers, consider what time it was when we finished asking for the directory, not what time it is now. - Make our socks5 handling more robust to broken socks clients: throw out everything waiting on the buffer in between socks handshake phases, since they can't possibly (so the theory goes) have predicted what we plan to respond to them. - Expire socks connections if they spend too long waiting for the handshake to finish. Previously we would let them sit around for days, if the connecting application didn't close them either. - And if the socks handshake hasn't started, don't send a "DNS resolve socks failed" handshake reply; just close it. - If the user asks to use invalid exit nodes, be willing to use unstable ones. - Track unreachable entry guards correctly: don't conflate 'unreachable by us right now' with 'listed as down by the directory authorities'. With the old code, if a guard was unreachable by us but listed as running, it would clog our guard list forever. - Behave correctly in case we ever have a network with more than 2GB/s total advertised capacity. - Claim a commonname of Tor, rather than TOR, in TLS handshakes. - Fix a memory leak when we ask for "all" networkstatuses and we get one we don't recognize. Changes in version 0.1.1.26 - 2006-12-14 o Security bugfixes: - Stop sending the HttpProxyAuthenticator string to directory servers when directory connections are tunnelled through Tor. - Clients no longer store bandwidth history in the state file. - Do not log introduction points for hidden services if SafeLogging is set. o Minor bugfixes: - Fix an assert failure when a directory authority sets AuthDirRejectUnlisted and then receives a descriptor from an unlisted router (reported by seeess). Changes in version 0.1.1.25 - 2006-11-04 o Major bugfixes: - When a client asks us to resolve (rather than connect to) an address, and we have a cached answer, give them the cached answer. Previously, we would give them no answer at all. - We were building exactly the wrong circuits when we predict hidden service requirements, meaning Tor would have to build all its circuits on demand. - If none of our live entry guards have a high uptime, but we require a guard with a high uptime, try adding a new guard before we give up on the requirement. This patch should make long-lived connections more stable on average. - When testing reachability of our DirPort, don't launch new tests when there's already one in progress -- unreachable servers were stacking up dozens of testing streams. o Security bugfixes: - When the user sends a NEWNYM signal, clear the client-side DNS cache too. Otherwise we continue to act on previous information. o Minor bugfixes: - Avoid a memory corruption bug when creating a hash table for the first time. - Avoid possibility of controller-triggered crash when misusing certain commands from a v0 controller on platforms that do not handle printf("%s",NULL) gracefully. - Avoid infinite loop on unexpected controller input. - Don't log spurious warnings when we see a circuit close reason we don't recognize; it's probably just from a newer version of Tor. - Add Vidalia to the OS X uninstaller script, so when we uninstall Tor/Privoxy we also uninstall Vidalia. Changes in version 0.1.1.24 - 2006-09-29 o Major bugfixes: - Allow really slow clients to not hang up five minutes into their directory downloads (suggested by Adam J. Richter). - Fix major performance regression from 0.1.0.x: instead of checking whether we have enough directory information every time we want to do something, only check when the directory information has changed. This should improve client CPU usage by 25-50%. - Don't crash if, after a server has been running for a while, it can't resolve its hostname. - When a client asks us to resolve (not connect to) an address, and we have a cached answer, give them the cached answer. Previously, we would give them no answer at all. o Minor bugfixes: - Allow Tor to start when RunAsDaemon is set but no logs are set. - Don't crash when the controller receives a third argument to an "extendcircuit" request. - Controller protocol fixes: fix encoding in "getinfo addr-mappings" response; fix error code when "getinfo dir/status/" fails. - Fix configure.in to not produce broken configure files with more recent versions of autoconf. Thanks to Clint for his auto* voodoo. - Fix security bug on NetBSD that could allow someone to force uninitialized RAM to be sent to a server's DNS resolver. This only affects NetBSD and other platforms that do not bounds-check tolower(). - Warn user when using libevent 1.1a or earlier with win32 or kqueue methods: these are known to be buggy. - If we're a directory mirror and we ask for "all" network status documents, we would discard status documents from authorities we don't recognize. Changes in version 0.1.1.23 - 2006-07-30 o Major bugfixes: - Fast Tor servers, especially exit nodes, were triggering asserts due to a bug in handling the list of pending DNS resolves. Some bugs still remain here; we're hunting them. - Entry guards could crash clients by sending unexpected input. - More fixes on reachability testing: if you find yourself reachable, then don't ever make any client requests (so you stop predicting circuits), then hup or have your clock jump, then later your IP changes, you won't think circuits are working, so you won't try to test reachability, so you won't publish. o Minor bugfixes: - Avoid a crash if the controller does a resetconf firewallports and then a setconf fascistfirewall=1. - Avoid an integer underflow when the dir authority decides whether a router is stable: we might wrongly label it stable, and compute a slightly wrong median stability, when a descriptor is published later than now. - Fix a place where we might trigger an assert if we can't build our own server descriptor yet. Changes in version 0.1.1.22 - 2006-07-05 o Major bugfixes: - Fix a big bug that was causing servers to not find themselves reachable if they changed IP addresses. Since only 0.1.1.22+ servers can do reachability testing correctly, now we automatically make sure to test via one of these. - Fix to allow clients and mirrors to learn directory info from descriptor downloads that get cut off partway through. - Directory authorities had a bug in deciding if a newly published descriptor was novel enough to make everybody want a copy -- a few servers seem to be publishing new descriptors many times a minute. o Minor bugfixes: - Fix a rare bug that was causing some servers to complain about "closing wedged cpuworkers" and skip some circuit create requests. - Make the Exit flag in directory status documents actually work. Changes in version 0.1.1.21 - 2006-06-10 o Crash and assert fixes from 0.1.1.20: - Fix a rare crash on Tor servers that have enabled hibernation. - Fix a seg fault on startup for Tor networks that use only one directory authority. - Fix an assert from a race condition that occurs on Tor servers while exiting, where various threads are trying to log that they're exiting, and delete the logs, at the same time. - Make our unit tests pass again on certain obscure platforms. o Other fixes: - Add support for building SUSE RPM packages. - Speed up initial bootstrapping for clients: if we are making our first ever connection to any entry guard, then don't mark it down right after that. - When only one Tor server in the network is labelled as a guard, and we've already picked him, we would cycle endlessly picking him again, being unhappy about it, etc. Now we specifically exclude current guards when picking a new guard. - Servers send create cells more reliably after the TLS connection is established: we were sometimes forgetting to send half of them when we had more than one pending. - If we get a create cell that asks us to extend somewhere, but the Tor server there doesn't match the expected digest, we now send a destroy cell back, rather than silently doing nothing. - Make options->RedirectExit work again. - Make cookie authentication for the controller work again. - Stop being picky about unusual characters in the arguments to mapaddress. It's none of our business. - Add a new config option "TestVia" that lets you specify preferred middle hops to use for test circuits. Perhaps this will let me debug the reachability problems better. o Log / documentation fixes: - If we're a server and some peer has a broken TLS certificate, don't log about it unless ProtocolWarnings is set, i.e., we want to hear about protocol violations by others. - Fix spelling of VirtualAddrNetwork in man page. - Add a better explanation at the top of the autogenerated torrc file about what happened to our old torrc. Changes in version 0.1.1.20 - 2006-05-23 o Crash and assert fixes from 0.1.0.17: - Fix assert bug in close_logs() on exit: when we close and delete logs, remove them all from the global "logfiles" list. - Fix an assert error when we're out of space in the connection_list and we try to post a hidden service descriptor (reported by Peter Palfrader). - Fix a rare assert error when we've tried all intro points for a hidden service and we try fetching the service descriptor again: "Assertion conn->state != AP_CONN_STATE_RENDDESC_WAIT failed". - Setconf SocksListenAddress kills Tor if it fails to bind. Now back out and refuse the setconf if it would fail. - If you specify a relative torrc path and you set RunAsDaemon in your torrc, then it chdir()'s to the new directory. If you then HUP, it tries to load the new torrc location, fails, and exits. The fix: no longer allow a relative path to torrc when using -f. - Check for integer overflows in more places, when adding elements to smartlists. This could possibly prevent a buffer overflow on malicious huge inputs. o Security fixes, major: - When we're printing strings from the network, don't try to print non-printable characters. Now we're safer against shell escape sequence exploits, and also against attacks to fool users into misreading their logs. - Implement entry guards: automatically choose a handful of entry nodes and stick with them for all circuits. Only pick new guards when the ones you have are unsuitable, and if the old guards become suitable again, switch back. This will increase security dramatically against certain end-point attacks. The EntryNodes config option now provides some hints about which entry guards you want to use most; and StrictEntryNodes means to only use those. Fixes CVE-2006-0414. - Implement exit enclaves: if we know an IP address for the destination, and there's a running Tor server at that address which allows exit to the destination, then extend the circuit to that exit first. This provides end-to-end encryption and end-to-end authentication. Also, if the user wants a .exit address or enclave, use 4 hops rather than 3, and cannibalize a general circ for it if you can. - Obey our firewall options more faithfully: . If we can't get to a dirserver directly, try going via Tor. . Don't ever try to connect (as a client) to a place our firewall options forbid. . If we specify a proxy and also firewall options, obey the firewall options even when we're using the proxy: some proxies can only proxy to certain destinations. - Make clients regenerate their keys when their IP address changes. - For the OS X package's modified privoxy config file, comment out the "logfile" line so we don't log everything passed through privoxy. - Our TLS handshakes were generating a single public/private keypair for the TLS context, rather than making a new one for each new connection. Oops. (But we were still rotating them periodically, so it's not so bad.) - When we were cannibalizing a circuit with a particular exit node in mind, we weren't checking to see if that exit node was already present earlier in the circuit. Now we are. - Require server descriptors to list IPv4 addresses -- hostnames are no longer allowed. This also fixes potential vulnerabilities to servers providing hostnames as their address and then preferentially resolving them so they can partition users. - Our logic to decide if the OR we connected to was the right guy was brittle and maybe open to a mitm for invalid routers. o Security fixes, minor: - Adjust tor-spec.txt to parameterize cell and key lengths. Now Ian Goldberg can prove things about our handshake protocol more easily. - Make directory authorities generate a separate "guard" flag to mean "would make a good entry guard". Clients now honor the is_guard flag rather than looking at is_fast or is_stable. - Try to list MyFamily elements by key, not by nickname, and warn if we've not heard of a server. - Start using RAND_bytes rather than RAND_pseudo_bytes from OpenSSL. Also, reseed our entropy every hour, not just at startup. And add entropy in 512-bit chunks, not 160-bit chunks. - Refuse server descriptors where the fingerprint line doesn't match the included identity key. Tor doesn't care, but other apps (and humans) might actually be trusting the fingerprint line. - We used to kill the circuit when we receive a relay command we don't recognize. Now we just drop that cell. - Fix a bug found by Lasse Overlier: when we were making internal circuits (intended to be cannibalized later for rendezvous and introduction circuits), we were picking them so that they had useful exit nodes. There was no need for this, and it actually aids some statistical attacks. - Start treating internal circuits and exit circuits separately. It's important to keep them separate because internal circuits have their last hops picked like middle hops, rather than like exit hops. So exiting on them will break the user's expectations. - Fix a possible way to DoS dirservers. - When the client asked for a rendezvous port that the hidden service didn't want to provide, we were sending an IP address back along with the end cell. Fortunately, it was zero. But stop that anyway. o Packaging improvements: - Implement --with-libevent-dir option to ./configure. Improve search techniques to find libevent, and use those for openssl too. - Fix a couple of bugs in OpenSSL detection. Deal better when there are multiple SSLs installed with different versions. - Avoid warnings about machine/limits.h on Debian GNU/kFreeBSD. - On non-gcc compilers (e.g. Solaris's cc), use "-g -O" instead of "-Wall -g -O2". - Make unit tests (and other invocations that aren't the real Tor) run without launching listeners, creating subdirectories, and so on. - The OS X installer was adding a symlink for tor_resolve but the binary was called tor-resolve (reported by Thomas Hardly). - Now we can target arch and OS in rpm builds (contributed by Phobos). Also make the resulting dist-rpm filename match the target arch. - Apply Matt Ghali's --with-syslog-facility patch to ./configure if you log to syslog and want something other than LOG_DAEMON. - Fix the torify (tsocks) config file to not use Tor for localhost connections. - Start shipping socks-extensions.txt, tor-doc-unix.html, tor-doc-server.html, and stylesheet.css in the tarball. - Stop shipping tor-doc.html, INSTALL, and README in the tarball. They are useless now. - Add Peter Palfrader's contributed check-tor script. It lets you easily check whether a given server (referenced by nickname) is reachable by you. - Add BSD-style contributed startup script "rc.subr" from Peter Thoenen. o Directory improvements -- new directory protocol: - See tor/doc/dir-spec.txt for all the juicy details. Key points: - Authorities and caches publish individual descriptors (by digest, by fingerprint, by "all", and by "tell me yours"). - Clients don't download or use the old directory anymore. Now they download network-statuses from the directory authorities, and fetch individual server descriptors as needed from mirrors. - Clients don't download descriptors of non-running servers. - Download descriptors by digest, not by fingerprint. Caches try to download all listed digests from authorities; clients try to download "best" digests from caches. This avoids partitioning and isolating attacks better. - Only upload a new server descriptor when options change, 18 hours have passed, uptime is reset, or bandwidth changes a lot. - Directory authorities silently throw away new descriptors that haven't changed much if the timestamps are similar. We do this to tolerate older Tor servers that upload a new descriptor every 15 minutes. (It seemed like a good idea at the time.) - Clients choose directory servers from the network status lists, not from their internal list of router descriptors. Now they can go to caches directly rather than needing to go to authorities to bootstrap the first set of descriptors. - When picking a random directory, prefer non-authorities if any are known. - Add a new flag to network-status indicating whether the server can answer v2 directory requests too. - Directory mirrors now cache up to 16 unrecognized network-status docs, so new directory authorities will be cached too. - Stop parsing, storing, or using running-routers output (but mirrors still cache and serve it). - Clients consider a threshold of "versioning" directory authorities before deciding whether to warn the user that he's obsolete. - Authorities publish separate sorted lists of recommended versions for clients and for servers. - Change DirServers config line to note which dirs are v1 authorities. - Put nicknames on the DirServer line, so we can refer to them without requiring all our users to memorize their IP addresses. - Remove option when getting directory cache to see whether they support running-routers; they all do now. Replace it with one to see whether caches support v2 stuff. - Stop listing down or invalid nodes in the v1 directory. This reduces its bulk by about 1/3, and reduces load on mirrors. - Mirrors no longer cache the v1 directory as often. - If we as a directory mirror don't know of any v1 directory authorities, then don't try to cache any v1 directories. o Other directory improvements: - Add lefkada.eecs.harvard.edu and tor.dizum.com as fourth and fifth authoritative directory servers. - Directory authorities no longer require an open connection from a server to consider him "reachable". We need this change because when we add new directory authorities, old servers won't know not to hang up on them. - Dir authorities now do their own external reachability testing of each server, and only list as running the ones they found to be reachable. We also send back warnings to the server's logs if it uploads a descriptor that we already believe is unreachable. - Spread the directory authorities' reachability testing over the entire testing interval, so we don't try to do 500 TLS's at once every 20 minutes. - Make the "stable" router flag in network-status be the median of the uptimes of running valid servers, and make clients pay attention to the network-status flags. Thus the cutoff adapts to the stability of the network as a whole, making IRC, IM, etc connections more reliable. - Make the v2 dir's "Fast" flag based on relative capacity, just like "Stable" is based on median uptime. Name everything in the top 7/8 Fast, and only the top 1/2 gets to be a Guard. - Retry directory requests if we fail to get an answer we like from a given dirserver (we were retrying before, but only if we fail to connect). - Return a robots.txt on our dirport to discourage google indexing. o Controller protocol improvements: - Revised controller protocol (version 1) that uses ascii rather than binary: tor/doc/control-spec.txt. Add supporting libraries in python and java and c# so you can use the controller from your applications without caring how our protocol works. - Allow the DEBUG controller event to work again. Mark certain log entries as "don't tell this to controllers", so we avoid cycles. - New controller function "getinfo accounting", to ask how many bytes we've used in this time period. - Add a "resetconf" command so you can set config options like AllowUnverifiedNodes and LongLivedPorts to "". Also, if you give a config option in the torrc with no value, then it clears it entirely (rather than setting it to its default). - Add a "getinfo config-file" to tell us where torrc is. Also expose guard nodes, config options/names. - Add a "quit" command (when when using the controller manually). - Add a new signal "newnym" to "change pseudonyms" -- that is, to stop using any currently-dirty circuits for new streams, so we don't link new actions to old actions. This also occurs on HUP or "signal reload". - If we would close a stream early (e.g. it asks for a .exit that we know would refuse it) but the LeaveStreamsUnattached config option is set by the controller, then don't close it. - Add a new controller event type "authdir_newdescs" that allows controllers to get all server descriptors that were uploaded to a router in its role as directory authority. - New controller option "getinfo desc/all-recent" to fetch the latest server descriptor for every router that Tor knows about. - Fix the controller's "attachstream 0" command to treat conn like it just connected, doing address remapping, handling .exit and .onion idioms, and so on. Now we're more uniform in making sure that the controller hears about new and closing connections. - Permit transitioning from ORPort==0 to ORPort!=0, and back, from the controller. Also, rotate dns and cpu workers if the controller changes options that will affect them; and initialize the dns worker cache tree whether or not we start out as a server. - Add a new circuit purpose 'controller' to let the controller ask for a circuit that Tor won't try to use. Extend the "extendcircuit" controller command to let you specify the purpose if you're starting a new circuit. Add a new "setcircuitpurpose" controller command to let you change a circuit's purpose after it's been created. - Let the controller ask for "getinfo dir/server/foo" so it can ask directly rather than connecting to the dir port. "getinfo dir/status/foo" also works, but currently only if your DirPort is enabled. - Let the controller tell us about certain router descriptors that it doesn't want Tor to use in circuits. Implement "setrouterpurpose" and modify "+postdescriptor" to do this. - If the controller's *setconf commands fail, collect an error message in a string and hand it back to the controller -- don't just tell them to go read their logs. o Scalability, resource management, and performance: - Fix a major load balance bug: we were round-robin reading in 16 KB chunks, and servers with bandwidthrate of 20 KB, while downloading a 600 KB directory, would starve their other connections. Now we try to be a bit more fair. - Be more conservative about whether to advertise our DirPort. The main change is to not advertise if we're running at capacity and either a) we could hibernate ever or b) our capacity is low and we're using a default DirPort. - We weren't cannibalizing circuits correctly for CIRCUIT_PURPOSE_C_ESTABLISH_REND and CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, so we were being forced to build those from scratch. This should make hidden services faster. - Predict required circuits better, with an eye toward making hidden services faster on the service end. - Compress exit policies even more: look for duplicate lines and remove them. - Generate 18.0.0.0/8 address policy format in descs when we can; warn when the mask is not reducible to a bit-prefix. - There used to be two ways to specify your listening ports in a server descriptor: on the "router" line and with a separate "ports" line. Remove support for the "ports" line. - Reduce memory requirements in our structs by changing the order of fields. Replace balanced trees with hash tables. Inline bottleneck smartlist functions. Add a "Map from digest to void*" abstraction so we can do less hex encoding/decoding, and use it in router_get_by_digest(). Many other CPU and memory improvements. - Allow tor_gzip_uncompress to extract as much as possible from truncated compressed data. Try to extract as many descriptors as possible from truncated http responses (when purpose is DIR_PURPOSE_FETCH_ROUTERDESC). - Make circ->onionskin a pointer, not a static array. moria2 was using 125000 circuit_t's after it had been up for a few weeks, which translates to 20+ megs of wasted space. - The private half of our EDH handshake keys are now chosen out of 320 bits, not 1024 bits. (Suggested by Ian Goldberg.) - Stop doing the complex voodoo overkill checking for insecure Diffie-Hellman keys. Just check if it's in [2,p-2] and be happy. - Do round-robin writes for TLS of at most 16 kB per write. This might be more fair on loaded Tor servers. - Do not use unaligned memory access on alpha, mips, or mipsel. It *works*, but is very slow, so we treat them as if it doesn't. o Other bugfixes and improvements: - Start storing useful information to $DATADIR/state, so we can remember things across invocations of Tor. Retain unrecognized lines so we can be forward-compatible, and write a TorVersion line so we can be backward-compatible. - If ORPort is set, Address is not explicitly set, and our hostname resolves to a private IP address, try to use an interface address if it has a public address. Now Windows machines that think of themselves as localhost can guess their address. - Regenerate our local descriptor if it's dirty and we try to use it locally (e.g. if it changes during reachability detection). This was causing some Tor servers to keep publishing the same initial descriptor forever. - Tor servers with dynamic IP addresses were needing to wait 18 hours before they could start doing reachability testing using the new IP address and ports. This is because they were using the internal descriptor to learn what to test, yet they were only rebuilding the descriptor once they decided they were reachable. - It turns out we couldn't bootstrap a network since we added reachability detection in 0.1.0.1-rc. Good thing the Tor network has never gone down. Add an AssumeReachable config option to let servers and authorities bootstrap. When we're trying to build a high-uptime or high-bandwidth circuit but there aren't enough suitable servers, try being less picky rather than simply failing. - Newly bootstrapped Tor networks couldn't establish hidden service circuits until they had nodes with high uptime. Be more tolerant. - Really busy servers were keeping enough circuits open on stable connections that they were wrapping around the circuit_id space. (It's only two bytes.) This exposed a bug where we would feel free to reuse a circuit_id even if it still exists but has been marked for close. Try to fix this bug. Some bug remains. - When we fail to bind or listen on an incoming or outgoing socket, we now close it before refusing, rather than just leaking it. (Thanks to Peter Palfrader for finding.) - Fix a file descriptor leak in start_daemon(). - On Windows, you can't always reopen a port right after you've closed it. So change retry_listeners() to only close and re-open ports that have changed. - Workaround a problem with some http proxies that refuse GET requests that specify "Content-Length: 0". Reported by Adrian. - Recover better from TCP connections to Tor servers that are broken but don't tell you (it happens!); and rotate TLS connections once a week. - Fix a scary-looking but apparently harmless bug where circuits would sometimes start out in state CIRCUIT_STATE_OR_WAIT at servers, and never switch to state CIRCUIT_STATE_OPEN. - Check for even more Windows version flags when writing the platform string in server descriptors, and note any we don't recognize. - Add reasons to DESTROY and RELAY_TRUNCATED cells, so clients can get a better idea of why their circuits failed. Not used yet. - Add TTLs to RESOLVED, CONNECTED, and END_REASON_EXITPOLICY cells. We don't use them yet, but maybe one day our DNS resolver will be able to discover them. - Let people type "tor --install" as well as "tor -install" when they want to make it an NT service. - Looks like we were never delivering deflated (i.e. compressed) running-routers lists, even when asked. Oops. - We were leaking some memory every time the client changed IPs. - Clean up more of the OpenSSL memory when exiting, so we can detect memory leaks better. - Never call free() on tor_malloc()d memory. This will help us use dmalloc to detect memory leaks. - Some Tor servers process billions of cells per day. These statistics are now uint64_t's. - Check [X-]Forwarded-For headers in HTTP requests when generating log messages. This lets people run dirservers (and caches) behind Apache but still know which IP addresses are causing warnings. - Fix minor integer overflow in calculating when we expect to use up our bandwidth allocation before hibernating. - Lower the minimum required number of file descriptors to 1000, so we can have some overhead for Valgrind on Linux, where the default ulimit -n is 1024. - Stop writing the "router.desc" file, ever. Nothing uses it anymore, and its existence is confusing some users. o Config option fixes: - Add a new config option ExitPolicyRejectPrivate which defaults to on. Now all exit policies will begin with rejecting private addresses, unless the server operator explicitly turns it off. - Bump the default bandwidthrate to 3 MB, and burst to 6 MB. - Add new ReachableORAddresses and ReachableDirAddresses options that understand address policies. FascistFirewall is now a synonym for "ReachableORAddresses *:443", "ReachableDirAddresses *:80". - Start calling it FooListenAddress rather than FooBindAddress, since few of our users know what it means to bind an address or port. - If the user gave Tor an odd number of command-line arguments, we were silently ignoring the last one. Now we complain and fail. This wins the oldest-bug prize -- this bug has been present since November 2002, as released in Tor 0.0.0. - If you write "HiddenServicePort 6667 127.0.0.1 6668" in your torrc rather than "HiddenServicePort 6667 127.0.0.1:6668", it would silently ignore the 6668. - If we get a linelist or linelist_s config option from the torrc, e.g. ExitPolicy, and it has no value, warn and skip rather than silently resetting it to its default. - Setconf was appending items to linelists, not clearing them. - Add MyFamily to torrc.sample in the server section, so operators will be more likely to learn that it exists. - Make ContactInfo mandatory for authoritative directory servers. - MaxConn has been obsolete for a while now. Document the ConnLimit config option, which is a *minimum* number of file descriptors that must be available else Tor refuses to start. - Get rid of IgnoreVersion undocumented config option, and make us only warn, never exit, when we're running an obsolete version. - Make MonthlyAccountingStart config option truly obsolete now. - Correct the man page entry on TrackHostExitsExpire. - Let directory authorities start even if they don't specify an Address config option. - Change "AllowUnverifiedNodes" to "AllowInvalidNodes", to reflect the updated flags in our v2 dir protocol. o Config option features: - Add a new config option FastFirstHopPK (on by default) so clients do a trivial crypto handshake for their first hop, since TLS has already taken care of confidentiality and authentication. - Let the user set ControlListenAddress in the torrc. This can be dangerous, but there are some cases (like a secured LAN) where it makes sense. - New config options to help controllers: FetchServerDescriptors and FetchHidServDescriptors for whether to fetch server info and hidserv info or let the controller do it, and PublishServerDescriptor and PublishHidServDescriptors. - Also let the controller set the __AllDirActionsPrivate config option if you want all directory fetches/publishes to happen via Tor (it assumes your controller bootstraps your circuits). - Add "HardwareAccel" config option: support for crypto hardware accelerators via OpenSSL. Off by default, until we find somebody smart who can test it for us. (It appears to produce seg faults in at least some cases.) - New config option "AuthDirRejectUnlisted" for directory authorities as a panic button: if we get flooded with unusable servers we can revert to only listing servers in the approved-routers file. - Directory authorities can now reject/invalidate by key and IP, with the config options "AuthDirInvalid" and "AuthDirReject", or by marking a fingerprint as "!reject" or "!invalid" (as its nickname) in the approved-routers file. This is useful since currently we automatically list servers as running and usable even if we know they're jerks. - Add a new config option TestSocks so people can see whether their applications are using socks4, socks4a, socks5-with-ip, or socks5-with-fqdn. This way they don't have to keep mucking with tcpdump and wondering if something got cached somewhere. - Add "private:*" as an alias in configuration for policies. Now you can simplify your exit policy rather than needing to list every single internal or nonroutable network space. - Accept "private:*" in routerdesc exit policies; not generated yet because older Tors do not understand it. - Add configuration option "V1AuthoritativeDirectory 1" which moria1, moria2, and tor26 have set. - Implement an option, VirtualAddrMask, to set which addresses get handed out in response to mapaddress requests. This works around a bug in tsocks where 127.0.0.0/8 is never socksified. - Add a new config option FetchUselessDescriptors, off by default, for when you plan to run "exitlist" on your client and you want to know about even the non-running descriptors. - SocksTimeout: How long do we let a socks connection wait unattached before we fail it? - CircuitBuildTimeout: Cull non-open circuits that were born at least this many seconds ago. - CircuitIdleTimeout: Cull open clean circuits that were born at least this many seconds ago. - New config option SafeSocks to reject all application connections using unsafe socks protocols. Defaults to off. o Improved and clearer log messages: - Reduce clutter in server logs. We're going to try to make them actually usable now. New config option ProtocolWarnings that lets you hear about how _other Tors_ are breaking the protocol. Off by default. - Divide log messages into logging domains. Once we put some sort of interface on this, it will let people looking at more verbose log levels specify the topics they want to hear more about. - Log server fingerprint on startup, so new server operators don't have to go hunting around their filesystem for it. - Provide dire warnings to any users who set DirServer manually; move it out of torrc.sample and into torrc.complete. - Make the log message less scary when all the dirservers are temporarily unreachable. - When tor_socketpair() fails in Windows, give a reasonable Windows-style errno back. - Improve tor_gettimeofday() granularity on windows. - We were printing the number of idle dns workers incorrectly when culling them. - Handle duplicate lines in approved-routers files without warning. - We were whining about using socks4 or socks5-with-local-lookup even when it's an IP address in the "virtual" range we designed exactly for this case. - Check for named servers when looking them up by nickname; warn when we're calling a non-named server by its nickname; don't warn twice about the same name. - Downgrade the dirserver log messages when whining about unreachability. - Correct "your server is reachable" log entries to indicate that it was self-testing that told us so. - If we're trying to be a Tor server and running Windows 95/98/ME as a server, explain that we'll likely crash. - Provide a more useful warn message when our onion queue gets full: the CPU is too slow or the exit policy is too liberal. - Don't warn when we receive a 503 from a dirserver/cache -- this will pave the way for them being able to refuse if they're busy. - When we fail to bind a listener, try to provide a more useful log message: e.g., "Is Tor already running?" - Only start testing reachability once we've established a circuit. This will make startup on dir authorities less noisy. - Don't try to upload hidden service descriptors until we have established a circuit. - Tor didn't warn when it failed to open a log file. - Warn when listening on a public address for socks. We suspect a lot of people are setting themselves up as open socks proxies, and they have no idea that jerks on the Internet are using them, since they simply proxy the traffic into the Tor network. - Give a useful message when people run Tor as the wrong user, rather than telling them to start chowning random directories. - Fix a harmless bug that was causing Tor servers to log "Got an end because of misc error, but we're not an AP. Closing." - Fix wrong log message when you add a "HiddenServiceNodes" config line without any HiddenServiceDir line (reported by Chris Thomas). - Directory authorities now stop whining so loudly about bad descriptors that they fetch from other dirservers. So when there's a log complaint, it's for sure from a freshly uploaded descriptor. - When logging via syslog, include the pid whenever we provide a log entry. Suggested by Todd Fries. - When we're shutting down and we do something like try to post a server descriptor or rendezvous descriptor, don't complain that we seem to be unreachable. Of course we are, we're shutting down. - Change log line for unreachability to explicitly suggest /etc/hosts as the culprit. Also make it clearer what IP address and ports we're testing for reachability. - Put quotes around user-supplied strings when logging so users are more likely to realize if they add bad characters (like quotes) to the torrc. - NT service patch from Matt Edman to improve error messages on Win32. Changes in version 0.1.0.17 - 2006-02-17 o Crash bugfixes on 0.1.0.x: - When servers with a non-zero DirPort came out of hibernation, sometimes they would trigger an assert. o Other important bugfixes: - On platforms that don't have getrlimit (like Windows), we were artificially constraining ourselves to a max of 1024 connections. Now just assume that we can handle as many as 15000 connections. Hopefully this won't cause other problems. o Backported features: - When we're a server, a client asks for an old-style directory, and our write bucket is empty, don't give it to him. This way small servers can continue to serve the directory *sometimes*, without getting overloaded. - Whenever you get a 503 in response to a directory fetch, try once more. This will become important once servers start sending 503's whenever they feel busy. - Fetch a new directory every 120 minutes, not every 40 minutes. Now that we have hundreds of thousands of users running the old directory algorithm, it's starting to hurt a lot. - Bump up the period for forcing a hidden service descriptor upload from 20 minutes to 1 hour. Changes in version 0.1.0.16 - 2006-01-02 o Crash bugfixes on 0.1.0.x: - On Windows, build with a libevent patch from "I-M Weasel" to avoid corrupting the heap, losing FDs, or crashing when we need to resize the fd_sets. (This affects the Win32 binaries, not Tor's sources.) - It turns out sparc64 platforms crash on unaligned memory access too -- so detect and avoid this. - Handle truncated compressed data correctly (by detecting it and giving an error). - Fix possible-but-unlikely free(NULL) in control.c. - When we were closing connections, there was a rare case that stomped on memory, triggering seg faults and asserts. - Avoid potential infinite recursion when building a descriptor. (We don't know that it ever happened, but better to fix it anyway.) - We were neglecting to unlink marked circuits from soon-to-close OR connections, which caused some rare scribbling on freed memory. - Fix a memory stomping race bug when closing the joining point of two rendezvous circuits. - Fix an assert in time parsing found by Steven Murdoch. o Other bugfixes on 0.1.0.x: - When we're doing reachability testing, provide more useful log messages so the operator knows what to expect. - Do not check whether DirPort is reachable when we are suppressing advertising it because of hibernation. - When building with -static or on Solaris, we sometimes needed -ldl. - One of the dirservers (tor26) changed its IP address. - When we're deciding whether a stream has enough circuits around that can handle it, count the freshly dirty ones and not the ones that are so dirty they won't be able to handle it. - When we're expiring old circuits, we had a logic error that caused us to close new rendezvous circuits rather than old ones. - Give a more helpful log message when you try to change ORPort via the controller: you should upgrade Tor if you want that to work. - We were failing to parse Tor versions that start with "Tor ". - Tolerate faulty streams better: when a stream fails for reason exitpolicy, stop assuming that the router is lying about his exit policy. When a stream fails for reason misc, allow it to retry just as if it was resolvefailed. When a stream has failed three times, reset its failure count so we can try again and get all three tries. Changes in version 0.1.0.15 - 2005-09-23 o Bugfixes on 0.1.0.x: - Reject ports 465 and 587 (spam targets) in default exit policy. - Don't crash when we don't have any spare file descriptors and we try to spawn a dns or cpu worker. - Get rid of IgnoreVersion undocumented config option, and make us only warn, never exit, when we're running an obsolete version. - Don't try to print a null string when your server finds itself to be unreachable and the Address config option is empty. - Make the numbers in read-history and write-history into uint64s, so they don't overflow and publish negatives in the descriptor. - Fix a minor memory leak in smartlist_string_remove(). - We were only allowing ourselves to upload a server descriptor at most every 20 minutes, even if it changed earlier than that. - Clean up log entries that pointed to old URLs. Changes in version 0.1.0.14 - 2005-08-08 o Bugfixes on 0.1.0.x: - Fix the other half of the bug with crypto handshakes (CVE-2005-2643). - Fix an assert trigger if you send a 'signal term' via the controller when it's listening for 'event info' messages. Changes in version 0.1.0.13 - 2005-08-04 o Bugfixes on 0.1.0.x: - Fix a critical bug in the security of our crypto handshakes. - Fix a size_t underflow in smartlist_join_strings2() that made it do bad things when you hand it an empty smartlist. - Fix Windows installer to ship Tor license (thanks to Aphex for pointing out this oversight) and put a link to the doc directory in the start menu. - Explicitly set no-unaligned-access for sparc: it turns out the new gcc's let you compile broken code, but that doesn't make it not-broken. Changes in version 0.1.0.12 - 2005-07-18 o New directory servers: - tor26 has changed IP address. o Bugfixes on 0.1.0.x: - Fix a possible double-free in tor_gzip_uncompress(). - When --disable-threads is set, do not search for or link against pthreads libraries. - Don't trigger an assert if an authoritative directory server claims its dirport is 0. - Fix bug with removing Tor as an NT service: some people were getting "The service did not return an error." Thanks to Matt Edman for the fix. Changes in version 0.1.0.11 - 2005-06-30 o Bugfixes on 0.1.0.x: - Fix major security bug: servers were disregarding their exit policies if clients behaved unexpectedly. - Make OS X init script check for missing argument, so we don't confuse users who invoke it incorrectly. - Fix a seg fault in "tor --hash-password foo". - The MAPADDRESS control command was broken. Changes in version 0.1.0.10 - 2005-06-14 o Fixes on Win32: - Make NT services work and start on startup on Win32 (based on patch by Matt Edman). See the FAQ entry for details. - Make 'platform' string in descriptor more accurate for Win32 servers, so it's not just "unknown platform". - REUSEADDR on normal platforms means you can rebind to the port right after somebody else has let it go. But REUSEADDR on Win32 means you can bind to the port _even when somebody else already has it bound_! So, don't do that on Win32. - Clean up the log messages when starting on Win32 with no config file. - Allow seeding the RNG on Win32 even when you're not running as Administrator. If seeding the RNG on Win32 fails, quit. o Assert / crash bugs: - Refuse relay cells that claim to have a length larger than the maximum allowed. This prevents a potential attack that could read arbitrary memory (e.g. keys) from an exit server's process (CVE-2005-2050). - If unofficial Tor clients connect and send weird TLS certs, our Tor server triggers an assert. Stop asserting, and start handling TLS errors better in other situations too. - Fix a race condition that can trigger an assert when we have a pending create cell and an OR connection attempt fails. o Resource leaks: - Use pthreads for worker processes rather than forking. This was forced because when we forked, we ended up wasting a lot of duplicate ram over time. - Also switch to foo_r versions of some library calls to allow reentry and threadsafeness. - Implement --disable-threads configure option. Disable threads on netbsd and openbsd by default, because they have no reentrant resolver functions (!), and on solaris since it has other threading issues. - Fix possible bug on threading platforms (e.g. win32) which was leaking a file descriptor whenever a cpuworker or dnsworker died. - Fix a minor memory leak when somebody establishes an introduction point at your Tor server. - Fix possible memory leak in tor_lookup_hostname(). (Thanks to Adam Langley.) - Add ./configure --with-dmalloc option, to track memory leaks. - And try to free all memory on closing, so we can detect what we're leaking. o Protocol correctness: - When we've connected to an OR and handshaked but didn't like the result, we were closing the conn without sending destroy cells back for pending circuits. Now send those destroys. - Start sending 'truncated' cells back rather than destroy cells if the circuit closes in front of you. This means we won't have to abandon partially built circuits. - Handle changed router status correctly when dirserver reloads fingerprint file. We used to be dropping all unverified descriptors right then. The bug was hidden because we would immediately fetch a directory from another dirserver, which would include the descriptors we just dropped. - Revise tor-spec to add more/better stream end reasons. - Revise all calls to connection_edge_end to avoid sending 'misc', and to take errno into account where possible. - Client now retries when streams end early for 'hibernating' or 'resource limit' reasons, rather than failing them. - Try to be more zealous about calling connection_edge_end when things go bad with edge conns in connection.c. o Robustness improvements: - Better handling for heterogeneous / unreliable nodes: - Annotate circuits with whether they aim to contain high uptime nodes and/or high capacity nodes. When building circuits, choose appropriate nodes. - This means that every single node in an intro rend circuit, not just the last one, will have a minimum uptime. - New config option LongLivedPorts to indicate application streams that will want high uptime circuits. - Servers reset uptime when a dir fetch entirely fails. This hopefully reflects stability of the server's network connectivity. - If somebody starts his tor server in Jan 2004 and then fixes his clock, don't make his published uptime be a year. - Reset published uptime when we wake up from hibernation. - Introduce a notion of 'internal' circs, which are chosen without regard to the exit policy of the last hop. Intro and rendezvous circs must be internal circs, to avoid leaking information. Resolve and connect streams can use internal circs if they want. - New circuit pooling algorithm: keep track of what destination ports we've used recently (start out assuming we'll want to use 80), and make sure to have enough circs around to satisfy these ports. Also make sure to have 2 internal circs around if we've required internal circs lately (and with high uptime if we've seen that lately too). - Turn addr_policy_compare from a tristate to a quadstate; this should help address our "Ah, you allow 1.2.3.4:80. You are a good choice for google.com" problem. - When a client asks us for a dir mirror and we don't have one, launch an attempt to get a fresh one. - First cut at support for "create-fast" cells. Clients can use these when extending to their first hop, since the TLS already provides forward secrecy and authentication. Not enabled on clients yet. o Reachability testing. - Your Tor server will automatically try to see if its ORPort and DirPort are reachable from the outside, and it won't upload its descriptor until it decides at least ORPort is reachable (when DirPort is not yet found reachable, publish it as zero). - When building testing circs for ORPort testing, use only high-bandwidth nodes, so fewer circuits fail. - Notice when our IP changes, and reset stats/uptime/reachability. - Authdirservers don't do ORPort reachability detection, since they're in clique mode, so it will be rare to find a server not already connected to them. - Authdirservers now automatically approve nodes running 0.1.0.2-rc or later. o Dirserver fixes: - Now we allow two unverified servers with the same nickname but different keys. But if a nickname is verified, only that nickname+key are allowed. - If you're an authdirserver connecting to an address:port, and it's not the OR you were expecting, forget about that descriptor. If he *was* the one you were expecting, then forget about all other descriptors for that address:port. - Allow servers to publish descriptors from 12 hours in the future. Corollary: only whine about clock skew from the dirserver if he's a trusted dirserver (since now even verified servers could have quite wrong clocks). - Require servers that use the default dirservers to have public IP addresses. We have too many servers that are configured with private IPs and their admins never notice the log entries complaining that their descriptors are being rejected. o Efficiency improvements: - Use libevent. Now we can use faster async cores (like epoll, kpoll, and /dev/poll), and hopefully work better on Windows too. - Apple's OS X 10.4.0 ships with a broken kqueue API, and using kqueue on 10.3.9 causes kernel panics. Don't use kqueue on OS X. - Find libevent even if it's hiding in /usr/local/ and your CFLAGS and LDFLAGS don't tell you to look there. - Be able to link with libevent as a shared library (the default after 1.0d), even if it's hiding in /usr/local/lib and even if you haven't added /usr/local/lib to your /etc/ld.so.conf, assuming you're running gcc. Otherwise fail and give a useful error message. - Switch to a new buffer management algorithm, which tries to avoid reallocing and copying quite as much. In first tests it looks like it uses *more* memory on average, but less cpu. - Switch our internal buffers implementation to use a ring buffer, to hopefully improve performance for fast servers a lot. - Reenable the part of the code that tries to flush as soon as an OR outbuf has a full TLS record available. Perhaps this will make OR outbufs not grow as huge except in rare cases, thus saving lots of CPU time plus memory. - Improve performance for dirservers: stop re-parsing the whole directory every time you regenerate it. - Keep a big splay tree of (circid,orconn)->circuit mappings to make it much faster to look up a circuit for each relay cell. - Remove most calls to assert_all_pending_dns_resolves_ok(), since they're eating our cpu on exit nodes. - Stop wasting time doing a case insensitive comparison for every dns name every time we do any lookup. Canonicalize the names to lowercase when you first see them. o Hidden services: - Handle unavailable hidden services better. Handle slow or busy hidden services better. - Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND circ as necessary, if there are any completed ones lying around when we try to launch one. - Make hidden services try to establish a rendezvous for 30 seconds after fetching the descriptor, rather than for n (where n=3) attempts to build a circuit. - Adjust maximum skew and age for rendezvous descriptors: let skew be 48 hours rather than 90 minutes. - Reject malformed .onion addresses rather then passing them on as normal web requests. o Controller: - More Tor controller support. See http://tor.eff.org/doc/control-spec.txt for all the new features, including signals to emulate unix signals from any platform; redirectstream; extendcircuit; mapaddress; getinfo; postdescriptor; closestream; closecircuit; etc. - Encode hashed controller passwords in hex instead of base64, to make it easier to write controllers. - Revise control spec and implementation to allow all log messages to be sent to controller with their severities intact (suggested by Matt Edman). Disable debug-level logs while delivering a debug-level log to the controller, to prevent loop. Update TorControl to handle new log event types. o New config options/defaults: - Begin scrubbing sensitive strings from logs by default. Turn off the config option SafeLogging if you need to do debugging. - New exit policy: accept most low-numbered ports, rather than rejecting most low-numbered ports. - Put a note in the torrc about abuse potential with the default exit policy. - Add support for CONNECTing through https proxies, with "HttpsProxy" config option. - Add HttpProxyAuthenticator and HttpsProxyAuthenticator support based on patch from Adam Langley (basic auth only). - Bump the default BandwidthRate from 1 MB to 2 MB, to accommodate the fast servers that have been joining lately. (Clients are now willing to load balance over up to 2 MB of advertised bandwidth capacity too.) - New config option MaxAdvertisedBandwidth which lets you advertise a low bandwidthrate (to not attract as many circuits) while still allowing a higher bandwidthrate in reality. - Require BandwidthRate to be at least 20kB/s for servers. - Add a NoPublish config option, so you can be a server (e.g. for testing running Tor servers in other Tor networks) without publishing your descriptor to the primary dirservers. - Add a new AddressMap config directive to rewrite incoming socks addresses. This lets you, for example, declare an implicit required exit node for certain sites. - Add a new TrackHostExits config directive to trigger addressmaps for certain incoming socks addresses -- for sites that break when your exit keeps changing (based on patch from Mike Perry). - Split NewCircuitPeriod option into NewCircuitPeriod (30 secs), which describes how often we retry making new circuits if current ones are dirty, and MaxCircuitDirtiness (10 mins), which describes how long we're willing to make use of an already-dirty circuit. - Change compiled-in SHUTDOWN_WAIT_LENGTH from a fixed 30 secs to a config option "ShutdownWaitLength" (when using kill -INT on servers). - Fix an edge case in parsing config options: if they say "--" on the commandline, it's not a config option (thanks weasel). - New config option DirAllowPrivateAddresses for authdirservers. Now by default they refuse router descriptors that have non-IP or private-IP addresses. - Change DirFetchPeriod/StatusFetchPeriod to have a special "Be smart" default value: low for servers and high for clients. - Some people were putting "Address " in their torrc, and they had a buggy resolver that resolved " " to 0.0.0.0. Oops. - If DataDir is ~/.tor, and that expands to /.tor, then default to LOCALSTATEDIR/tor instead. - Implement --verify-config command-line option to check if your torrc is valid without actually launching Tor. o Logging improvements: - When dirservers refuse a server descriptor, we now log its contactinfo, platform, and the poster's IP address. - Only warn once per nickname from add_nickname_list_to_smartlist() per failure, so an entrynode or exitnode choice that's down won't yell so much. - When we're connecting to an OR and he's got a different nickname/key than we were expecting, only complain loudly if we're an OP or a dirserver. Complaining loudly to the OR admins just confuses them. - Whine at you if you're a server and you don't set your contactinfo. - Warn when exit policy implicitly allows local addresses. - Give a better warning when some other server advertises an ORPort that is actually an apache running ssl. - If we get an incredibly skewed timestamp from a dirserver mirror that isn't a verified OR, don't warn -- it's probably him that's wrong. - When a dirserver causes you to give a warn, mention which dirserver it was. - Initialize libevent later in the startup process, so the logs are already established by the time we start logging libevent warns. - Use correct errno on win32 if libevent fails. - Check and warn about known-bad/slow libevent versions. - Stop warning about sigpipes in the logs. We're going to pretend that getting these occassionally is normal and fine. o New contrib scripts: - New experimental script tor/contrib/exitlist: a simple python script to parse directories and find Tor nodes that exit to listed addresses/ports. - New experimental script tor/contrib/ExerciseServer.py (needs more work) that uses the controller interface to build circuits and fetch pages over them. This will help us bootstrap servers that have lots of capacity but haven't noticed it yet. - New experimental script tor/contrib/PathDemo.py (needs more work) that uses the controller interface to let you choose whole paths via addresses like "...path" - New contributed script "privoxy-tor-toggle" to toggle whether Privoxy uses Tor. Seems to be configured for Debian by default. - Have torctl.in/tor.sh.in check for location of su binary (needed on FreeBSD) o Misc bugfixes: - chdir() to your datadirectory at the *end* of the daemonize process, not the beginning. This was a problem because the first time you run tor, if your datadir isn't there, and you have runasdaemon set to 1, it will try to chdir to it before it tries to create it. Oops. - Fix several double-mark-for-close bugs, e.g. where we were finding a conn for a cell even if that conn is already marked for close. - Stop most cases of hanging up on a socks connection without sending the socks reject. - Fix a bug in the RPM package: set home directory for _tor to something more reasonable when first installing. - Stop putting nodename in the Platform string in server descriptors. It doesn't actually help, and it is confusing/upsetting some people. - When using preferred entry or exit nodes, ignore whether the circuit wants uptime or capacity. They asked for the nodes, they get the nodes. - Tie MAX_DIR_SIZE to MAX_BUF_SIZE, so now directory sizes won't get artificially capped at 500kB. - Cache local dns resolves correctly even when they're .exit addresses. - If we're hibernating and we get a SIGINT, exit immediately. - tor-resolve requests were ignoring .exit if there was a working circuit they could use instead. - Pay more attention to the ClientOnly config option. - Resolve OS X installer bugs: stop claiming to be 0.0.9.2 in certain installer screens; and don't put stuff into StartupItems unless the user asks you to. o Misc features: - Rewrite address "serifos.exit" to "externalIP.serifos.exit" rather than just rejecting it. - If our clock jumps forward by 100 seconds or more, assume something has gone wrong with our network and abandon all not-yet-used circs. - When an application is using socks5, give him the whole variety of potential socks5 responses (connect refused, host unreachable, etc), rather than just "success" or "failure". - A more sane version numbering system. See http://tor.eff.org/cvs/tor/doc/version-spec.txt for details. - Change version parsing logic: a version is "obsolete" if it is not recommended and (1) there is a newer recommended version in the same series, or (2) there are no recommended versions in the same series, but there are some recommended versions in a newer series. A version is "new" if it is newer than any recommended version in the same series. - Report HTTP reasons to client when getting a response from directory servers -- so you can actually know what went wrong. - Reject odd-looking addresses at the client (e.g. addresses that contain a colon), rather than having the server drop them because they're malformed. - Stop publishing socksport in the directory, since it's not actually meant to be public. For compatibility, publish a 0 there for now. - Since we ship our own Privoxy on OS X, tweak it so it doesn't write cookies to disk and doesn't log each web request to disk. (Thanks to Brett Carrington for pointing this out.) - Add OSX uninstall instructions. An actual uninstall script will come later. - Add "opt hibernating 1" to server descriptor to make it clearer whether the server is hibernating. Changes in version 0.0.9.10 - 2005-06-16 o Bugfixes on 0.0.9.x (backported from 0.1.0.10): - Refuse relay cells that claim to have a length larger than the maximum allowed. This prevents a potential attack that could read arbitrary memory (e.g. keys) from an exit server's process (CVE-2005-2050). Changes in version 0.0.9.9 - 2005-04-23 o Bugfixes on 0.0.9.x: - If unofficial Tor clients connect and send weird TLS certs, our Tor server triggers an assert. This release contains a minimal backport from the broader fix that we put into 0.1.0.4-rc. Changes in version 0.0.9.8 - 2005-04-07 o Bugfixes on 0.0.9.x: - We have a bug that I haven't found yet. Sometimes, very rarely, cpuworkers get stuck in the 'busy' state, even though the cpuworker thinks of itself as idle. This meant that no new circuits ever got established. Here's a workaround to kill any cpuworker that's been busy for more than 100 seconds. Changes in version 0.0.9.7 - 2005-04-01 o Bugfixes on 0.0.9.x: - Fix another race crash bug (thanks to Glenn Fink for reporting). - Compare identity to identity, not to nickname, when extending to a router not already in the directory. This was preventing us from extending to unknown routers. Oops. - Make sure to create OS X Tor user in <500 range, so we aren't creating actual system users. - Note where connection-that-hasn't-sent-end was marked, and fix a few really loud instances of this harmless bug (it's fixed more in 0.1.0.x). Changes in version 0.0.9.6 - 2005-03-24 o Bugfixes on 0.0.9.x (crashes and asserts): - Add new end stream reasons to maintainance branch. Fix bug where reason (8) could trigger an assert. Prevent bug from recurring. - Apparently win32 stat wants paths to not end with a slash. - Fix assert triggers in assert_cpath_layer_ok(), where we were blowing away the circuit that conn->cpath_layer points to, then checking to see if the circ is well-formed. Backport check to make sure we dont use the cpath on a closed connection. - Prevent circuit_resume_edge_reading_helper() from trying to package inbufs for marked-for-close streams. - Don't crash on hup if your options->address has become unresolvable. - Some systems (like OS X) sometimes accept() a connection and tell you the remote host is 0.0.0.0:0. If this happens, due to some other mis-features, we get confused; so refuse the conn for now. o Bugfixes on 0.0.9.x (other): - Fix harmless but scary "Unrecognized content encoding" warn message. - Add new stream error reason: TORPROTOCOL reason means "you are not speaking a version of Tor I understand; say bye-bye to your stream." - Be willing to cache directories from up to ROUTER_MAX_AGE seconds into the future, now that we are more tolerant of skew. This resolves a bug where a Tor server would refuse to cache a directory because all the directories it gets are too far in the future; yet the Tor server never logs any complaints about clock skew. - Mac packaging magic: make man pages useable, and do not overwrite existing torrc files. - Make OS X log happily to /var/log/tor/tor.log Changes in version 0.0.9.5 - 2005-02-22 o Bugfixes on 0.0.9.x: - Fix an assert race at exit nodes when resolve requests fail. - Stop picking unverified dir mirrors--it only leads to misery. - Patch from Matt Edman to make NT services work better. Service support is still not compiled into the executable by default. - Patch from Dmitri Bely so the Tor service runs better under the win32 SYSTEM account. - Make tor-resolve actually work (?) on Win32. - Fix a sign bug when getrlimit claims to have 4+ billion file descriptors available. - Stop refusing to start when bandwidthburst == bandwidthrate. - When create cells have been on the onion queue more than five seconds, just send back a destroy and take them off the list. Changes in version 0.0.9.4 - 2005-02-03 o Bugfixes on 0.0.9: - Fix an assert bug that took down most of our servers: when a server claims to have 1 GB of bandwidthburst, don't freak out. - Don't crash as badly if we have spawned the max allowed number of dnsworkers, or we're out of file descriptors. - Block more file-sharing ports in the default exit policy. - MaxConn is now automatically set to the hard limit of max file descriptors we're allowed (ulimit -n), minus a few for logs, etc. - Give a clearer message when servers need to raise their ulimit -n when they start running out of file descriptors. - SGI Compatibility patches from Jan Schaumann. - Tolerate a corrupt cached directory better. - When a dirserver hasn't approved your server, list which one. - Go into soft hibernation after 95% of the bandwidth is used, not 99%. This is especially important for daily hibernators who have a small accounting max. Hopefully it will result in fewer cut connections when the hard hibernation starts. - Load-balance better when using servers that claim more than 800kB/s of capacity. - Make NT services work (experimental, only used if compiled in). Changes in version 0.0.9.3 - 2005-01-21 o Bugfixes on 0.0.9: - Backport the cpu use fixes from main branch, so busy servers won't need as much processor time. - Work better when we go offline and then come back, or when we run Tor at boot before the network is up. We do this by optimistically trying to fetch a new directory whenever an application request comes in and we think we're offline -- the human is hopefully a good measure of when the network is back. - Backport some minimal hidserv bugfixes: keep rend circuits open as long as you keep using them; actually publish hidserv descriptors shortly after they change, rather than waiting 20-40 minutes. - Enable Mac startup script by default. - Fix duplicate dns_cancel_pending_resolve reported by Giorgos Pallas. - When you update AllowUnverifiedNodes or FirewallPorts via the controller's setconf feature, we were always appending, never resetting. - When you update HiddenServiceDir via setconf, it was screwing up the order of reading the lines, making it fail. - Do not rewrite a cached directory back to the cache; otherwise we will think it is recent and not fetch a newer one on startup. - Workaround for webservers that lie about Content-Encoding: Tor now tries to autodetect compressed directories and compression itself. This lets us Proxypass dir fetches through apache. Changes in version 0.0.9.2 - 2005-01-04 o Bugfixes on 0.0.9 (crashes and asserts): - Fix an assert on startup when the disk is full and you're logging to a file. - If you do socks4 with an IP of 0.0.0.x but *don't* provide a socks4a style address, then we'd crash. - Fix an assert trigger when the running-routers string we get from a dirserver is broken. - Make worker threads start and run on win32. Now win32 servers may work better. - Bandaid (not actually fix, but now it doesn't crash) an assert where the dns worker dies mysteriously and the main Tor process doesn't remember anything about the address it was resolving. o Bugfixes on 0.0.9 (Win32): - Workaround for brain-damaged __FILE__ handling on MSVC: keep Nick's name out of the warning/assert messages. - Fix a superficial "unhandled error on read" bug on win32. - The win32 installer no longer requires a click-through for our license, since our Free Software license grants rights but does not take any away. - Win32: When connecting to a dirserver fails, try another one immediately. (This was already working for non-win32 Tors.) - Stop trying to parse $HOME on win32 when hunting for default DataDirectory. - Make tor-resolve.c work on win32 by calling network_init(). o Bugfixes on 0.0.9 (other): - Make 0.0.9.x build on Solaris again. - Due to a fencepost error, we were blowing away the \n when reporting confvalue items in the controller. So asking for multiple config values at once couldn't work. - When listing circuits that are pending on an opening OR connection, if we're an OR we were listing circuits that *end* at us as being pending on every listener, dns/cpu worker, etc. Stop that. - Dirservers were failing to create 'running-routers' or 'directory' strings if we had more than some threshold of routers. Fix them so they can handle any number of routers. - Fix a superficial "Duplicate mark for close" bug. - Stop checking for clock skew for OR connections, even for servers. - Fix a fencepost error that was chopping off the last letter of any nickname that is the maximum allowed nickname length. - Update URLs in log messages so they point to the new website. - Fix a potential problem in mangling server private keys while writing to disk (not triggered yet, as far as we know). - Include the licenses for other free software we include in Tor, now that we're shipping binary distributions more regularly. Changes in version 0.0.9.1 - 2004-12-15 o Bugfixes on 0.0.9: - Make hibernation actually work. - Make HashedControlPassword config option work. - When we're reporting event circuit status to a controller, don't use the stream status code. Changes in version 0.0.9 - 2004-12-12 o Bugfixes on 0.0.8.1 (Crashes and asserts): - Catch and ignore SIGXFSZ signals when log files exceed 2GB; our write() call will fail and we handle it there. - When we run out of disk space, or other log writing error, don't crash. Just stop logging to that log and continue. - Fix isspace() and friends so they still make Solaris happy but also so they don't trigger asserts on win32. - Fix assert failure on malformed socks4a requests. - Fix an assert bug where a hidden service provider would fail if the first hop of his rendezvous circuit was down. - Better handling of size_t vs int, so we're more robust on 64 bit platforms. o Bugfixes on 0.0.8.1 (Win32): - Make windows sockets actually non-blocking (oops), and handle win32 socket errors better. - Fix parse_iso_time on platforms without strptime (eg win32). - win32: when being multithreaded, leave parent fdarray open. - Better handling of winsock includes on non-MSV win32 compilers. - Change our file IO stuff (especially wrt OpenSSL) so win32 is happier. - Make unit tests work on win32. o Bugfixes on 0.0.8.1 (Path selection and streams): - Calculate timeout for waiting for a connected cell from the time we sent the begin cell, not from the time the stream started. If it took a long time to establish the circuit, we would time out right after sending the begin cell. - Fix router_compare_addr_to_addr_policy: it was not treating a port of * as always matching, so we were picking reject *:* nodes as exit nodes too. Oops. - When read() failed on a stream, we would close it without sending back an end. So 'connection refused' would simply be ignored and the user would get no response. - Stop a sigpipe: when an 'end' cell races with eof from the app, we shouldn't hold-open-until-flush if the eof arrived first. - Let resolve conns retry/expire also, rather than sticking around forever. - Fix more dns related bugs: send back resolve_failed and end cells more reliably when the resolve fails, rather than closing the circuit and then trying to send the cell. Also attach dummy resolve connections to a circuit *before* calling dns_resolve(), to fix a bug where cached answers would never be sent in RESOLVED cells. o Bugfixes on 0.0.8.1 (Circuits): - Finally fix a bug that's been plaguing us for a year: With high load, circuit package window was reaching 0. Whenever we got a circuit-level sendme, we were reading a lot on each socket, but only writing out a bit. So we would eventually reach eof. This would be noticed and acted on even when there were still bytes sitting in the inbuf. - Use identity comparison, not nickname comparison, to choose which half of circuit-ID-space each side gets to use. This is needed because sometimes we think of a router as a nickname, and sometimes as a hex ID, and we can't predict what the other side will do. o Bugfixes on 0.0.8.1 (Other): - Fix a whole slew of memory leaks. - Disallow NDEBUG. We don't ever want anybody to turn off debug. - If we are using select, make sure we stay within FD_SETSIZE. - When poll() is interrupted, we shouldn't believe the revents values. - Add a FAST_SMARTLIST define to optionally inline smartlist_get and smartlist_len, which are two major profiling offenders. - If do_hup fails, actually notice. - Flush the log file descriptor after we print "Tor opening log file", so we don't see those messages days later. - Hidden service operators now correctly handle version 1 style INTRODUCE1 cells (nobody generates them still, so not a critical bug). - Handle more errnos from accept() without closing the listener. Some OpenBSD machines were closing their listeners because they ran out of file descriptors. - Some people had wrapped their tor client/server in a script that would restart it whenever it died. This did not play well with our "shut down if your version is obsolete" code. Now people don't fetch a new directory if their local cached version is recent enough. - Make our autogen.sh work on ksh as well as bash. - Better torrc example lines for dirbindaddress and orbindaddress. - Improved bounds checking on parsed ints (e.g. config options and the ones we find in directories.) - Stop using separate defaults for no-config-file and empty-config-file. Now you have to explicitly turn off SocksPort, if you don't want it open. - We were starting to daemonize before we opened our logs, so if there were any problems opening logs, we would complain to stderr, which wouldn't work, and then mysteriously exit. - If a verified OR connects to us before he's uploaded his descriptor, or we verify him and hup but he still has the original TLS connection, then conn->nickname is still set like he's unverified. o Code security improvements, inspired by Ilja: - tor_snprintf wrapper over snprintf with consistent (though not C99) overflow behavior. - Replace sprintf with tor_snprintf. (I think they were all safe, but hey.) - Replace strcpy/strncpy with strlcpy in more places. - Avoid strcat; use tor_snprintf or strlcat instead. o Features (circuits and streams): - New circuit building strategy: keep a list of ports that we've used in the past 6 hours, and always try to have 2 circuits open or on the way that will handle each such port. Seed us with port 80 so web users won't complain that Tor is "slow to start up". - Make kill -USR1 dump more useful stats about circuits. - When warning about retrying or giving up, print the address, so the user knows which one it's talking about. - If you haven't used a clean circuit in an hour, throw it away, just to be on the safe side. (This means after 6 hours a totally unused Tor client will have no circuits open.) - Support "foo.nickname.exit" addresses, to let Alice request the address "foo" as viewed by exit node "nickname". Based on a patch from Geoff Goodell. - If your requested entry or exit node has advertised bandwidth 0, pick it anyway. - Be more greedy about filling up relay cells -- we try reading again once we've processed the stuff we read, in case enough has arrived to fill the last cell completely. - Refuse application socks connections to port 0. - Use only 0.0.9pre1 and later servers for resolve cells. o Features (bandwidth): - Hibernation: New config option "AccountingMax" lets you set how many bytes per month (in each direction) you want to allow your server to consume. Rather than spreading those bytes out evenly over the month, we instead hibernate for some of the month and pop up at a deterministic time, work until the bytes are consumed, then hibernate again. Config option "MonthlyAccountingStart" lets you specify which day of the month your billing cycle starts on. - Implement weekly/monthly/daily accounting: now you specify your hibernation properties by AccountingMax N bytes|KB|MB|GB|TB AccountingStart day|week|month [day] HH:MM Defaults to "month 1 0:00". - Let bandwidth and interval config options be specified as 5 bytes, kb, kilobytes, etc; and as seconds, minutes, hours, days, weeks. o Features (directories): - New "router-status" line in directory, to better bind each verified nickname to its identity key. - Clients can ask dirservers for /dir.z to get a compressed version of the directory. Only works for servers running 0.0.9, of course. - Make clients cache directories and use them to seed their router lists at startup. This means clients have a datadir again. - Respond to content-encoding headers by trying to uncompress as appropriate. - Clients and servers now fetch running-routers; cache running-routers; compress running-routers; serve compressed running-routers.z - Make moria2 advertise a dirport of 80, so people behind firewalls will be able to get a directory. - Http proxy support - Dirservers translate requests for http://%s:%d/x to /x - You can specify "HttpProxy %s[:%d]" and all dir fetches will be routed through this host. - Clients ask for /tor/x rather than /x for new enough dirservers. This way we can one day coexist peacefully with apache. - Clients specify a "Host: %s%d" http header, to be compatible with more proxies, and so running squid on an exit node can work. - Protect dirservers from overzealous descriptor uploading -- wait 10 seconds after directory gets dirty, before regenerating. o Features (packages and install): - Add NSI installer contributed by J Doe. - Apply NT service patch from Osamu Fujino. Still needs more work. - Commit VC6 and VC7 workspace/project files. - Commit a tor.spec for making RPM files, with help from jbash. - Add contrib/torctl.in contributed by Glenn Fink. - Make expand_filename handle ~ and ~username. - Use autoconf to enable largefile support where necessary. Use ftello where available, since ftell can fail at 2GB. - Ship src/win32/ in the tarball, so people can use it to build. - Make old win32 fall back to CWD if SHGetSpecialFolderLocation is broken. o Features (ui controller): - Control interface: a separate program can now talk to your client/server over a socket, and get/set config options, receive notifications of circuits and streams starting/finishing/dying, bandwidth used, etc. The next step is to get some GUIs working. Let us know if you want to help out. See doc/control-spec.txt . - Ship a contrib/tor-control.py as an example script to interact with the control port. - "tor --hash-password zzyxz" will output a salted password for use in authenticating to the control interface. - Implement the control-spec's SAVECONF command, to write your configuration to torrc. - Get cookie authentication for the controller closer to working. - When set_conf changes our server descriptor, upload a new copy. But don't upload it too often if there are frequent changes. o Features (config and command-line): - Deprecate unofficial config option abbreviations, and abbreviations not on the command line. - Configuration infrastructure support for warning on obsolete options. - Give a slightly more useful output for "tor -h". - Break DirFetchPostPeriod into: - DirFetchPeriod for fetching full directory, - StatusFetchPeriod for fetching running-routers, - DirPostPeriod for posting server descriptor, - RendPostPeriod for posting hidden service descriptors. - New log format in config: "Log minsev[-maxsev] stdout|stderr|syslog" or "Log minsev[-maxsev] file /var/foo" - DirPolicy config option, to let people reject incoming addresses from their dirserver. - "tor --list-fingerprint" will list your identity key fingerprint and then exit. - Make tor --version --version dump the cvs Id of every file. - New 'MyFamily nick1,...' config option for a server to specify other servers that shouldn't be used in the same circuit with it. Only believed if nick1 also specifies us. - New 'NodeFamily nick1,nick2,...' config option for a client to specify nodes that it doesn't want to use in the same circuit. - New 'Redirectexit pattern address:port' config option for a server to redirect exit connections, e.g. to a local squid. - Add "pass" target for RedirectExit, to make it easier to break out of a sequence of RedirectExit rules. - Make the dirservers file obsolete. - Include a dir-signing-key token in directories to tell the parsing entity which key is being used to sign. - Remove the built-in bulky default dirservers string. - New config option "Dirserver %s:%d [fingerprint]", which can be repeated as many times as needed. If no dirservers specified, default to moria1,moria2,tor26. - Make 'Routerfile' config option obsolete. - Discourage people from setting their dirfetchpostperiod more often than once per minute. o Features (other): - kill -USR2 now moves all logs to loglevel debug (kill -HUP to get back to normal.) - Accept *:706 (silc) in default exit policy. - Implement new versioning format for post 0.1. - Distinguish between TOR_TLS_CLOSE and TOR_TLS_ERROR, so we can log more informatively. - Check clock skew for verified servers, but allow unverified servers and clients to have any clock skew. - Make sure the hidden service descriptors are at a random offset from each other, to hinder linkability. - Clients now generate a TLS cert too, in preparation for having them act more like real nodes. - Add a pure-C tor-resolve implementation. - Use getrlimit and friends to ensure we can reach MaxConn (currently 1024) file descriptors. - Raise the max dns workers from 50 to 100. Changes in version 0.0.8.1 - 2004-10-13 o Bugfixes: - Fix a seg fault that can be triggered remotely for Tor clients/servers with an open dirport. - Fix a rare assert trigger, where routerinfos for entries in our cpath would expire while we're building the path. - Fix a bug in OutboundBindAddress so it (hopefully) works. - Fix a rare seg fault for people running hidden services on intermittent connections. - Fix a bug in parsing opt keywords with objects. - Fix a stale pointer assert bug when a stream detaches and reattaches. - Fix a string format vulnerability (probably not exploitable) in reporting stats locally. - Fix an assert trigger: sometimes launching circuits can fail immediately, e.g. because too many circuits have failed recently. - Fix a compile warning on 64 bit platforms. Changes in version 0.0.8 - 2004-08-25 o Bugfixes: - Made our unit tests compile again on OpenBSD 3.5, and tor itself compile again on OpenBSD on a sparc64. - We were neglecting milliseconds when logging on win32, so everything appeared to happen at the beginning of each second. - Check directory signature _before_ you decide whether you're you're running an obsolete version and should exit. - Check directory signature _before_ you parse the running-routers list to decide who's running. - Check return value of fclose while writing to disk, so we don't end up with broken files when servers run out of disk space. - Port it to SunOS 5.9 / Athena - Fix two bugs in saving onion keys to disk when rotating, so hopefully we'll get fewer people using old onion keys. - Remove our mostly unused -- and broken -- hex_encode() function. Use base16_encode() instead. (Thanks to Timo Lindfors for pointing out this bug.) - Only pick and establish intro points after we've gotten a directory. - Fix assert triggers: if the other side returns an address 0.0.0.0, don't put it into the client dns cache. - If a begin failed due to exit policy, but we believe the IP address should have been allowed, switch that router to exitpolicy reject *:* until we get our next directory. o Protocol changes: - 'Extend' relay cell payloads now include the digest of the intended next hop's identity key. Now we can verify that we're extending to the right router, and also extend to routers we hadn't heard of before. o Features: - Tor nodes can now act as relays (with an advertised ORPort) without being manually verified by the dirserver operators. - Uploaded descriptors of unverified routers are now accepted by the dirservers, and included in the directory. - Verified routers are listed by nickname in the running-routers list; unverified routers are listed as "$". - We now use hash-of-identity-key in most places rather than nickname or addr:port, for improved security/flexibility. - AllowUnverifiedNodes config option to let circuits choose no-name routers in entry,middle,exit,introduction,rendezvous positions. Allow middle and rendezvous positions by default. - When picking unverified routers, skip those with low uptime and/or low bandwidth, depending on what properties you care about. - ClientOnly option for nodes that never want to become servers. - Directory caching. - "AuthoritativeDir 1" option for the official dirservers. - Now other nodes (clients and servers) will cache the latest directory they've pulled down. - They can enable their DirPort to serve it to others. - Clients will pull down a directory from any node with an open DirPort, and check the signature/timestamp correctly. - Authoritative dirservers now fetch directories from other authdirservers, to stay better synced. - Running-routers list tells who's down also, along with noting if they're verified (listed by nickname) or unverified (listed by hash-of-key). - Allow dirservers to serve running-router list separately. This isn't used yet. - You can now fetch $DIRURL/running-routers to get just the running-routers line, not the whole descriptor list. (But clients don't use this yet.) - Clients choose nodes proportional to advertised bandwidth. - Clients avoid using nodes with low uptime as introduction points. - Handle servers with dynamic IP addresses: don't just replace options->Address with the resolved one at startup, and detect our address right before we make a routerinfo each time. - 'FascistFirewall' option to pick dirservers and ORs on specific ports; plus 'FirewallPorts' config option to tell FascistFirewall which ports are open. (Defaults to 80,443) - Try other dirservers immediately if the one you try is down. This should tolerate down dirservers better now. - ORs connect-on-demand to other ORs - If you get an extend cell to an OR you're not connected to, connect, handshake, and forward the create cell. - The authoritative dirservers stay connected to everybody, and everybody stays connected to 0.0.7 servers, but otherwise clients/servers expire unused connections after 5 minutes. - When servers get a sigint, they delay 30 seconds (refusing new connections) then exit. A second sigint causes immediate exit. - File and name management: - Look for .torrc if no CONFDIR "torrc" is found. - If no datadir is defined, then choose, make, and secure ~/.tor as datadir. - If torrc not found, exitpolicy reject *:*. - Expands ~/ in filenames to $HOME/ (but doesn't yet expand ~arma). - If no nickname is defined, derive default from hostname. - Rename secret key files, e.g. identity.key -> secret_id_key, to discourage people from mailing their identity key to tor-ops. - Refuse to build a circuit before the directory has arrived -- it won't work anyway, since you won't know the right onion keys to use. - Parse tor version numbers so we can do an is-newer-than check rather than an is-in-the-list check. - New socks command 'resolve', to let us shim gethostbyname() locally. - A 'tor_resolve' script to access the socks resolve functionality. - A new socks-extensions.txt doc file to describe our interpretation and extensions to the socks protocols. - Add a ContactInfo option, which gets published in descriptor. - Write tor version at the top of each log file - New docs in the tarball: - tor-doc.html. - Document that you should proxy your SSL traffic too. - Log a warning if the user uses an unsafe socks variant, so people are more likely to learn about privoxy or socat. - Log a warning if you're running an unverified server, to let you know you might want to get it verified. - Change the default exit policy to reject the default edonkey, kazaa, gnutella ports. - Add replace_file() to util.[ch] to handle win32's rename(). - Publish OR uptime in descriptor (and thus in directory) too. - Remember used bandwidth (both in and out), and publish 15-minute snapshots for the past day into our descriptor. - Be more aggressive about trying to make circuits when the network has changed (e.g. when you unsuspend your laptop). - Check for time skew on http headers; report date in response to "GET /". - If the entrynode config line has only one node, don't pick it as an exitnode. - Add strict{entry|exit}nodes config options. If set to 1, then we refuse to build circuits that don't include the specified entry or exit nodes. - OutboundBindAddress config option, to bind to a specific IP address for outgoing connect()s. - End truncated log entries (e.g. directories) with "[truncated]". Changes in version 0.0.7.3 - 2004-08-12 o Stop dnsworkers from triggering an assert failure when you ask them to resolve the host "". Changes in version 0.0.7.2 - 2004-07-07 o A better fix for the 0.0.0.0 problem, that will hopefully eliminate the remaining related assertion failures. Changes in version 0.0.7.1 - 2004-07-04 o When an address resolves to 0.0.0.0, treat it as a failed resolve, since internally we use 0.0.0.0 to signify "not yet resolved". Changes in version 0.0.7 - 2004-06-07 o Fixes for crashes and other obnoxious bugs: - Fix an epipe bug: sometimes when directory connections failed to connect, we would give them a chance to flush before closing them. - When we detached from a circuit because of resolvefailed, we would immediately try the same circuit twice more, and then give up on the resolve thinking we'd tried three different exit nodes. - Limit the number of intro circuits we'll attempt to build for a hidden service per 15-minute period. - Check recommended-software string *early*, before actually parsing the directory. Thus we can detect an obsolete version and exit, even if the new directory format doesn't parse. o Fixes for security bugs: - Remember which nodes are dirservers when you startup, and if a random OR enables his dirport, don't automatically assume he's a trusted dirserver. o Other bugfixes: - Directory connections were asking the wrong poll socket to start writing, and not asking themselves to start writing. - When we detached from a circuit because we sent a begin but didn't get a connected, we would use it again the first time; but after that we would correctly switch to a different one. - Stop warning when the first onion decrypt attempt fails; they will sometimes legitimately fail now that we rotate keys. - Override unaligned-access-ok check when $host_cpu is ia64 or arm. Apparently they allow it but the kernel whines. - Dirservers try to reconnect periodically too, in case connections have failed. - Fix some memory leaks in directory servers. - Allow backslash in Win32 filenames. - Made Tor build complain-free on FreeBSD, hopefully without breaking other BSD builds. We'll see. - Check directory signatures based on name of signer, not on whom we got the directory from. This will let us cache directories more easily. - Rotate dnsworkers and cpuworkers on SIGHUP, so they get new config settings too. o Features: - Doxygen markup on all functions and global variables. - Make directory functions update routerlist, not replace it. So now directory disagreements are not so critical a problem. - Remove the upper limit on number of descriptors in a dirserver's directory (not that we were anywhere close). - Allow multiple logfiles at different severity ranges. - Allow *BindAddress to specify ":port" rather than setting *Port separately. Allow multiple instances of each BindAddress config option, so you can bind to multiple interfaces if you want. - Allow multiple exit policy lines, which are processed in order. Now we don't need that huge line with all the commas in it. - Enable accept/reject policies on SOCKS connections, so you can bind to 0.0.0.0 but still control who can use your OP. - Updated the man page to reflect these features. Changes in version 0.0.6.2 - 2004-05-16 o Our integrity-checking digest was checking only the most recent cell, not the previous cells like we'd thought. Thanks to Stefan Mark for finding the flaw! Changes in version 0.0.6.1 - 2004-05-06 o Fix two bugs in our AES counter-mode implementation (this affected onion-level stream encryption, but not TLS-level). It turns out we were doing something much more akin to a 16-character polyalphabetic cipher. Oops. Thanks to Stefan Mark for finding the flaw! o Retire moria3 as a directory server, and add tor26 as a directory server. Changes in version 0.0.6 - 2004-05-02 o Features: - Hidden services and rendezvous points are implemented. Go to http://6sxoyfb3h2nvok2d.onion/ for an index of currently available hidden services. (This only works via a socks4a proxy such as Privoxy, and currently it's quite slow.) - We now rotate link (tls context) keys and onion keys. - CREATE cells now include oaep padding, so you can tell if you decrypted them correctly. - Retry stream correctly when we fail to connect because of exit-policy-reject (should try another) or can't-resolve-address. - When we hup a dirserver and we've *removed* a server from the approved-routers list, now we remove that server from the in-memory directories too. - Add bandwidthburst to server descriptor. - Directories now say which dirserver signed them. - Use a tor_assert macro that logs failed assertions too. - Since we don't support truncateds much, don't bother sending them; just close the circ. - Fetch randomness from /dev/urandom better (not via fopen/fread) - Better debugging for tls errors - Set Content-Type on the directory and hidserv descriptor. - Remove IVs from cipher code, since AES-ctr has none. o Bugfixes: - Fix an assert trigger for exit nodes that's been plaguing us since the days of 0.0.2prexx (thanks weasel!) - Fix a bug where we were closing tls connections intermittently. It turns out openssl keeps its errors around -- so if an error happens, and you don't ask about it, and then another openssl operation happens and succeeds, and you ask if there was an error, it tells you about the first error. - Fix a bug that's been lurking since 27 may 03 (!) When passing back a destroy cell, we would use the wrong circ id. - Don't crash if a conn that sent a begin has suddenly lost its circuit. - Some versions of openssl have an SSL_pending function that erroneously returns bytes when there is a non-application record pending. - Win32 fixes. Tor now compiles on win32 with no warnings/errors. o We were using an array of length zero in a few places. o Win32's gethostbyname can't resolve an IP to an IP. o Win32's close can't close a socket. o Handle windows socket errors correctly. o Portability: - check for so we build on FreeBSD again, and for NetBSD. Changes in version 0.0.5 - 2004-03-30 o Install torrc as torrc.sample -- we no longer clobber your torrc. (Woo!) o Fix mangled-state bug in directory fetching (was causing sigpipes). o Only build circuits after we've fetched the directory: clients were using only the directory servers before they'd fetched a directory. This also means longer startup time; so it goes. o Fix an assert trigger where an OP would fail to handshake, and we'd expect it to have a nickname. o Work around a tsocks bug: do a socks reject when AP connection dies early, else tsocks goes into an infinite loop. o Hold socks connection open until reply is flushed (if possible) o Make exit nodes resolve IPs to IPs immediately, rather than asking the dns farm to do it. o Fix c99 aliasing warnings in rephist.c o Don't include server descriptors that are older than 24 hours in the directory. o Give socks 'reject' replies their whole 15s to attempt to flush, rather than seeing the 60s timeout and assuming the flush had failed. o Clean automake droppings from the cvs repository o Add in a 'notice' log level for things the operator should hear but that aren't warnings Changes in version 0.0.4 - 2004-03-26 o When connecting to a dirserver or OR and the network is down, we would crash. Changes in version 0.0.3 - 2004-03-26 o Warn and fail if server chose a nickname with illegal characters o Port to Solaris and Sparc: - include missing header fcntl.h - have autoconf find -lsocket -lnsl automatically - deal with hardware word alignment - make uname() work (solaris has a different return convention) - switch from using signal() to sigaction() o Preliminary work on reputation system: - Keep statistics on success/fail of connect attempts; they're published by kill -USR1 currently. - Add a RunTesting option to try to learn link state by creating test circuits, even when SocksPort is off. - Remove unused open circuits when there are too many. Changes in version 0.0.2 - 2004-03-19 - Include strlcpy and strlcat for safer string ops - define INADDR_NONE so we compile (but still not run) on solaris Changes in version 0.0.2pre27 - 2004-03-14 o Bugfixes: - Allow internal tor networks (we were rejecting internal IPs, now we allow them if they're set explicitly). - And fix a few endian issues. Changes in version 0.0.2pre26 - 2004-03-14 o New features: - If a stream times out after 15s without a connected cell, don't try that circuit again: try a new one. - Retry streams at most 4 times. Then give up. - When a dirserver gets a descriptor from an unknown router, it logs its fingerprint (so the dirserver operator can choose to accept it even without mail from the server operator). - Inform unapproved servers when we reject their descriptors. - Make tor build on Windows again. It works as a client, who knows about as a server. - Clearer instructions in the torrc for how to set up a server. - Be more efficient about reading fd's when our global token bucket (used for rate limiting) becomes empty. o Bugfixes: - Stop asserting that computers always go forward in time. It's simply not true. - When we sent a cell (e.g. destroy) and then marked an OR connection expired, we might close it before finishing a flush if the other side isn't reading right then. - Don't allow dirservers to start if they haven't defined RecommendedVersions - We were caching transient dns failures. Oops. - Prevent servers from publishing an internal IP as their address. - Address a strcat vulnerability in circuit.c Changes in version 0.0.2pre25 - 2004-03-04 o New features: - Put the OR's IP in its router descriptor, not its fqdn. That way we'll stop being stalled by gethostbyname for nodes with flaky dns, e.g. poblano. o Bugfixes: - If the user typed in an address that didn't resolve, the server crashed. Changes in version 0.0.2pre24 - 2004-03-03 o Bugfixes: - Fix an assertion failure in dns.c, where we were trying to dequeue a pending dns resolve even if it wasn't pending - Fix a spurious socks5 warning about still trying to write after the connection is finished. - Hold certain marked_for_close connections open until they're finished flushing, rather than losing bytes by closing them too early. - Correctly report the reason for ending a stream - Remove some duplicate calls to connection_mark_for_close - Put switch_id and start_daemon earlier in the boot sequence, so it will actually try to chdir() to options.DataDirectory - Make 'make test' exit(1) if a test fails; fix some unit tests - Make tor fail when you use a config option it doesn't know about, rather than warn and continue. - Make --version work - Bugfixes on the rpm spec file and tor.sh, so it's more up to date Changes in version 0.0.2pre23 - 2004-02-29 o New features: - Print a statement when the first circ is finished, so the user knows it's working. - If a relay cell is unrecognized at the end of the circuit, send back a destroy. (So attacks to mutate cells are more clearly thwarted.) - New config option 'excludenodes' to avoid certain nodes for circuits. - When it daemonizes, it chdir's to the DataDirectory rather than "/", so you can collect coredumps there. o Bugfixes: - Fix a bug in tls flushing where sometimes data got wedged and didn't flush until more data got sent. Hopefully this bug was a big factor in the random delays we were seeing. - Make 'connected' cells include the resolved IP, so the client dns cache actually gets populated. - Disallow changing from ORPort=0 to ORPort>0 on hup. - When we time-out on a stream and detach from the circuit, send an end cell down it first. - Only warn about an unknown router (in exitnodes, entrynodes, excludenodes) after we've fetched a directory. Changes in version 0.0.2pre22 - 2004-02-26 o New features: - Servers publish less revealing uname information in descriptors. - More memory tracking and assertions, to crash more usefully when errors happen. - If the default torrc isn't there, just use some default defaults. Plus provide an internal dirservers file if they don't have one. - When the user tries to use Tor as an http proxy, give them an http 501 failure explaining that we're a socks proxy. - Dump a new router.desc on hup, to help confused people who change their exit policies and then wonder why router.desc doesn't reflect it. - Clean up the generic tor.sh init script that we ship with. o Bugfixes: - If the exit stream is pending on the resolve, and a destroy arrives, then the stream wasn't getting removed from the pending list. I think this was the one causing recent server crashes. - Use a more robust poll on OSX 10.3, since their poll is flaky. - When it couldn't resolve any dirservers, it was useless from then on. Now it reloads the RouterFile (or default dirservers) if it has no dirservers. - Move the 'tor' binary back to /usr/local/bin/ -- it turns out many users don't even *have* a /usr/local/sbin/. Changes in version 0.0.2pre21 - 2004-02-18 o New features: - There's a ChangeLog file that actually reflects the changelog. - There's a 'torify' wrapper script, with an accompanying tor-tsocks.conf, that simplifies the process of using tsocks for tor. It even has a man page. - The tor binary gets installed to sbin rather than bin now. - Retry streams where the connected cell hasn't arrived in 15 seconds - Clean up exit policy handling -- get the default out of the torrc, so we can update it without forcing each server operator to fix his/her torrc. - Allow imaps and pop3s in default exit policy o Bugfixes: - Prevent picking middleman nodes as the last node in the circuit Changes in version 0.0.2pre20 - 2004-01-30 o New features: - We now have a deb package, and it's in debian unstable. Go to it, apt-getters. :) - I've split the TotalBandwidth option into BandwidthRate (how many bytes per second you want to allow, long-term) and BandwidthBurst (how many bytes you will allow at once before the cap kicks in). This better token bucket approach lets you, say, set BandwidthRate to 10KB/s and BandwidthBurst to 10MB, allowing good performance while not exceeding your monthly bandwidth quota. - Push out a tls record's worth of data once you've got it, rather than waiting until you've read everything waiting to be read. This may improve performance by pipelining better. We'll see. - Add an AP_CONN_STATE_CONNECTING state, to allow streams to detach from failed circuits (if they haven't been connected yet) and attach to new ones. - Expire old streams that haven't managed to connect. Some day we'll have them reattach to new circuits instead. o Bugfixes: - Fix several memory leaks that were causing servers to become bloated after a while. - Fix a few very rare assert triggers. A few more remain. - Setuid to User _before_ complaining about running as root. Changes in version 0.0.2pre19 - 2004-01-07 o Bugfixes: - Fix deadlock condition in dns farm. We were telling a child to die by closing the parent's file descriptor to him. But newer children were inheriting the open file descriptor from the parent, and since they weren't closing it, the socket never closed, so the child never read eof, so he never knew to exit. Similarly, dns workers were holding open other sockets, leading to all sorts of chaos. - New cleaner daemon() code for forking and backgrounding. - If you log to a file, it now prints an entry at the top of the logfile so you know it's working. - The onionskin challenge length was 30 bytes longer than necessary. - Started to patch up the spec so it's not quite so out of date. Changes in version 0.0.2pre18 - 2004-01-02 o Bugfixes: - Fix endian issues with the 'integrity' field in the relay header. - Fix a potential bug where connections in state AP_CONN_STATE_CIRCUIT_WAIT might unexpectedly ask to write. Changes in version 0.0.2pre17 - 2003-12-30 o Bugfixes: - Made --debuglogfile (or any second log file, actually) work. - Resolved an edge case in get_unique_circ_id_by_conn where a smart adversary could force us into an infinite loop. o Features: - Each onionskin handshake now includes a hash of the computed key, to prove the server's identity and help perfect forward secrecy. - Changed cell size from 256 to 512 bytes (working toward compatibility with MorphMix). - Changed cell length to 2 bytes, and moved it to the relay header. - Implemented end-to-end integrity checking for the payloads of relay cells. - Separated streamid from 'recognized' (otherwise circuits will get messed up when we try to have streams exit from the middle). We use the integrity-checking to confirm that a cell is addressed to this hop. - Randomize the initial circid and streamid values, so an adversary who breaks into a node can't learn how many circuits or streams have been made so far. Changes in version 0.0.2pre16 - 2003-12-14 o Bugfixes: - Fixed a bug that made HUP trigger an assert - Fixed a bug where a circuit that immediately failed wasn't being counted as a failed circuit in counting retries. o Features: - Now we close the circuit when we get a truncated cell: otherwise we're open to an anonymity attack where a bad node in the path truncates the circuit and then we open streams at him. - Add port ranges to exit policies - Add a conservative default exit policy - Warn if you're running tor as root - on HUP, retry OR connections and close/rebind listeners - options.EntryNodes: try these nodes first when picking the first node - options.ExitNodes: if your best choices happen to include any of your preferred exit nodes, you choose among just those preferred exit nodes. - options.ExcludedNodes: nodes that are never picked in path building Changes in version 0.0.2pre15 - 2003-12-03 o Robustness and bugfixes: - Sometimes clients would cache incorrect DNS resolves, which would really screw things up. - An OP that goes offline would slowly leak all its sockets and stop working. - A wide variety of bugfixes in exit node selection, exit policy handling, and processing pending streams when a new circuit is established. - Pick nodes for a path only from those the directory says are up - Choose randomly from all running dirservers, not always the first one - Increase allowed http header size for directory fetch. - Stop writing to stderr (if we're daemonized it will be closed). - Enable -g always, so cores will be more useful to me. - Switch "-lcrypto -lssl" to "-lssl -lcrypto" for broken distributions. o Documentation: - Wrote a man page. It lists commonly used options. o Configuration: - Change default loglevel to warn. - Make PidFile default to null rather than littering in your CWD. - OnionRouter config option is now obsolete. Instead it just checks ORPort>0. - Moved to a single unified torrc file for both clients and servers. Changes in version 0.0.2pre14 - 2003-11-29 o Robustness and bugfixes: - Force the admin to make the DataDirectory himself - to get ownership/permissions right - so clients no longer make a DataDirectory and then never use it - fix bug where a client who was offline for 45 minutes would never pull down a directory again - fix (or at least hide really well) the dns assert bug that was causing server crashes - warnings and improved robustness wrt clockskew for certs - use the native daemon(3) to daemonize, when available - exit if bind() fails - exit if neither socksport nor orport is defined - include our own tor_timegm (Win32 doesn't have its own) - bugfix for win32 with lots of connections - fix minor bias in PRNG - make dirserver more robust to corrupt cached directory o Documentation: - Wrote the design document (woo) o Circuit building and exit policies: - Circuits no longer try to use nodes that the directory has told them are down. - Exit policies now support bitmasks (18.0.0.0/255.0.0.0) and bitcounts (18.0.0.0/8). - Make AP connections standby for a circuit if no suitable circuit exists, rather than failing - Circuits choose exit node based on addr/port, exit policies, and which AP connections are standing by - Bump min pathlen from 2 to 3 - Relay end cells have a payload to describe why the stream ended. - If the stream failed because of exit policy, try again with a new circuit. - Clients have a dns cache to remember resolved addresses. - Notice more quickly when we have no working circuits o Configuration: - APPort is now called SocksPort - SocksBindAddress, ORBindAddress, DirBindAddress let you configure where to bind - RecommendedVersions is now a config variable rather than hardcoded (for dirservers) - Reloads config on HUP - Usage info on -h or --help - If you set User and Group config vars, it'll setu/gid to them. Changes in version 0.0.2pre13 - 2003-10-19 o General stability: - SSL_write no longer fails when it returns WANTWRITE and the number of bytes in the buf has changed by the next SSL_write call. - Fix segfault fetching directory when network is down - Fix a variety of minor memory leaks - Dirservers reload the fingerprints file on HUP, so I don't have to take down the network when I approve a new router - Default server config file has explicit Address line to specify fqdn o Buffers: - Buffers grow and shrink as needed (Cut process size from 20M to 2M) - Make listener connections not ever alloc bufs o Autoconf improvements: - don't clobber an external CFLAGS in ./configure - Make install now works - create var/lib/tor on make install - autocreate a tor.sh initscript to help distribs - autocreate the torrc and sample-server-torrc with correct paths o Log files and Daemonizing now work: - If --DebugLogFile is specified, log to it at -l debug - If --LogFile is specified, use it instead of commandline - If --RunAsDaemon is set, tor forks and backgrounds on startup tor-0.2.4.20/Makefile.am0000644000175000017500000000441412255745673011541 00000000000000# Copyright (c) 2001-2004, Roger Dingledine # Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson # Copyright (c) 2007-2011, The Tor Project, Inc. # See LICENSE for licensing information # "foreign" means we don't follow GNU package layout standards # 1.9 means we require automake vesion 1.9 AUTOMAKE_OPTIONS = foreign 1.9 subdir-objects ACLOCAL_AMFLAGS = -I m4 noinst_LIBRARIES= EXTRA_DIST= noinst_HEADERS= bin_PROGRAMS= CLEANFILES= TESTS= noinst_PROGRAMS= DISTCLEANFILES= bin_SCRIPTS= AM_CPPFLAGS= include src/include.am include doc/include.am include contrib/include.am EXTRA_DIST+= \ ChangeLog \ INSTALL \ LICENSE \ Makefile.nmake \ README \ ReleaseNotes #install-data-local: # $(INSTALL) -m 755 -d $(LOCALSTATEDIR)/lib/tor # Allows to override rpmbuild with rpmbuild-md5 from fedora-packager so that # building for EL5 won't fail on https://bugzilla.redhat.com/show_bug.cgi?id=490613 RPMBUILD ?= rpmbuild # Use automake's dist-gzip target to build the tarball dist-rpm: dist-gzip TIMESTAMP=$$(date +"%Y-%m-%d_%H.%M.%S"); \ RPM_BUILD_DIR=$$(mktemp -d "/tmp/tor-rpm-build-$$TIMESTAMP-XXXX"); \ mkdir -p "$$RPM_BUILD_DIR"/{BUILD,RPMS,SOURCES/"tor-$(VERSION)",SPECS,SRPMS}; \ cp -fa "$(distdir).tar.gz" "$$RPM_BUILD_DIR"/SOURCES/; \ LIBS=-lrt $(RPMBUILD) -ba --define "_topdir $$RPM_BUILD_DIR" tor.spec; \ cp -fa "$$RPM_BUILD_DIR"/SRPMS/* .; \ cp -fa "$$RPM_BUILD_DIR"/RPMS/* .; \ rm -rf "$$RPM_BUILD_DIR"; \ echo "RPM build finished"; \ #end of dist-rpm dist: check doxygen: doxygen && cd doc/doxygen/latex && make test: all ./src/test/test # Avoid strlcpy.c, strlcat.c, aes.c, OpenBSD_malloc_Linux.c, sha256.c, # eventdns.[hc], tinytest*.[ch] check-spaces: ./contrib/checkSpace.pl -C \ src/common/*.[ch] \ src/or/*.[ch] \ src/test/*.[ch] \ src/tools/*.[ch] \ src/tools/tor-fw-helper/*.[ch] check-docs: ./contrib/checkOptionDocs.pl check-logs: ./contrib/checkLogs.pl \ src/*/*.[ch] | sort -n version: @echo "Tor @VERSION@" @if test -d "$(top_srcdir)/.git" && test -x "`which git 2>&1;true`"; then \ echo -n "git: " ;\ (cd "$(top_srcdir)" && git rev-parse --short=16 HEAD); \ fi tor-0.2.4.20/contrib/0000755000175000017500000000000012255753765011223 500000000000000tor-0.2.4.20/contrib/include.am0000644000175000017500000000057212255745673013110 00000000000000include contrib/suse/include.am EXTRA_DIST+= \ contrib/cross.sh \ contrib/exitlist \ contrib/linux-tor-prio.sh \ contrib/package_nsis-mingw.sh \ contrib/rc.subr \ contrib/tor-ctrl.sh \ contrib/tor-exit-notice.html \ contrib/tor-mingw.nsi.in \ contrib/tor.ico \ contrib/tor.nsi.in \ contrib/tor.sh \ contrib/torctl bin_SCRIPTS+= contrib/torify tor-0.2.4.20/contrib/linux-tor-prio.sh0000644000175000017500000001462512072315241014373 00000000000000#!/bin/bash # Written by Marco Bonetti & Mike Perry # Based on instructions from Dan Singletary's ADSL BW Management HOWTO: # http://www.faqs.org/docs/Linux-HOWTO/ADSL-Bandwidth-Management-HOWTO.html # This script is Public Domain. ############################### README ################################# # This script provides prioritization of Tor traffic below other # traffic on a Linux server. It has two modes of operation: UID based # and IP based. # UID BASED PRIORITIZATION # # The UID based method requires that Tor be launched from # a specific user ID. The "User" Tor config setting is # insufficient, as it sets the UID after the socket is created. # Here is a C wrapper you can use to execute Tor and drop privs before # it creates any sockets. # # Compile with: # gcc -DUID=`id -u tor` -DGID=`id -g tor` tor_wrap.c -o tor_wrap # # #include # int main(int argc, char **argv) { # if(initgroups("tor", GID) == -1) { perror("initgroups"); return 1; } # if(setresgid(GID, GID, GID) == -1) { perror("setresgid"); return 1; } # if(setresuid(UID, UID, UID) == -1) { perror("setresuid"); return 1; } # execl("/bin/tor", "/bin/tor", "-f", "/etc/tor/torrc", NULL); # perror("execl"); return 1; # } # IP BASED PRIORITIZATION # # The IP setting requires that a separate IP address be dedicated to Tor. # Your Torrc should be set to bind to this IP for "OutboundBindAddress", # "ListenAddress", and "Address". # GENERAL USAGE # # You should also tune the individual connection rate parameters below # to your individual connection. In particular, you should leave *some* # minimum amount of bandwidth for Tor, so that Tor users are not # completely choked out when you use your server's bandwidth. 30% is # probably a reasonable choice. More is better of course. # # To start the shaping, run it as: # ./linux-tor-prio.sh # # To get status information (useful to verify packets are getting marked # and prioritized), run: # ./linux-tor-prio.sh status # # And to stop prioritization: # ./linux-tor-prio.sh stop # ######################################################################## # BEGIN USER TUNABLE PARAMETERS DEV=eth0 # NOTE! You must START Tor under this UID. Using the Tor User # config setting is NOT sufficient. See above. TOR_UID=$(id -u tor) # If the UID mechanism doesn't work for you, you can set this parameter # instead. If set, it will take precedence over the UID setting. Note that # you need multiple IPs with one specifically devoted to Tor for this to # work. #TOR_IP="42.42.42.42" # Average ping to most places on the net, milliseconds RTT_LATENCY=40 # RATE_UP must be less than your connection's upload capacity in # kbits/sec. If it is larger, then the bottleneck will be at your # router's queue, which you do not control. This will cause congestion # and a revert to normal TCP fairness no matter what the queing # priority is. RATE_UP=5000 # RATE_UP_TOR is the minimum speed your Tor connections will have in # kbits/sec. They will have at least this much bandwidth for upload. # In general, you probably shouldn't set this too low, or else Tor # users who use your node will be completely choked out whenever your # machine does any other network activity. That is not very fun. RATE_UP_TOR=1500 # RATE_UP_TOR_CEIL is the maximum rate allowed for all Tor trafic in # kbits/sec. RATE_UP_TOR_CEIL=5000 CHAIN=OUTPUT #CHAIN=PREROUTING #CHAIN=POSTROUTING MTU=1500 AVG_PKT=900 # should be more like 600 for non-exit nodes # END USER TUNABLE PARAMETERS # The queue size should be no larger than your bandwidth-delay # product. This is RT latency*bandwidth/MTU/2 BDP=$(expr $RTT_LATENCY \* $RATE_UP / $AVG_PKT) # Further research indicates that the BDP calculations should use # RTT/sqrt(n) where n is the expected number of active connections.. BDP=$(expr $BDP / 4) if [ "$1" = "status" ] then echo "[qdisc]" tc -s qdisc show dev $DEV tc -s qdisc show dev imq0 echo "[class]" tc -s class show dev $DEV tc -s class show dev imq0 echo "[filter]" tc -s filter show dev $DEV tc -s filter show dev imq0 echo "[iptables]" iptables -t mangle -L TORSHAPER-OUT -v -x 2> /dev/null exit fi # Reset everything to a known state (cleared) tc qdisc del dev $DEV root 2> /dev/null > /dev/null tc qdisc del dev imq0 root 2> /dev/null > /dev/null iptables -t mangle -D POSTROUTING -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null iptables -t mangle -D PREROUTING -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null iptables -t mangle -D OUTPUT -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null iptables -t mangle -F TORSHAPER-OUT 2> /dev/null > /dev/null iptables -t mangle -X TORSHAPER-OUT 2> /dev/null > /dev/null ip link set imq0 down 2> /dev/null > /dev/null rmmod imq 2> /dev/null > /dev/null if [ "$1" = "stop" ] then echo "Shaping removed on $DEV." exit fi # Outbound Shaping (limits total bandwidth to RATE_UP) ip link set dev $DEV qlen $BDP # Add HTB root qdisc, default is high prio tc qdisc add dev $DEV root handle 1: htb default 20 # Add main rate limit class tc class add dev $DEV parent 1: classid 1:1 htb rate ${RATE_UP}kbit # Create the two classes, giving Tor at least RATE_UP_TOR kbit and capping # total upstream at RATE_UP so the queue is under our control. tc class add dev $DEV parent 1:1 classid 1:20 htb rate $(expr $RATE_UP - $RATE_UP_TOR)kbit ceil ${RATE_UP}kbit prio 0 tc class add dev $DEV parent 1:1 classid 1:21 htb rate $[$RATE_UP_TOR]kbit ceil ${RATE_UP_TOR_CEIL}kbit prio 10 # Start up pfifo tc qdisc add dev $DEV parent 1:20 handle 20: pfifo limit $BDP tc qdisc add dev $DEV parent 1:21 handle 21: pfifo limit $BDP # filter traffic into classes by fwmark tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20 tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:21 # add TORSHAPER-OUT chain to the mangle table in iptables iptables -t mangle -N TORSHAPER-OUT iptables -t mangle -I $CHAIN -o $DEV -j TORSHAPER-OUT # Set firewall marks # Low priority to Tor if [ ""$TOR_IP == "" ] then echo "Using UID-based QoS. UID $TOR_UID marked as low priority." iptables -t mangle -A TORSHAPER-OUT -m owner --uid-owner $TOR_UID -j MARK --set-mark 21 else echo "Using IP-based QoS. $TOR_IP marked as low priority." iptables -t mangle -A TORSHAPER-OUT -s $TOR_IP -j MARK --set-mark 21 fi # High prio for everything else iptables -t mangle -A TORSHAPER-OUT -m mark --mark 0 -j MARK --set-mark 20 echo "Outbound shaping added to $DEV. Rate for Tor upload at least: ${RATE_UP_TOR}Kbyte/sec." tor-0.2.4.20/contrib/torctl.in0000644000175000017500000001160712072315241012763 00000000000000#!/bin/sh # # TOR control script designed to allow an easy command line interface # to controlling The Onion Router # # The exit codes returned are: # 0 - operation completed successfully. For "status", tor running. # 1 - For "status", tor not running. # 2 - Command not supported # 3 - Could not be started or reloaded # 4 - Could not be stopped # 5 - # 6 - # 7 - # 8 - # # When multiple arguments are given, only the error from the _last_ # one is reported. # # # |||||||||||||||||||| START CONFIGURATION SECTION |||||||||||||||||||| # -------------------- -------------------- # Name of the executable EXEC=tor # # the path to your binary, including options if necessary TORBIN="@BINDIR@/$EXEC" # # the path to the configuration file TORCONF="@CONFDIR@/torrc" # # the path to your PID file PIDFILE="@LOCALSTATEDIR@/run/tor/tor.pid" # # The path to the log file LOGFILE="@LOCALSTATEDIR@/log/tor/tor.log" # # The path to the datadirectory TORDATA="@LOCALSTATEDIR@/lib/tor" # TORARGS="--pidfile $PIDFILE --log \"notice file $LOGFILE\" --runasdaemon 1" TORARGS="$TORARGS --datadirectory $TORDATA" # If user name is set in the environment, then use it; # otherwise run as the invoking user (or whatever user the config # file says)... unless the invoking user is root. The idea here is to # let an unprivileged user run tor for her own use using this script, # while still providing for it to be used as a system daemon. if [ "x`id -u`" = "x0" ]; then TORUSER=@TORUSER@ fi if [ "x$TORUSER" != "x" ]; then TORARGS="$TORARGS --user $TORUSER" fi # We no longer wrap the Tor daemon startup in an su when running as # root, because it's too painful to make the use of su portable. # Just let the daemon set the UID and GID. START="$TORBIN -f $TORCONF $TORARGS" # # -------------------- -------------------- # |||||||||||||||||||| END CONFIGURATION SECTION |||||||||||||||||||| ERROR=0 ARGV="$@" if [ "x$ARGV" = "x" ] ; then ARGS="help" fi checkIfRunning ( ) { # check for pidfile PID=unknown if [ -f $PIDFILE ] ; then PID=`/bin/cat $PIDFILE` if [ "x$PID" != "x" ] ; then if kill -0 $PID 2>/dev/null ; then STATUS="$EXEC (pid $PID) running" RUNNING=1 else STATUS="PID file ($PIDFILE) present, but $EXEC ($PID) not running" RUNNING=0 fi else STATUS="$EXEC (pid $PID?) not running" RUNNING=0 fi else STATUS="$EXEC apparently not running (no pid file)" RUNNING=0 fi return } for ARG in $@ $ARGS do checkIfRunning case $ARG in start) if [ $RUNNING -eq 1 ]; then echo "$0 $ARG: $EXEC (pid $PID) already running" continue fi if eval "$START" ; then echo "$0 $ARG: $EXEC started" # Make sure it stayed up! /bin/sleep 1 checkIfRunning if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $EXEC (pid $PID) quit unexpectedly" fi else echo "$0 $ARG: $EXEC could not be started" ERROR=3 fi ;; stop) if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $STATUS" continue fi if kill -15 $PID ; then echo "$0 $ARG: $EXEC stopped" else /bin/sleep 1 if kill -9 $PID ; then echo "$0 $ARG: $EXEC stopped" else echo "$0 $ARG: $EXEC could not be stopped" ERROR=4 fi fi # Make sure it really died! /bin/sleep 1 checkIfRunning if [ $RUNNING -eq 1 ]; then echo "$0 $ARG: $EXEC (pid $PID) unexpectedly still running" ERROR=4 fi ;; restart) $0 stop start ;; reload) if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $STATUS" continue fi if kill -1 $PID; then /bin/sleep 1 echo "$EXEC (PID $PID) reloaded" else echo "Can't reload $EXEC" ERROR=3 fi ;; status) echo $STATUS if [ $RUNNING -eq 1 ]; then ERROR=0 else ERROR=1 fi ;; log) cat $LOGFILE ;; help) echo "usage: $0 (start|stop|restart|status|help)" /bin/cat <= (2,2) def maskIP(ip,mask): return "".join([chr(ord(a) & ord(b)) for a,b in zip(ip,mask)]) def maskFromLong(lng): return struct.pack("!L", lng) def maskByBits(n): return maskFromLong(0xffffffffl ^ ((1L<<(32-n))-1)) class Pattern: """ >>> import socket >>> ip1 = socket.inet_aton("192.169.64.11") >>> ip2 = socket.inet_aton("192.168.64.11") >>> ip3 = socket.inet_aton("18.244.0.188") >>> print Pattern.parse("18.244.0.188") 18.244.0.188/255.255.255.255:1-65535 >>> print Pattern.parse("18.244.0.188/16:*") 18.244.0.0/255.255.0.0:1-65535 >>> print Pattern.parse("18.244.0.188/2.2.2.2:80") 2.0.0.0/2.2.2.2:80-80 >>> print Pattern.parse("192.168.0.1/255.255.00.0:22-25") 192.168.0.0/255.255.0.0:22-25 >>> p1 = Pattern.parse("192.168.0.1/255.255.00.0:22-25") >>> import socket >>> p1.appliesTo(ip1, 22) False >>> p1.appliesTo(ip2, 22) True >>> p1.appliesTo(ip2, 25) True >>> p1.appliesTo(ip2, 26) False """ def __init__(self, ip, mask, portMin, portMax): self.ip = maskIP(ip,mask) self.mask = mask self.portMin = portMin self.portMax = portMax def __str__(self): return "%s/%s:%s-%s"%(socket.inet_ntoa(self.ip), socket.inet_ntoa(self.mask), self.portMin, self.portMax) def parse(s): if ":" in s: addrspec, portspec = s.split(":",1) else: addrspec, portspec = s, "*" if addrspec == '*': ip,mask = "\x00\x00\x00\x00","\x00\x00\x00\x00" elif '/' not in addrspec: ip = socket.inet_aton(addrspec) mask = "\xff\xff\xff\xff" else: ip,mask = addrspec.split("/",1) ip = socket.inet_aton(ip) if "." in mask: mask = socket.inet_aton(mask) else: mask = maskByBits(int(mask)) if portspec == '*': portMin = 1 portMax = 65535 elif '-' not in portspec: portMin = portMax = int(portspec) else: portMin, portMax = map(int,portspec.split("-",1)) return Pattern(ip,mask,portMin,portMax) parse = staticmethod(parse) def appliesTo(self, ip, port): return ((maskIP(ip,self.mask) == self.ip) and (self.portMin <= port <= self.portMax)) class Policy: """ >>> import socket >>> ip1 = socket.inet_aton("192.169.64.11") >>> ip2 = socket.inet_aton("192.168.64.11") >>> ip3 = socket.inet_aton("18.244.0.188") >>> pol = Policy.parseLines(["reject *:80","accept 18.244.0.188:*"]) >>> print str(pol).strip() reject 0.0.0.0/0.0.0.0:80-80 accept 18.244.0.188/255.255.255.255:1-65535 >>> pol.accepts(ip1,80) False >>> pol.accepts(ip3,80) False >>> pol.accepts(ip3,81) True """ def __init__(self, lst): self.lst = lst def parseLines(lines): r = [] for item in lines: a,p=item.split(" ",1) if a == 'accept': a = True elif a == 'reject': a = False else: raise ValueError("Unrecognized action %r",a) p = Pattern.parse(p) r.append((p,a)) return Policy(r) parseLines = staticmethod(parseLines) def __str__(self): r = [] for pat, accept in self.lst: rule = accept and "accept" or "reject" r.append("%s %s\n"%(rule,pat)) return "".join(r) def accepts(self, ip, port): for pattern,accept in self.lst: if pattern.appliesTo(ip,port): return accept return True class Server: def __init__(self, name, ip, policy, published, fingerprint): self.name = name self.ip = ip self.policy = policy self.published = published self.fingerprint = fingerprint def uniq_sort(lst): d = {} for item in lst: d[item] = 1 lst = d.keys() lst.sort() return lst def run(): global VERBOSE global INVERSE global ADDRESSES_OF_INTEREST if len(sys.argv) > 1: try: opts, pargs = getopt.getopt(sys.argv[1:], "vx") except getopt.GetoptError, e: print """ usage: cat ~/.tor/cached-routers* | %s [-v] [-x] [host:port [host:port [...]]] -v verbose output -x invert results """ % sys.argv[0] sys.exit(0) for o, a in opts: if o == "-v": VERBOSE = True if o == "-x": INVERSE = True if len(pargs): ADDRESSES_OF_INTEREST = "\n".join(pargs) servers = [] policy = [] name = ip = None published = 0 fp = "" for line in sys.stdin.xreadlines(): if line.startswith('router '): if name: servers.append(Server(name, ip, Policy.parseLines(policy), published, fp)) _, name, ip, rest = line.split(" ", 3) policy = [] published = 0 fp = "" elif line.startswith('fingerprint') or \ line.startswith('opt fingerprint'): elts = line.strip().split() if elts[0] == 'opt': del elts[0] assert elts[0] == 'fingerprint' del elts[0] fp = "".join(elts) elif line.startswith('accept ') or line.startswith('reject '): policy.append(line.strip()) elif line.startswith('published '): date = time.strptime(line[len('published '):].strip(), "%Y-%m-%d %H:%M:%S") published = time.mktime(date) if name: servers.append(Server(name, ip, Policy.parseLines(policy), published, fp)) targets = [] for line in ADDRESSES_OF_INTEREST.split("\n"): line = line.strip() if not line: continue p = Pattern.parse(line) targets.append((p.ip, p.portMin)) # remove all but the latest server of each IP/Nickname pair. latest = {} for s in servers: if (not latest.has_key((s.fingerprint)) or s.published > latest[(s.fingerprint)]): latest[s.fingerprint] = s servers = latest.values() accepters, rejecters = {}, {} for s in servers: for ip,port in targets: if s.policy.accepts(ip,port): accepters[s.ip] = s break else: rejecters[s.ip] = s # If any server at IP foo accepts, the IP does not reject. for k in accepters.keys(): if rejecters.has_key(k): del rejecters[k] if INVERSE: printlist = rejecters.values() else: printlist = accepters.values() ents = [] if VERBOSE: ents = uniq_sort([ "%s\t%s"%(s.ip,s.name) for s in printlist ]) else: ents = uniq_sort([ s.ip for s in printlist ]) for e in ents: print e def _test(): import doctest, exitparse return doctest.testmod(exitparse) #_test() run() tor-0.2.4.20/contrib/tor.logrotate.in0000644000175000017500000000037312072315241014255 00000000000000@LOCALSTATEDIR@/log/tor/*log { daily rotate 5 compress delaycompress missingok notifempty # you may need to change the username/groupname below create 0640 _tor _tor sharedscripts postrotate /etc/init.d/tor reload > /dev/null endscript } tor-0.2.4.20/contrib/tor.sh.in0000644000175000017500000000551612120436355012677 00000000000000#!/bin/sh # # tor The Onion Router # # Startup/shutdown script for tor. This is a wrapper around torctl; # torctl does the actual work in a relatively system-independent, or at least # distribution-independent, way, and this script deals with fitting the # whole thing into the conventions of the particular system at hand. # This particular script is written for Red Hat/Fedora Linux, and may # also work on Mandrake, but not SuSE. # # These next couple of lines "declare" tor for the "chkconfig" program, # originally from SGI, used on Red Hat/Fedora and probably elsewhere. # # chkconfig: 2345 90 10 # description: Onion Router - A low-latency anonymous proxy # PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/tor NAME=tor DESC="tor daemon" TORPIDDIR=/var/run/tor TORPID=$TORPIDDIR/tor.pid WAITFORDAEMON=60 ARGS="" # Library functions if [ -f /etc/rc.d/init.d/functions ]; then . /etc/rc.d/init.d/functions elif [ -f /etc/init.d/functions ]; then . /etc/init.d/functions fi TORCTL=@BINDIR@/torctl # torctl will use these environment variables TORUSER=@TORUSER@ export TORUSER if [ -x /bin/su ] ; then SUPROG=/bin/su elif [ -x /sbin/su ] ; then SUPROG=/sbin/su elif [ -x /usr/bin/su ] ; then SUPROG=/usr/bin/su elif [ -x /usr/sbin/su ] ; then SUPROG=/usr/sbin/su else SUPROG=/bin/su fi # Raise ulimit based on number of file descriptors available (thanks, Debian) if [ -r /proc/sys/fs/file-max ]; then system_max=`cat /proc/sys/fs/file-max` if [ "$system_max" -gt "80000" ] ; then MAX_FILEDESCRIPTORS=32768 elif [ "$system_max" -gt "40000" ] ; then MAX_FILEDESCRIPTORS=16384 elif [ "$system_max" -gt "10000" ] ; then MAX_FILEDESCRIPTORS=8192 else MAX_FILEDESCRIPTORS=1024 cat << EOF Warning: Your system has very few filedescriptors available in total. Maybe you should try raising that by adding 'fs.file-max=100000' to your /etc/sysctl.conf file. Feel free to pick any number that you deem appropriate. Then run 'sysctl -p'. See /proc/sys/fs/file-max for the current value, and file-nr in the same directory for how many of those are used at the moment. EOF fi else MAX_FILEDESCRIPTORS=8192 fi NICE="" case "$1" in start) if [ -n "$MAX_FILEDESCRIPTORS" ]; then echo -n "Raising maximum number of filedescriptors (ulimit -n) to $MAX_FILEDESCRIPTORS" if ulimit -n "$MAX_FILEDESCRIPTORS" ; then echo "." else echo ": FAILED." fi fi action $"Starting tor:" $TORCTL start RETVAL=$? ;; stop) action $"Stopping tor:" $TORCTL stop RETVAL=$? ;; restart) action $"Restarting tor:" $TORCTL restart RETVAL=$? ;; reload) action $"Reloading tor:" $TORCTL reload RETVAL=$? ;; status) $TORCTL status RETVAL=$? ;; *) echo "Usage: $0 (start|stop|restart|reload|status)" RETVAL=1 esac exit $RETVAL tor-0.2.4.20/contrib/tor-mingw.nsi.in0000644000175000017500000002210012255745673014200 00000000000000;tor.nsi - A basic win32 installer for Tor ; Originally written by J Doe. ; Modified by Steve Topletz, Andrew Lewman ; See the Tor LICENSE for licensing information ;----------------------------------------- ; !include "MUI.nsh" !include "LogicLib.nsh" !include "FileFunc.nsh" !insertmacro GetParameters !define VERSION "0.2.4.20" !define INSTALLER "tor-${VERSION}-win32.exe" !define WEBSITE "https://www.torproject.org/" !define LICENSE "LICENSE" !define BIN "..\bin" ;BIN is where it expects to find tor.exe, tor-resolve.exe SetCompressor /SOLID LZMA ;Tighter compression RequestExecutionLevel user ;Updated for Vista compatibility OutFile ${INSTALLER} InstallDir $PROGRAMFILES\Tor SetOverWrite ifnewer Name "Tor" Caption "Tor ${VERSION} Setup" BrandingText "The Onion Router" CRCCheck on XPStyle on VIProductVersion "${VERSION}" VIAddVersionKey "ProductName" "The Onion Router: Tor" VIAddVersionKey "Comments" "${WEBSITE}" VIAddVersionKey "LegalTrademarks" "Three line BSD" VIAddVersionKey "LegalCopyright" "2004-2008, Roger Dingledine, Nick Mathewson. 2009 The Tor Project, Inc. " VIAddVersionKey "FileDescription" "Tor is an implementation of Onion Routing. You can read more at ${WEBSITE}" VIAddVersionKey "FileVersion" "${VERSION}" !define MUI_WELCOMEPAGE_TITLE "Welcome to the Tor Setup Wizard" !define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Tor ${VERSION}.\r\n\r\nIf you have previously installed Tor and it is currently running, please exit Tor first before continuing this installation.\r\n\r\n$_CLICK" !define MUI_ABORTWARNING !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\win-install.ico" !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\win-uninstall.ico" !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\win.bmp" !define MUI_FINISHPAGE_RUN "$INSTDIR\tor.exe" !define MUI_FINISHPAGE_LINK "Visit the Tor website for the latest updates." !define MUI_FINISHPAGE_LINK_LOCATION ${WEBSITE} !insertmacro MUI_PAGE_WELCOME ; There's no point in having a clickthrough license: Our license adds ; certain rights, but doesn't remove them. ; !insertmacro MUI_PAGE_LICENSE "${LICENSE}" !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH !insertmacro MUI_LANGUAGE "English" Var CONFIGDIR Var CONFIGFILE Function .onInit Call ParseCmdLine FunctionEnd ;Sections ;-------- Section "Tor" Tor ;Files that have to be installed for tor to run and that the user ;cannot choose not to install SectionIn RO SetOutPath $INSTDIR Call ExtractBinaries Call ExtractIcon WriteINIStr "$INSTDIR\Tor Website.url" "InternetShortcut" "URL" ${WEBSITE} StrCpy $CONFIGFILE "torrc" StrCpy $CONFIGDIR $APPDATA\Tor ; ;If $APPDATA isn't valid here (Early win95 releases with no updated ; ; shfolder.dll) then we put it in the program directory instead. ; StrCmp $APPDATA "" "" +2 ; StrCpy $CONFIGDIR $INSTDIR SetOutPath $CONFIGDIR ;If there's already a torrc config file, ask if they want to ;overwrite it with the new one. ${If} ${FileExists} "$CONFIGDIR\torrc" MessageBox MB_ICONQUESTION|MB_YESNO "You already have a Tor config file.$\r$\nDo you want to overwrite it with the default sample config file?" IDYES Yes IDNO No Yes: Delete $CONFIGDIR\torrc Goto Next No: StrCpy $CONFIGFILE "torrc.sample" Next: ${EndIf} File /oname=$CONFIGFILE "..\src\config\torrc.sample" ; the geoip file needs to be included and stuffed into the right directory ; otherwise tor is unhappy SetOutPath $APPDATA\Tor Call ExtractGEOIP SectionEnd Section "Documents" Docs Call ExtractDocuments SectionEnd SubSection /e "Shortcuts" Shortcuts Section "Start Menu" StartMenu SetOutPath $INSTDIR ${If} ${FileExists} "$SMPROGRAMS\Tor\*.*" RMDir /r "$SMPROGRAMS\Tor" ${EndIf} Call CreateTorLinks ${If} ${FileExists} "$INSTDIR\Documents\*.*" Call CreateDocLinks ${EndIf} SectionEnd Section "Desktop" Desktop SetOutPath $INSTDIR CreateShortCut "$DESKTOP\Tor.lnk" "$INSTDIR\tor.exe" "" "$INSTDIR\tor.ico" SectionEnd Section /o "Run at startup" Startup SetOutPath $INSTDIR CreateShortCut "$SMSTARTUP\Tor.lnk" "$INSTDIR\tor.exe" "" "$INSTDIR\tor.ico" "" SW_SHOWMINIMIZED SectionEnd SubSectionEnd Section "Uninstall" Call un.InstallPackage SectionEnd Section -End WriteUninstaller "$INSTDIR\Uninstall.exe" ;The registry entries simply add the Tor uninstaller to the Windows ;uninstall list. WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tor" "DisplayName" "Tor (remove only)" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tor" "UninstallString" '"$INSTDIR\Uninstall.exe"' SectionEnd !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${Tor} "The core executable and config files needed for Tor to run." !insertmacro MUI_DESCRIPTION_TEXT ${Docs} "Documentation about Tor." !insertmacro MUI_DESCRIPTION_TEXT ${ShortCuts} "Shortcuts to easily start Tor" !insertmacro MUI_DESCRIPTION_TEXT ${StartMenu} "Shortcuts to access Tor and its documentation from the Start Menu" !insertmacro MUI_DESCRIPTION_TEXT ${Desktop} "A shortcut to start Tor from the desktop" !insertmacro MUI_DESCRIPTION_TEXT ${Startup} "Launches Tor automatically at startup in a minimized window" !insertmacro MUI_FUNCTION_DESCRIPTION_END ;####################Functions######################### Function ExtractBinaries File "${BIN}\tor.exe" File "${BIN}\tor-resolve.exe" FunctionEnd Function ExtractGEOIP File "${BIN}\geoip" FunctionEnd Function ExtractIcon File "${BIN}\tor.ico" FunctionEnd Function ExtractSpecs File "..\doc\HACKING" File "..\doc\spec\address-spec.txt" File "..\doc\spec\bridges-spec.txt" File "..\doc\spec\control-spec.txt" File "..\doc\spec\dir-spec.txt" File "..\doc\spec\path-spec.txt" File "..\doc\spec\rend-spec.txt" File "..\doc\spec\socks-extensions.txt" File "..\doc\spec\tor-spec.txt" File "..\doc\spec\version-spec.txt" FunctionEnd Function ExtractHTML File "..\doc\tor.html" File "..\doc\torify.html" File "..\doc\tor-resolve.html" File "..\doc\tor-gencert.html" FunctionEnd Function ExtractReleaseDocs File "..\README" File "..\ChangeLog" File "..\LICENSE" FunctionEnd Function ExtractDocuments SetOutPath "$INSTDIR\Documents" Call ExtractSpecs Call ExtractHTML Call ExtractReleaseDocs FunctionEnd Function un.InstallFiles Delete "$DESKTOP\Tor.lnk" Delete "$INSTDIR\tor.exe" Delete "$INSTDIR\tor-resolve.exe" Delete "$INSTDIR\Tor Website.url" Delete "$INSTDIR\torrc" Delete "$INSTDIR\torrc.sample" Delete "$INSTDIR\tor.ico" Delete "$SMSTARTUP\Tor.lnk" Delete "$INSTDIR\Uninstall.exe" Delete "$INSTDIR\geoip" FunctionEnd Function un.InstallDirectories ${If} $CONFIGDIR == $INSTDIR RMDir /r $CONFIGDIR ${EndIf} RMDir /r "$INSTDIR\Documents" RMDir $INSTDIR RMDir /r "$SMPROGRAMS\Tor" RMDir /r "$APPDATA\Tor" FunctionEnd Function un.WriteRegistry DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Tor" FunctionEnd Function un.InstallPackage Call un.InstallFiles Call un.InstallDirectories Call un.WriteRegistry FunctionEnd Function CreateTorLinks CreateDirectory "$SMPROGRAMS\Tor" CreateShortCut "$SMPROGRAMS\Tor\Tor.lnk" "$INSTDIR\tor.exe" "" "$INSTDIR\tor.ico" CreateShortCut "$SMPROGRAMS\Tor\Torrc.lnk" "Notepad.exe" "$CONFIGDIR\torrc" CreateShortCut "$SMPROGRAMS\Tor\Tor Website.lnk" "$INSTDIR\Tor Website.url" CreateShortCut "$SMPROGRAMS\Tor\Uninstall.lnk" "$INSTDIR\Uninstall.exe" FunctionEnd Function CreateDocLinks CreateDirectory "$SMPROGRAMS\Tor\Documents" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Documentation.lnk" "$INSTDIR\Documents" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Specification.lnk" "$INSTDIR\Documents\tor-spec.txt" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Address Specification.lnk" "$INSTDIR\Documents\address-spec.txt" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Bridges Specification.lnk" "$INSTDIR\Documents\bridges-spec.txt" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Control Specification.lnk" "$INSTDIR\Documents\control-spec.txt" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Directory Specification.lnk" "$INSTDIR\Documents\dir-spec.txt" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Path Specification.lnk" "$INSTDIR\Documents\path-spec.txt" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Rend Specification.lnk" "$INSTDIR\Documents\rend-spec.txt" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Version Specification.lnk" "$INSTDIR\Documents\version-spec.txt" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor SOCKS Extensions.lnk" "$INSTDIR\Documents\socks-extensions.txt" FunctionEnd Function ParseCmdLine ${GetParameters} $1 ${If} $1 == "-x" ;Extract All Files StrCpy $INSTDIR $EXEDIR Call ExtractBinaries Call ExtractDocuments Quit ${ElseIf} $1 == "-b" ;Extract Binaries Only StrCpy $INSTDIR $EXEDIR Call ExtractBinaries Quit ${ElseIf} $1 != "" MessageBox MB_OK|MB_TOPMOST `${Installer} [-x|-b]$\r$\n$\r$\n -x Extract all files$\r$\n -b Extract binary files only` Quit ${EndIf} FunctionEnd tor-0.2.4.20/contrib/torctl0000644000175000017500000001161612255746026012372 00000000000000#!/bin/sh # # TOR control script designed to allow an easy command line interface # to controlling The Onion Router # # The exit codes returned are: # 0 - operation completed successfully. For "status", tor running. # 1 - For "status", tor not running. # 2 - Command not supported # 3 - Could not be started or reloaded # 4 - Could not be stopped # 5 - # 6 - # 7 - # 8 - # # When multiple arguments are given, only the error from the _last_ # one is reported. # # # |||||||||||||||||||| START CONFIGURATION SECTION |||||||||||||||||||| # -------------------- -------------------- # Name of the executable EXEC=tor # # the path to your binary, including options if necessary TORBIN="/usr/local/bin/$EXEC" # # the path to the configuration file TORCONF="/usr/local/etc/tor/torrc" # # the path to your PID file PIDFILE="/usr/local/var/run/tor/tor.pid" # # The path to the log file LOGFILE="/usr/local/var/log/tor/tor.log" # # The path to the datadirectory TORDATA="/usr/local/var/lib/tor" # TORARGS="--pidfile $PIDFILE --log \"notice file $LOGFILE\" --runasdaemon 1" TORARGS="$TORARGS --datadirectory $TORDATA" # If user name is set in the environment, then use it; # otherwise run as the invoking user (or whatever user the config # file says)... unless the invoking user is root. The idea here is to # let an unprivileged user run tor for her own use using this script, # while still providing for it to be used as a system daemon. if [ "x`id -u`" = "x0" ]; then TORUSER=_tor fi if [ "x$TORUSER" != "x" ]; then TORARGS="$TORARGS --user $TORUSER" fi # We no longer wrap the Tor daemon startup in an su when running as # root, because it's too painful to make the use of su portable. # Just let the daemon set the UID and GID. START="$TORBIN -f $TORCONF $TORARGS" # # -------------------- -------------------- # |||||||||||||||||||| END CONFIGURATION SECTION |||||||||||||||||||| ERROR=0 ARGV="$@" if [ "x$ARGV" = "x" ] ; then ARGS="help" fi checkIfRunning ( ) { # check for pidfile PID=unknown if [ -f $PIDFILE ] ; then PID=`/bin/cat $PIDFILE` if [ "x$PID" != "x" ] ; then if kill -0 $PID 2>/dev/null ; then STATUS="$EXEC (pid $PID) running" RUNNING=1 else STATUS="PID file ($PIDFILE) present, but $EXEC ($PID) not running" RUNNING=0 fi else STATUS="$EXEC (pid $PID?) not running" RUNNING=0 fi else STATUS="$EXEC apparently not running (no pid file)" RUNNING=0 fi return } for ARG in $@ $ARGS do checkIfRunning case $ARG in start) if [ $RUNNING -eq 1 ]; then echo "$0 $ARG: $EXEC (pid $PID) already running" continue fi if eval "$START" ; then echo "$0 $ARG: $EXEC started" # Make sure it stayed up! /bin/sleep 1 checkIfRunning if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $EXEC (pid $PID) quit unexpectedly" fi else echo "$0 $ARG: $EXEC could not be started" ERROR=3 fi ;; stop) if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $STATUS" continue fi if kill -15 $PID ; then echo "$0 $ARG: $EXEC stopped" else /bin/sleep 1 if kill -9 $PID ; then echo "$0 $ARG: $EXEC stopped" else echo "$0 $ARG: $EXEC could not be stopped" ERROR=4 fi fi # Make sure it really died! /bin/sleep 1 checkIfRunning if [ $RUNNING -eq 1 ]; then echo "$0 $ARG: $EXEC (pid $PID) unexpectedly still running" ERROR=4 fi ;; restart) $0 stop start ;; reload) if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $STATUS" continue fi if kill -1 $PID; then /bin/sleep 1 echo "$EXEC (PID $PID) reloaded" else echo "Can't reload $EXEC" ERROR=3 fi ;; status) echo $STATUS if [ $RUNNING -eq 1 ]; then ERROR=0 else ERROR=1 fi ;; log) cat $LOGFILE ;; help) echo "usage: $0 (start|stop|restart|status|help)" /bin/cat < April 16th 2006 # Stripped of all the tsocks cruft by ugh on February 22nd 2012 # May be distributed under the same terms as Tor itself compat() { echo "torify is now just a wrapper around torsocks(1) for backwards compatibility." } usage() { compat echo "Usage: $0 [-hv] [...]" } case $# in 0) usage >&2 exit 1 esac case $# in 1) case $1 in -h|--help) usage exit 0 esac esac case $1 in -v|--verbose) compat >&2 shift esac # taken from Debian's Developer's Reference, 6.4 pathfind() { OLDIFS="$IFS" IFS=: for p in $PATH; do if [ -x "$p/$*" ]; then IFS="$OLDIFS" return 0 fi done IFS="$OLDIFS" return 1 } if pathfind torsocks; then exec torsocks "$@" echo "$0: Failed to exec torsocks $@" >&2 exit 1 else echo "$0: torsocks not found in your PATH. Perhaps it isn't installed? (tsocks is no longer supported, for security reasons.)" >&2 fi tor-0.2.4.20/contrib/suse/0000755000175000017500000000000012255753765012202 500000000000000tor-0.2.4.20/contrib/suse/include.am0000644000175000017500000000004112153762274014047 00000000000000EXTRA_DIST+= contrib/suse/tor.sh tor-0.2.4.20/contrib/suse/tor.sh.in0000644000175000017500000000556312120436355013660 00000000000000#!/bin/sh # # Copyright (c) 2006-2007 Andrew Lewman # # tor The Onion Router # # Startup/shutdown script for tor. This is a wrapper around torctl; # torctl does the actual work in a relatively system-independent, or at least # distribution-independent, way, and this script deals with fitting the # whole thing into the conventions of the particular system at hand. # # These next couple of lines "declare" tor for the "chkconfig" program, # originally from SGI, used on Red Hat/Fedora and probably elsewhere. # # chkconfig: 2345 90 10 # description: Onion Router - A low-latency anonymous proxy # ### BEGIN INIT INFO # Provides: tor # Required-Start: $remote_fs $network # Required-Stop: $remote_fs $network # Default-Start: 3 5 # Default-Stop: 0 1 2 6 # Short-Description: Start the tor daemon # Description: Start the tor daemon: the anon-proxy server ### END INIT INFO . /etc/rc.status # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status # rc_status -v ditto but be verbose in local rc status # rc_status -v -r ditto and clear the local rc status # rc_failed set local and overall rc status to failed # rc_reset clear local rc status (overall remains) # rc_exit exit appropriate to overall rc status # First reset status of this service rc_reset # Increase open file descriptors a reasonable amount ulimit -n 8192 TORCTL=@BINDIR@/torctl # torctl will use these environment variables TORUSER=@TORUSER@ export TORUSER TORGROUP=@TORGROUP@ export TORGROUP TOR_DAEMON_PID_DIR="@LOCALSTATEDIR@/run/tor" if [ -x /bin/su ] ; then SUPROG=/bin/su elif [ -x /sbin/su ] ; then SUPROG=/sbin/su elif [ -x /usr/bin/su ] ; then SUPROG=/usr/bin/su elif [ -x /usr/sbin/su ] ; then SUPROG=/usr/sbin/su else SUPROG=/bin/su fi case "$1" in start) echo "Starting tor daemon" if [ ! -d $TOR_DAEMON_PID_DIR ] ; then mkdir -p $TOR_DAEMON_PID_DIR chown $TORUSER:$TORGROUP $TOR_DAEMON_PID_DIR fi ## Start daemon with startproc(8). If this fails ## the echo return value is set appropriate. startproc -f $TORCTL start # Remember status and be verbose rc_status -v ;; stop) echo "Stopping tor daemon" startproc -f $TORCTL stop # Remember status and be verbose rc_status -v ;; restart) echo "Restarting tor daemon" startproc -f $TORCTL restart # Remember status and be verbose rc_status -v ;; reload) echo "Reloading tor daemon" startproc -f $TORCTL reload # Remember status and be verbose rc_status -v ;; status) startproc -f $TORCTL status # Remember status and be verbose rc_status -v ;; *) echo "Usage: $0 (start|stop|restart|reload|status)" RETVAL=1 esac rc_exit tor-0.2.4.20/contrib/suse/tor.sh0000644000175000017500000000555512255746025013263 00000000000000#!/bin/sh # # Copyright (c) 2006-2007 Andrew Lewman # # tor The Onion Router # # Startup/shutdown script for tor. This is a wrapper around torctl; # torctl does the actual work in a relatively system-independent, or at least # distribution-independent, way, and this script deals with fitting the # whole thing into the conventions of the particular system at hand. # # These next couple of lines "declare" tor for the "chkconfig" program, # originally from SGI, used on Red Hat/Fedora and probably elsewhere. # # chkconfig: 2345 90 10 # description: Onion Router - A low-latency anonymous proxy # ### BEGIN INIT INFO # Provides: tor # Required-Start: $remote_fs $network # Required-Stop: $remote_fs $network # Default-Start: 3 5 # Default-Stop: 0 1 2 6 # Short-Description: Start the tor daemon # Description: Start the tor daemon: the anon-proxy server ### END INIT INFO . /etc/rc.status # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status # rc_status -v ditto but be verbose in local rc status # rc_status -v -r ditto and clear the local rc status # rc_failed set local and overall rc status to failed # rc_reset clear local rc status (overall remains) # rc_exit exit appropriate to overall rc status # First reset status of this service rc_reset # Increase open file descriptors a reasonable amount ulimit -n 8192 TORCTL=/usr/local/bin/torctl # torctl will use these environment variables TORUSER=_tor export TORUSER TORGROUP=_tor export TORGROUP TOR_DAEMON_PID_DIR="/usr/local/var/run/tor" if [ -x /bin/su ] ; then SUPROG=/bin/su elif [ -x /sbin/su ] ; then SUPROG=/sbin/su elif [ -x /usr/bin/su ] ; then SUPROG=/usr/bin/su elif [ -x /usr/sbin/su ] ; then SUPROG=/usr/sbin/su else SUPROG=/bin/su fi case "$1" in start) echo "Starting tor daemon" if [ ! -d $TOR_DAEMON_PID_DIR ] ; then mkdir -p $TOR_DAEMON_PID_DIR chown $TORUSER:$TORGROUP $TOR_DAEMON_PID_DIR fi ## Start daemon with startproc(8). If this fails ## the echo return value is set appropriate. startproc -f $TORCTL start # Remember status and be verbose rc_status -v ;; stop) echo "Stopping tor daemon" startproc -f $TORCTL stop # Remember status and be verbose rc_status -v ;; restart) echo "Restarting tor daemon" startproc -f $TORCTL restart # Remember status and be verbose rc_status -v ;; reload) echo "Reloading tor daemon" startproc -f $TORCTL reload # Remember status and be verbose rc_status -v ;; status) startproc -f $TORCTL status # Remember status and be verbose rc_status -v ;; *) echo "Usage: $0 (start|stop|restart|reload|status)" RETVAL=1 esac rc_exit tor-0.2.4.20/contrib/package_nsis-mingw.sh0000644000175000017500000000704412120436355015232 00000000000000#!/bin/sh # # =============================================================================== # package_nsis-ming.sh is distributed under this license: # Copyright (c) 2006-2007 Andrew Lewman # Copyright (c) 2008 The Tor Project, Inc. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the names of the copyright owners nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # =============================================================================== # Script to package a Tor installer on win32. This script assumes that # you have already built Tor, that you are running msys/mingw, and that # you know what you are doing. # Start in the tor source directory after you've compiled tor.exe # This means start as ./contrib/package_nsis-mingw.sh rm -rf win_tmp mkdir win_tmp mkdir win_tmp/bin mkdir win_tmp/contrib mkdir win_tmp/doc mkdir win_tmp/doc/spec mkdir win_tmp/doc/design-paper mkdir win_tmp/doc/contrib mkdir win_tmp/src mkdir win_tmp/src/config mkdir win_tmp/tmp cp src/or/tor.exe win_tmp/bin/ cp src/tools/tor-resolve.exe win_tmp/bin/ cp contrib/tor.ico win_tmp/bin/ cp src/config/geoip win_tmp/bin/ strip win_tmp/bin/*.exe # There is no man2html in mingw. # Maybe we should add this into make dist instead. # One has to do this manually and cp it do the tor-source/doc dir #man2html doc/tor.1.in > win_tmp/tmp/tor-reference.html #man2html doc/tor-resolve.1 > win_tmp/tmp/tor-resolve.html clean_newlines() { perl -pe 's/^\n$/\r\n/mg; s/([^\r])\n$/\1\r\n/mg;' $1 >$2 } clean_localstatedir() { perl -pe 's/^\n$/\r\n/mg; s/([^\r])\n$/\1\r\n/mg; s{\@LOCALSTATEDIR\@/(lib|log)/tor/}{C:\\Documents and Settings\\Application Data\\Tor\\}' $1 >$2 } for fn in address-spec.txt bridges-spec.txt control-spec.txt dir-spec.txt path-spec.txt rend-spec.txt socks-extensions.txt tor-spec.txt version-spec.txt; do clean_newlines doc/spec/$fn win_tmp/doc/spec/$fn done for fn in HACKING tor-gencert.html tor.html torify.html tor-resolve.html; do clean_newlines doc/$fn win_tmp/doc/$fn done for fn in README ChangeLog LICENSE; do clean_newlines $fn win_tmp/$fn done clean_localstatedir src/config/torrc.sample.in win_tmp/src/config/torrc.sample cp contrib/tor-mingw.nsi.in win_tmp/contrib/ cd win_tmp makensis.exe contrib/tor-mingw.nsi.in tor-0.2.4.20/contrib/tor.nsi.in0000644000175000017500000002021712166112776013061 00000000000000;tor.nsi - A basic win32 installer for Tor ; Originally written by J Doe. ; See LICENSE for licensing information ;----------------------------------------- ; NOTE: This file might be obsolete. Look at tor-mingw.nsi.in instead. ;----------------------------------------- ; How to make an installer: ; Step 0. If you are a Tor maintainer, make sure that tor.nsi and ; src/win32/orconfig.h all have the correct version number. ; Step 1. Download and install OpenSSL. Make sure that the OpenSSL ; version listed below matches the one you downloaded. ; Step 2. Download and install NSIS (http://nsis.sourceforge.net) ; Step 3. Make a directory under the main tor directory called "bin". ; Step 4. Copy ssleay32.dll and libeay32.dll from OpenSSL into "bin". ; Step 5. Run man2html on tor.1.in; call the result tor-reference.html ; Run man2html on tor-resolve.1; call the result tor-resolve.html ; Step 6. Copy torrc.sample.in to torrc.sample. ; Step 7. Build tor.exe and tor_resolve.exe; save the result into bin. ; Step 8. cd into contrib and run "makensis tor.nsi". ; ; Problems: ; - Copying torrc.sample.in to torrc.sample and tor.1.in (implicitly) ; to tor.1 is a Bad Thing, and leaves us with @autoconf@ vars in the final ; result. ; - Building Tor requires too much windows C clue. ; - We should have actual makefiles for VC that do the right thing. ; - I need to learn more NSIS juju to solve these: ; - There should be a batteries-included installer that comes with ; privoxy too. (Check privoxy license on this; be sure to include ; all privoxy documents.) ; - The filename should probably have a revision number. !include "MUI.nsh" !define VERSION "0.1.2.3-alpha-dev" !define INSTALLER "tor-${VERSION}-win32.exe" !define WEBSITE "https://www.torproject.org/" !define LICENSE "..\LICENSE" ;BIN is where it expects to find tor.exe, tor_resolve.exe, libeay32.dll and ; ssleay32.dll !define BIN "..\bin" SetCompressor lzma ;SetCompressor zlib OutFile ${INSTALLER} InstallDir $PROGRAMFILES\Tor SetOverWrite ifnewer Name "Tor" Caption "Tor ${VERSION} Setup" BrandingText "The Onion Router" CRCCheck on ;Use upx on the installer header to shrink the size. !packhdr header.dat "upx --best header.dat" !define MUI_WELCOMEPAGE_TITLE "Welcome to the Tor ${VERSION} Setup Wizard" !define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Tor ${VERSION}.\r\n\r\nIf you have previously installed Tor and it is currently running, please exit Tor first before continuing this installation.\r\n\r\n$_CLICK" !define MUI_ABORTWARNING !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\win-install.ico" !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\win-uninstall.ico" !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\win.bmp" !define MUI_HEADERIMAGE !define MUI_FINISHPAGE_RUN "$INSTDIR\tor.exe" !define MUI_FINISHPAGE_LINK "Visit the Tor website for the latest updates." !define MUI_FINISHPAGE_LINK_LOCATION ${WEBSITE} !insertmacro MUI_PAGE_WELCOME ; There's no point in having a clickthrough license: Our license adds ; certain rights, but doesn't remove them. ; !insertmacro MUI_PAGE_LICENSE "${LICENSE}" !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH !insertmacro MUI_LANGUAGE "English" Var configdir Var configfile ;Sections ;-------- Section "Tor" Tor ;Files that have to be installed for tor to run and that the user ;cannot choose not to install SectionIn RO SetOutPath $INSTDIR File "${BIN}\tor.exe" File "${BIN}\tor_resolve.exe" WriteIniStr "$INSTDIR\Tor Website.url" "InternetShortcut" "URL" ${WEBSITE} StrCpy $configfile "torrc" StrCpy $configdir $APPDATA\Tor ; ;If $APPDATA isn't valid here (Early win95 releases with no updated ; ; shfolder.dll) then we put it in the program directory instead. ; StrCmp $APPDATA "" "" +2 ; StrCpy $configdir $INSTDIR SetOutPath $configdir ;If there's already a torrc config file, ask if they want to ;overwrite it with the new one. IfFileExists "$configdir\torrc" "" endiftorrc MessageBox MB_ICONQUESTION|MB_YESNO "You already have a Tor config file.$\r$\nDo you want to overwrite it with the default sample config file?" IDNO yesreplace Delete $configdir\torrc Goto endiftorrc yesreplace: StrCpy $configfile "torrc.sample" endiftorrc: File /oname=$configfile "..\src\config\torrc.sample" SectionEnd Section "OpenSSL 0.9.8a" OpenSSL SetOutPath $INSTDIR File "${BIN}\libeay32.dll" File "${BIN}\ssleay32.dll" SectionEnd Section "Documents" Docs SetOutPath "$INSTDIR\Documents" ;File "..\doc\FAQ" File "..\doc\HACKING" File "..\doc\spec\control-spec.txt" File "..\doc\spec\dir-spec.txt" File "..\doc\spec\rend-spec.txt" File "..\doc\spec\socks-extensions.txt" File "..\doc\spec\tor-spec.txt" File "..\doc\spec\version-spec.txt" ; ; WEBSITE-FILES-HERE ; File "..\doc\tor-resolve.html" File "..\doc\tor-reference.html" ; File "..\doc\design-paper\tor-design.pdf" ; File "..\README" File "..\AUTHORS" File "..\ChangeLog" File "..\LICENSE" SectionEnd SubSection /e "Shortcuts" Shortcuts Section "Start Menu" StartMenu SetOutPath $INSTDIR IfFileExists "$SMPROGRAMS\Tor\*.*" "" +2 RMDir /r "$SMPROGRAMS\Tor" CreateDirectory "$SMPROGRAMS\Tor" CreateShortCut "$SMPROGRAMS\Tor\Tor.lnk" "$INSTDIR\tor.exe" CreateShortCut "$SMPROGRAMS\Tor\Torrc.lnk" "Notepad.exe" "$configdir\torrc" CreateShortCut "$SMPROGRAMS\Tor\Tor Website.lnk" "$INSTDIR\Tor Website.url" CreateShortCut "$SMPROGRAMS\Tor\Uninstall.lnk" "$INSTDIR\Uninstall.exe" IfFileExists "$INSTDIR\Documents\*.*" "" endifdocs CreateDirectory "$SMPROGRAMS\Tor\Documents" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Manual.lnk" "$INSTDIR\Documents\tor-reference.html" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Documentation.lnk" "$INSTDIR\Documents" CreateShortCut "$SMPROGRAMS\Tor\Documents\Tor Specification.lnk" "$INSTDIR\Documents\tor-spec.txt" endifdocs: SectionEnd Section "Desktop" Desktop SetOutPath $INSTDIR CreateShortCut "$DESKTOP\Tor.lnk" "$INSTDIR\tor.exe" SectionEnd Section /o "Run at startup" Startup SetOutPath $INSTDIR CreateShortCut "$SMSTARTUP\Tor.lnk" "$INSTDIR\tor.exe" "" "" 0 SW_SHOWMINIMIZED SectionEnd SubSectionEnd Section "Uninstall" Delete "$DESKTOP\Tor.lnk" Delete "$INSTDIR\libeay32.dll" Delete "$INSTDIR\ssleay32.dll" Delete "$INSTDIR\tor.exe" Delete "$INSTDIR\tor_resolve.exe" Delete "$INSTDIR\Tor Website.url" Delete "$INSTDIR\torrc" Delete "$INSTDIR\torrc.sample" StrCmp $configdir $INSTDIR +2 "" RMDir /r $configdir Delete "$INSTDIR\Uninstall.exe" RMDir /r "$INSTDIR\Documents" RMDir $INSTDIR RMDir /r "$SMPROGRAMS\Tor" Delete "$SMSTARTUP\Tor.lnk" DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Tor" SectionEnd Section -End WriteUninstaller "$INSTDIR\Uninstall.exe" ;The registry entries simply add the Tor uninstaller to the Windows ;uninstall list. WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tor" "DisplayName" "Tor (remove only)" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tor" "UninstallString" '"$INSTDIR\Uninstall.exe"' SectionEnd !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${Tor} "The core executable and config files needed for Tor to run." !insertmacro MUI_DESCRIPTION_TEXT ${OpenSSL} "OpenSSL libraries required by Tor." !insertmacro MUI_DESCRIPTION_TEXT ${Docs} "Documentation about Tor." !insertmacro MUI_DESCRIPTION_TEXT ${ShortCuts} "Shortcuts to easily start Tor" !insertmacro MUI_DESCRIPTION_TEXT ${StartMenu} "Shortcuts to access Tor and its documentation from the Start Menu" !insertmacro MUI_DESCRIPTION_TEXT ${Desktop} "A shortcut to start Tor from the desktop" !insertmacro MUI_DESCRIPTION_TEXT ${Startup} "Launches Tor automatically at startup in a minimized window" !insertmacro MUI_FUNCTION_DESCRIPTION_END tor-0.2.4.20/contrib/tor.sh0000644000175000017500000000551712255746025012302 00000000000000#!/bin/sh # # tor The Onion Router # # Startup/shutdown script for tor. This is a wrapper around torctl; # torctl does the actual work in a relatively system-independent, or at least # distribution-independent, way, and this script deals with fitting the # whole thing into the conventions of the particular system at hand. # This particular script is written for Red Hat/Fedora Linux, and may # also work on Mandrake, but not SuSE. # # These next couple of lines "declare" tor for the "chkconfig" program, # originally from SGI, used on Red Hat/Fedora and probably elsewhere. # # chkconfig: 2345 90 10 # description: Onion Router - A low-latency anonymous proxy # PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/tor NAME=tor DESC="tor daemon" TORPIDDIR=/var/run/tor TORPID=$TORPIDDIR/tor.pid WAITFORDAEMON=60 ARGS="" # Library functions if [ -f /etc/rc.d/init.d/functions ]; then . /etc/rc.d/init.d/functions elif [ -f /etc/init.d/functions ]; then . /etc/init.d/functions fi TORCTL=/usr/local/bin/torctl # torctl will use these environment variables TORUSER=_tor export TORUSER if [ -x /bin/su ] ; then SUPROG=/bin/su elif [ -x /sbin/su ] ; then SUPROG=/sbin/su elif [ -x /usr/bin/su ] ; then SUPROG=/usr/bin/su elif [ -x /usr/sbin/su ] ; then SUPROG=/usr/sbin/su else SUPROG=/bin/su fi # Raise ulimit based on number of file descriptors available (thanks, Debian) if [ -r /proc/sys/fs/file-max ]; then system_max=`cat /proc/sys/fs/file-max` if [ "$system_max" -gt "80000" ] ; then MAX_FILEDESCRIPTORS=32768 elif [ "$system_max" -gt "40000" ] ; then MAX_FILEDESCRIPTORS=16384 elif [ "$system_max" -gt "10000" ] ; then MAX_FILEDESCRIPTORS=8192 else MAX_FILEDESCRIPTORS=1024 cat << EOF Warning: Your system has very few filedescriptors available in total. Maybe you should try raising that by adding 'fs.file-max=100000' to your /etc/sysctl.conf file. Feel free to pick any number that you deem appropriate. Then run 'sysctl -p'. See /proc/sys/fs/file-max for the current value, and file-nr in the same directory for how many of those are used at the moment. EOF fi else MAX_FILEDESCRIPTORS=8192 fi NICE="" case "$1" in start) if [ -n "$MAX_FILEDESCRIPTORS" ]; then echo -n "Raising maximum number of filedescriptors (ulimit -n) to $MAX_FILEDESCRIPTORS" if ulimit -n "$MAX_FILEDESCRIPTORS" ; then echo "." else echo ": FAILED." fi fi action $"Starting tor:" $TORCTL start RETVAL=$? ;; stop) action $"Stopping tor:" $TORCTL stop RETVAL=$? ;; restart) action $"Restarting tor:" $TORCTL restart RETVAL=$? ;; reload) action $"Reloading tor:" $TORCTL reload RETVAL=$? ;; status) $TORCTL status RETVAL=$? ;; *) echo "Usage: $0 (start|stop|restart|reload|status)" RETVAL=1 esac exit $RETVAL tor-0.2.4.20/contrib/tor.ico0000644000175000017500000024144612072315241012432 00000000000000 (F00 %n  . h>(        "##$%%&''''''''''''&%$$#"!    "$%'(*+-./122445556666666655543210/-,+*'&$#   "$&)+-/24689<=>@ABCDFFFFGHIIHHGGFFEEDCBA?=<;97531.,*(%#   "%),0269<=@BEGIJLNPPQSTUVVWWWXXXXXXWWWVUTSRQPNMKJHFDA?=:752.+($!  #(,048<@CFILNPSUVY[[]^_`abbcdeeeeeeeeeeeddcba`__]\ZYXVTRPMJHEB?;73/,'"  &,27<AEILPSVXZ\^`bdfghijklmnnopppqqqqqqqqpoonnmlkjihgfeca`^[YWUROKGC?;60*%  #+3:AGKPTXZ]`bdfhjkmopprsstuvwwwxxyyyzzzzyyxxwwvvutssrqoonljigeca_\YVSOKF@92*"  $-8AIOUZ]adfiklopqstvwwxyzz{|||}}}~~~~~~~}}}|||{zyyxwwutsrpomkjgec`]XTNG@6,#   +7BLU[aehknorstvwxyz{||}}~~~  '''---222555888::9;;9<<:==;==<<<;786,.+01/00/**)%%$ ~}}}||{zxxwvusrpnljgc`YSKA5)  $0=HS\cilpqtuwxyz{|}}~!')%HIFfga~~zđϟ٪ᴴ꺺񾿻ľ𥩢饧ׅ{{xeecEED***$#$~}|{{zyxwutspnkga[RG;." %2>JU^fknrtwwyz{|}~--,[_UpxcĆyף軿ƼȼɿȽĹƽ曙Ԁ[[[(((~}||{zywvusqmid]SI<0#  $0<HS[bhkpqtvwyz{| ??;suoӴǿŹȻʻ̽̾ʺɼ蕕qqp673 ~|{zywvtrpmjg`ZPF;-"   +7ALSZ`dhknprtvz~()%jlcӶƺ̺˼ȿ슏p`dL!!}zvuspnlifc_YRI?4( %-7@HOTZ_afgknxGJDaj\m}d甡ǷȶλɼpxonmR:;, vmkifd_\XSLF>5+"  $,3:AGMQVZ]n&/DRuySspMLL175 6172"C  &&%#yzt^xmTcGzħǯʷyVlYv{ǮʯǿƾObFK]Bokew_yynmhbbx^m}qWh\l}ltcqR~j]cIekFiiGTS=94!8.7,4.Q  %%$'qsmkzWlK|nɺηĠȧĥȸɽzwxvnng|gɯȯŵȾ9L76K2dw]j}flmxzomxplYnRduc_o`dyfzz̼ǻewVGW7ZiJmmvaOX7_`A_]CG@(D8!?19/5) ]  01/)uyruryhjZUlFϾ{zhxfL\J&A+PjSġåȸĹźĴ}EWG4I8/C0^q^~|tmMcF8M3J\Gvzns~|ql~^\kN\jO\mRarVwFP2SU8VT8HC(F=%A5A6!<.8( e "  HHF+{~sgzWuat]mrŲǰ͹¯{y4K8!5&';/N_Qǵ˿ó`ph@SJMbTvxivyoThKSgMooYk\j|gocw{nhatXwj|lU]AKO3[]@OP4??#A>"UP6ME.<26+(l$  JJF)ڇ|fxXi}Volu;¥[sXHeL:&iylʻ˵ʴǴİë~wsnrwdp_h}T|f~q|c>P6\oVRfPUkXCXCyq~pdz̾\qSDU3RZ;\`ELT9eoOZcBEL,SX9mpSbcHA?&>7";/+o "  @A9#~wi\nJ`uNuanlyd{k|̺θ}PiRvnvn}v[u\ŲɼŹrfRjIKcA[oNn{]ny\DU7YkNK]C8G5AP>RaJZlTAT;bqTujXgMAL0U[?hnP_iJZdEIQ5T[?fmQNU:JL2?=&?8$;.6&. m    swހvauQavOr`n]WiFbsRO_BET;ȴ{yʾȲǼǸȼedkhz±ǻxvTmP`wXtgykReFTkJZqSkzg7C3@K8amVix_\lTtkblUAG/IN5KT8\iJerQcmL_iOT^Gpz`OZ=IU6GK/?;$6.6)=-@1!(!f ipWmwݓ{qxg\mIFV5qbZoNYnMskRiMupøfk¸yumktkf^`_x`ReR:I7M[AJW>]kZcnbDL:01:7 DG-P[>gvVbpOyҶkx_6B(Q\=PZ;HN49;'55%HE5SNbuVLbCCX9Ͽǯqb=Q6k{jͺ}öøʻ³ȴih\y_TnQth~w`q^qtjTpO]w[;R6@R:O[EVaI2>)ZgX]h\=D3>A*IJ3@C+?F+q|ao}_kwVA(mnQor\<  LS;*wXaqTi|VyuratWasRuiawe/C1|yIWAq|e{`pWxsùĺĺƹz}rveljtr~mvxgqgkLgQMdQexfih[sV^qSS`H-9(EQ@q~lyy9K7@H0rϰԺȧڳ~p{q~c3=)5<&[bD沲xxr$ jqSltMjuKoXe\ssjk~bxZPgJqmqt~÷jyf>M6jta~|as^ƶ¿ƽqƾDfL2O>>XKnwnuB[I/C5;L?QhTXsZOgNCWA:N8BVB;N=GVF8D0JR8CJ.[jMI]Ady_`qY4?(;C,mu_|XlS_jPřǦwhzUTeFM_@crRŶܟr V[I\r|\yaarJk~Wg|Zg`mj}zwWqU?Z?RkSƽMYFHUA[fTyyŷľSqcc~iPmT9S<7L8K\Kat`d{b^vYbz\f}``x`RkY_uXx{k~fPhKKbEriizf:J3?L55=&CH2BH0GP5CN3VdHre~}NbLDVAP]HclRǰǽĽFM:)cjXgqZAK0V_B`jM[gIXjI\nN`qSZmPKcHJfMjmsut~gQXC:A,HO;FO=1<-*5(O^O~~|z~}pf\pTZnXauam}iŶ>SKS9CS7]oT_rYRfOXmW|}orBL<08$25%44$=?-HO>ƶiiqqĿ̷brPHM8@   $#1fj\P^BR[AbmSaqW}~RiVsyJUG%-"'10$52$=?/U]LDM<,2!27'4>-EXDJfNtwøɼpqOdOGYDES>GQ=8@,?D/GL6HQ8BS8MaE~vps6L7NcIȶ̸YsTMeJPcQmzmuu\iFy_KN?  ,*hBF7|xƼRkXd|jan`&/"%*"%89+68)5;,bl^WbR/7&5;*4=*5F/VlSȴyeype}bxq{DWC>M;8C239*=?/8:(:=)@A-EJ4P]Ak{_jmOiRMhLhd̦ɳ|ndw\IYEIUD_iUyi¦m[N[;pwYڈsS  +* ;BC25<.XaU{Ƹ_uedn'.!#%'%%&JO>>,?@/AD/S]@wggdxr[tYxxǪӿʱ~jp_]oR9I2?G4dgRŬP]?LV:\aDkGK<(  bdQopvfIQDai[kp_IP>^dUnsfqwUlaIcWPf[fxkosip[bY #*&)"53$diSCK8-5$u~nbp_?M<9H4K\A}OiT.G49O?4G9#7+=TIyyhzegqQLW:FK945(,,/.9;'>A+@F-OX=sxptjYo[jrZO^:FT4UcD]iJSX=HH/vCH.ZZBGD)z{\ݛZ()# *(UGyƯf\hM9B,<@+IL3KR4YbDvukriuk{Wu[xr~t_i}Sr\^pKEQ4EJ/OO3IE,>:#prY?E)JH0A; ~z^LLF*  :3"kMG6^[GacJOR;;>+>B2PVELQ@PVCMU@ZfRxv~vvi~mtVbV"*()'1(7+ 0&,(,,:>(blPl{^jz_uuVt\MkU]y`}LfRMcHcvUN`F5E3+:-+=.OeP¶ºpjYlOvuaMW6!on[AH/96$LH+[ڪU3326E<%QI0WT8_aEpɴ]kXNbPksw}-5*)(+$+#5(9)/"-%2.VW>krSlyWapO]pLrcwspvSy]]{c[{Wd`NeM7F3>N5=M71A0/@04H3SlP`|UOlBxeu~[V]C89#0/26&5<-FK:S\HWjT`v[gy[ì|LeF˲\nTJJ3VM6L@+B9%v66!6- LE,bcB999&"WD:!E:!idHqyȺ˸LTEEQCg}lykwWk[DN>43&0&6'6)1%/!7(@8)KK4U[;]gB]iD\kChzNn]um¯LeD9N2;L58I42C/:K8[mV~w˷shAV5arUhqW@C(>@$SU>EE4('&(JWAjcj|ZsmM\I>:'>.=.B=(rv{a=3 ?4"C>&bbI==+G;'G;)9-3&6(3, 43 AE*QV:UZ@W]@[dDS_ASeHXmRfhjq(;*,:),:+1E6RjOsµ¼mu3J57C*BE,EF.B@,40!($-(89&IW>1F;$A=$liiZH@6 WJ0yWcWS4fcAm~uP_J4<*9A0m{hwbf|ZfGI,HG1F?(L?+D3 @1 7/74BC(PV7T[=HO69@*2:%6=);D/FQ;UeOCZD?XB>XA4N6+E+WsVȷ˼ZnZS[HjjlNHH-ED,FD074 1.@D+OT7XX8jtPduPeuSl_XmO^vXuowHM@@1#F4"@2K@%e]?c[?;,;0F?(WT=665(LE1q;.B2RE+kbGUR3Z^;f;B6/:(WcQĢtjzZ_jM~PN992 B6&=1 =0G;&PG0JC-?='DG0MU>LYAGV@CN;:?-8<*4>*.:',FB1;6!<5JD,UU;[^CWX&`U8jaFND.=*<0WQ=ýehM^[A@5"Z  II6-`X=B1J7!N@'^T:ojOknRrLPCPSJQWK;B57@1{qku_nz[s|_rw]BC-:7#A9%<4:1:1=4#<4#3/DF4go\|HP@5<,3>.K^L>VBJ]K|{ź{|`~ZLe>m_MW@1.0(0';/F<%GC*XZ?chJ]cEmuakvYW`F/EJ2)4(8)?/F:$IE,MO5HN4R[@vlbqVOZDUYDBF2|qʻp{lC@0@0!F1 M7$N7!M6N6!J/D)=*TK*95 9:(hoaϻϻl|YP^;\hGmvVkkK\Y>D=':0!;.#:/%5-!0*/+.. -7(>OBaph~˽Ƚ@ZG7O9J^GI\CGZ<_oPVbD\dJKK4:4 2%2#6&B0J;%JC)HG.BE.;C-DO7PY@SY@XaHZaKYYFVYF|TSG=,C*L5!T>&T:"N3J/G,D+A2}8/#B1M6"J/0W53!SM/h]>iY=M; G8I?&]Y@poUUT8=>)u|mžxxcGK2AA,1/.)/),*./"7:-8=/6G=*:-7'B8'\UBPG2RI3ZV=\]C[]CJO6OW>]aLNN9@>'MH2;7#abOpxgORD<0#B(J,L2P7U6T5P6K4 B/kbHYRK7'F3Q;#N3>" ><';c\9wlHxjIWJ,K>#G:!PE,\W=rrW|ʿõϽ|QUA:=*gjXfgVghW`dTekYu|i}t|o{[qdmqƾ~j{`vAA.0'B3!C4#A1!>.NB1f_LMF1E?*MJ4WU>_]E\ZBmmVjhSXS>RG0WN6IF.qs^w{gPI9?-F)M+N/N0U5aD,_G0H4B2{B2+>%B*Q9"O4B$.84"WpiIwnJgZ9YL.TI,j`?riFZW7uȹϹǶhlYRUByrx|ſĽr{aiYya-I77R?]w_^ue@WECVB[jWhucxqoxfPVCW]Jrxfno]E<+:+3$7&>+@*F1"K7'G5"G8#QG.UK2N@,M>+TE2M?+N?+XF.WJ0\U=b\FaVCN<,D+J*Q.P0U>&gT:lW>[D.@/TH5žQNDB&H'D$Q1M.A"E82"svoQwnN\N/WG,neGo_^`<ʼz~ilp_ghWbbORO>PM-69'38#9@+AE3>;-71$86'EH5LK7B5#?.5%9$>$B$C$>"H.O7!WD)U@'H-F*A&?%H.T;$P:"Q>'G2@'?$F(U3 U6!T?)d[ClfNZJ3K5 WI6v<- D$M(J#L$H#@ [ E:%eX;l^@[K.ZL0d~{yTlnOu}yWbQ\hU`mUZhLalNehKWS;PH3@7$80?1#A4%8,6+82!CG0`fP\dU;RL1Z[XpNrdHiRKhMOiLwoXgSO^KRbKAL6MP=38%;A-PV@>>,;6&=6&<5&:1"9+@0"LB.\X?b[D<-:&;'C)D&H%I&H(H)G)F)J+R/X4"R0J*P2aC-W8"K-I*I(F&N.X8]E*j_EhfPLG4@3aQ>A3'D-H0K+I&O*K%A *w  9/#QB%YJ,j\@cW:\S5{xWd}_qjmKv}Vs{XksWwhfpZR\GU\INS>RT?[\DPO7GC+J>*SA1H8(A2#G5(D4&?2#@4%B9*JD4>B01C67\XDw}fd{XuaH^F@O6^lPjw[T`Jxo|p6<';5'<8(FC0hfQEB.:3#<2#?2#A2#A/!E1!M>(WM3`T85)?'hT4qeDL7E.]@)S1A A"&6.:YO3aY=upUzuZ]V9NI+hiKxrtpHz|RilKDG.qv`mtYjtrpU\X=YQ8OF.L@*K:(J5%F1#C/"C0$C1%A4%F<,IC2CD2ANH/CO5^hPtLQ?99(C=+B=+GC0VS?B<)B5&C3$C2#F3%H3%H2"J7$Q@+XE0S<+M5#N6$U=+J/F'C%F,L3!J1F*G&K)S2!W9'Q1 J(K(Q+S)Q'Q)O.V<&eP5dS7M;$?-[M9]^O4&J3f}aR6G4X=&R0C E#*.LF7O{fwu\_\@WO3PC'I<#`Y>uqTunP^R3aV8UL5XP?spmXe\CXJ2L=(F6%C3%G5&O:(Q<*J4&H0$G0&C/'C3)B9*ID3LK8KSCizohE{0rveXdWv1NE8J;KWBP\B[gKckPOT;;=)DA.KC.LD/MD0MB/E9&H6'H3%F/!F.!J1#L4$M4$P6&K1!M2!R4#W9)kUB^H6N2 H-^I3wfPo]GW>(H+S8&kTC^G5E)L)L*Q,U+S-P/M5!p^Gl\CG8!I;(wjYν`\J7+M;#cV/_uYN6L,O)G!C!& @a]QbpԔ}hfZ;bN/`L/XH,fX=gV=Q8!R6M2Q6'J1"F2 K5%M5'L4&M4&N6'N7'N8&K6%H3%K5(Q;0J<.G=-A>*QS<{ltw#S`/dpPj`]w9VKDYKaq\grV]bG=?*AA.IH2HH0IH2RL7MB/I:(J9(I6'G3%D. D,J0"O3$N2!M0!H,F)N,P/H,T8'V4%Q2 bL8gU@\H4S9%P1U8'[C1R8'N0 N*O+R,Q*I*L6#l]Gm_KN?.?2unSȶSS:>2E0ylJYtlAuhLL1P,P)F#?!"P7,tZM:ދuyfS"P,R)L%N,T9 1"^. I/H4!H5"N4R1Q.O1O5bB,iC,aD(U9[>$Y;%Z<+Y:+X:+V:,U;,S;,N9+H8)G7)M=/M>/M>/NB2MG4FH68K?X2u(f/euiiwPsnHia?[Q8OD:I>AF7JH3NJ4RQ8[bFζ|RI4M>+L9'P<)Q;+Q8(X@+cM2`I/Q8$P4%N0 U8"P0Q0!R/ T-V-T. O,L*M+N,O,P,P+T.[3!f;)Z4U4bH2wcP[L:>6"}{hu|ZOB%L>!aV1]yQOCkV5bE)Q.W.R)K%J(cH,E8'k9+I3=)F7aQ5cM1L2N>"ZS2XL/J0V: aF+W<$T8!Z=*Y;/T9/H7+D;*JB0RJ7[WB_ZFIA/H<-K?2D@2DD46?0k{sol<5~BU`^GzvjW~y6UP)E>3HA8G=?F7HG3NL8UY?\hJq]`FQL5QG3UG3YH2U@.S<+YB-_H0cK3cJ5X=+Q3"]>(c@-d@0]8'V0W/X1!X3"[6$^9'Y7%U5"\;&fC,hC-b9&e;(^:$_A-vbM[L9@3"sj[plV`Q7ZF-UA(hZ<̣mQC%W="V1M&R(P'I#D" Y<#>0"v?6*O?-[M6vpTmeIO;#WD,hvwYbZI\I1YB)Y?&]A+eH3^C2WF4ws]sxwXu{~ipq^PSABG5IG6FSFyLt}EwSIAEPteM}}=`X2SI@XNAODDK=MN=TT?Y]CalNl[^@[Y@VP8WL6WG3VD/T@,S<+R8*T8*[>.]B/U<)T7$]9'_:+X5&W4%S0!R0"V3"b=)i@,kB/kH4nO9uV>uR<_<)X5#X4$S3$W4&Z9)W<*^L7wRJ4D/J/^H0x[yr{_TB&S4R+K#M#K#U0O.G*) *&OG1wYVB?2g]Bɺ[V:MB(XH0^I3^N7bY@jȫ˻xZzofrN4fr;tSPASc_L|?e\OsiSnd=PDBN?LR?TVAZ\B^eGejK_^B_Z@XN6VG2VC/WA-W>,W<,V9+U7)Z?.iR>kWCW?+Y:(Z8(W6'V4$S1"U4$Y6$b;)g=*i@-fB.bC.dD1_?-Q5#M5$WA2cN;dJ6oO;]A,YC,rlhPcS;M0!D&\I0ac[>i`D[j]:ZE(J(L!O M#\9#U:"H2(HH5efK|}QO<@8!\V:vǹxkeMWSZM8VG5WE4XB0Y@/X>.Y<-X;,X>.bJ;eN=W<,X9+_=.dB2];+W6&V7'T9(W<,Y9([7&Z7&W8&U9)ZC5pbRxin[DgK:Y>+U@*~ziXO>cP;eK4P1L/r^DbH8`N/TwPgI-T,V'Q"J! M-N4J4)TUCq|np]LJ3OI-[V8ecHԵǣxrhѲpK>t7l~5k:r>zBILFCKKz}?eg9[Y;_ZLsk?g^Z~vYwm>VL;MAK\J_nVblT^bH`_EbaE^\C[T=ZN:[J9\G8[E4ZC2Y@0Z@/Z>.V<.X=0[>1Y:-Y:-\<.cF4`G4cN;iVCbWExm]iXHZC1dM:{hWzouvrgZjUCaG3cF5YB/cU@sgaLVE/fK5oP8dC*X8bJ.m[>P;ZA#pV0lN/W1S(T(O$O.]G2O<'A)& WXEmo^IG1VQ4`]:YV7^[DpìǤvir|ռԺ`G~?sx:n};o>uB|CBIKD|@vxU=lI/[9T8iQ3w_AW:\9T.M#N#R'Q%T1ZC.K3B!' Y[G}rWYCkjIniEWM0F8$D8)YSCjhMrnOleEukNzjQxlSz_`nԴڶЯ^sOEvBpxAq~DwJLHFHKHIN=mu?eh=_]:\W>_[=YTC\SRl_TpaJeULcSPeSRaL^cL^_F\\C^ZC_TA_N=aM=`L;_I8^G8\D7ZG:XPCSUIQRHQK@XG9W=-Y>/aK:q`OsfTeUD]H7\C3_C4cE6eG7dF6_A2X;,[=.bD4gK6z`Dz[uXm|oXt^GtT=yS=vO9kD-`8\:tZ=|`CQ.X0e<#T(T%Y)T&S,Q1G(C 'Y\JuzfuzY^^/[A2W?/Y>.[>.]?/a@1d@3d@1d@/dA/bB/dF4jN;~lOvgoY?x^|bv\DmJ5rJ5sK6oF0b9"^@&lP}cIN)T.jD'^4^0\,S)S1[>%V:"H+$NRD򴶳u~d^fL[[FPD2I7#G3N1N2!^H8gQAjSBkRAgQ@_O?c[KecT^_NjnYt|f\bPhvhU|xIsqFruP}PI{CyLOOQSjgEy>fjBefAeaCd_D`ZH`WHaV\yi}v{Tk^PaV\fS^aHa`GfbJe[Fj]IeUBcO=fKZNBV[QTeaNhgIc_M_UgjYdWEhO@dG8cD4bE6hJ:mM;oN?lL>fF9dD7hI:mN>pR?w^FtYybr]IqT?qU?nUwaMkQ?kL9zXA^FwR:_;%X8kO5eE,W1Y1U.]6_8Y2Q*F$V?%dT3Q>$! rKMD}㯯·]gUKR>WUA]Q?lVFrZHqXGlTEiSCgTChWGfYJ`TG[XK`ukm]mM}}jpp_fkpdh\W{rQmdMe]Me]Mg^Wrejte|j]kWhjSgeNfgPggNolS|x`nfPhWBiQAbM@]UH[bXVidQjiKfaVg]y}mlbPePAeJ;fH:gL=qUEsSDlN?dI:bJ"eG*Y9V0Z2X1S-P)U/Q,C#U@'aS4O?%4)fcc\mۯzpwr}jidSo`N{iSraMjXHkWGnXHmYJjZLdWKaaUlp^mVx_hǿstSy~\~OsjMkdNhaPhaPg`Pf]XmagzjnyekjUlgRllUy{]o~vt^h^IiTCdPBaYN^f\YldWnjQjf^pgmVH;dL>pSEmUEkTDiRBfSAaTBneU|mxfvmWw`q^JpRCnPAlVuZtYqYqYAlUeNvT>uN:xS=sS8hK,iO/R5W4X4T1Q.P.P/K-G1UG.RH-@4WODY]]T[Ѥwyguuclws`h_Pi[Kq`NoaOh\Lc[Mbh[odMpiFnl]xbR}|^|ʺϾȻdqzǸdYuX|r[ypZqiUg^Xi^^m`fn\jiVmhTkiQknzs\tbNlXIdYM`dXaqg^voVplZpgWPBiSGw\OkSFgWF}s]or~rzlwi\gPD|iUnwgSrTDsQ?xVBvT@uQ=vR>yXBvX>v[={cEM1V5S5aE(Z?#]E+^G.M7_N5fYAI=&8*YPEJ-,!GQQCrsh}|bjI`gQnmgUiaQnhWsp^mlZq{l_IkaU|tV{tRwoQunPtm]yĴlXyiuhbyWocWi]csden\ggSrmYnkTmkVrq\uv`xw_h}oYn^LeUGa[OeoeczsZspSi_wpb`MjWIjRGhUJ~pι{zi`ZMaXJ{pqf[thX|ѽzwhdQAwUB~XB|XA|YBbKcKx[CoR:cI-^E(N2W7\<qY9n[;h[9,;7,:9+WZCx_{ruTA<"74bbHqs^sccUvthrjvi~RwmvaZxnawfjumxȼ̾ŹyfSnb]sc{xwo\bPhjXop[ljUhbOlbOrhUukXueUp]OhWKc[PdmaeypZpjOe]TfWjgVHhTGzq_xvydjlXhjWmkYsiWscRq_N~m]qok^pSFwS@]IzXD{YD`K}\GwVBnO:`C+eI/W9Q.Q-M.S:!YG-_P7H6#G5#@0:*7)VND'41$94"-%/$5&9,A<(ON;MM:61?2G6E8!|xcqv`tǴѸnl`b\Pyyczrnk[|rYxl]~qw~~Y~s\wj[zn_~lmq{wksapu_yyenlXmfRpgUlaPk]Nj]ObYLhj\~zWqiQe`ZibcbQlcTnhVghp±ĵwi\IlZGs`OqaOpjcZw\RzZLz]I|_JaL|_Jz]H|`KoU@YA(\F*cH-P/O,I)Q3F+<# A*I5!E4 =/;1YUIIJBij]HF76/G>(LE,@<$[YC}dRJ.TE'ZL.ogPpo_rq_keWxwd^~sutnb{U|p]v|{giwdlz|tofq]rxdus`qjZofUnbRpaRl_Rb]Qvpi|Wmh\khzϽ~ovxtjXs]M{bSt^NxhVvkYufVl[iTfQhScP}_L}_LfPwfLldEwuUYQ4Q?$D+F*B&I)M*F&@&<*:1[XKj}}|GJBh؎caVOK:d^ITN5[U<}~bkkK¢jmmZq{|lñ°wdu{ɽwkys|y}~tqjuarubro^mgVmdSvgYwj]kh[~s\wn`rm̸ɱuvsa}ulYxdS|dTr[KrZJ{aQkY~fRlWnXkVfRbOeQlWmSrS_\Q4]M3^P7RG.ZL5M5 G(A"@(=-94\[OSLOGLotjw{skkaDB2EA,OE.G:#ibKmrWfoRȪغ|orc}qv}pxq{ysnɽҿʻ~vzvyomq|ijm[ihUmhVuk[uk^hhZ{{`sjzvydtsd˿yyxgzsbtjYxjYp_q[KuZKwZKx]Kz_LgRlXkVhTjWiVkVzeMfQ6\K1RG.ulqG;%;'<&B1>3<7"^^S<ch^.`fXPRH?=394";0@/B0TJ8]\I?:(dcF~kqqaxxiqmlpwteonav|pyɹϿx}|~tug}i}yujk\qp_xtdzvgopbuqgrwqquaxzz|hsm\wqanp|iiWy^N{`OhUiTmVoZs_mYjVjWnZydMY?&H1]Q9ghVMP<[\F]W?F9"<->1>5!=8%^]S$_dXW]Lnpghh_GD1:1A2N<(L?-G?,A1 C9hɨk|ze~imjzgzvfssd|uоɽyt~qstivuiyyju|ysxtxp|}{j{tdw|gxezdTx`Qn]o\jUkVr_t`p[p\uaxeNT@&H7OC+bXCJA.oq^eoYms[QM6>4<3=8$;9&n\\R qsnUXL`cf[}wko]MH1=0F4E4 D6"D5 B9buqto~k}}lvwgxqϿǽǻŷƹ¹{˸μtzpqsgy}nyryo{|nywhvl_rcyoxot_QhZiZeUgUucs`o\ubt`wgPlaHd]FD:$F4!J7$~zb`lOtW[F830*;7$UTHKrrnWTJ>@>.TVF_`NOI48+A/R?)PA*D5 E?#evqrol{}kuxjϽo~~ķ~ƹĴqzo|u}}{xitl`rg\wh\~n^ucmrxwxzgXeVfXfXhWo]n[sa{h{fitor]ID/ZJ4I5!VK0[\<{fQWB97#1.87#bbZ0WSG6/92@8%?4:+B1VG.UK0D6IB%qs{yl|xmzyjy{j}rz}˾´îκ¸ƾƴʰwyytn|k}qdyl`tfra|iYqcxjxjue|jtan\lZjXmZp]tawe|jrtheiQQK3_N5K9!?1PI.SQ8GI2@B*<>'>B,xdf\ig_HB0`9.:+;+?/H;!VK0OE)C3LC&fzwzzlsv~v~̷dz̶˷ļħ¦ñҿv~nu}mzjrctf|mvfm^|mtq`tbr`wdmxds^jnnzizii{uVhiGddEN@&S:#UB(J<%A8"A>&XY>PV;HN4V\JKrtn\WM99.<+<+@4VN4^U:E9@1RH-a^?RW=ryhw~qǮɵɺŸȴ̹ò͹ʺ;©Ͼҽ˳wwuzlseug{m{nqdpcw}|jp{ir`txy}s}l~k{nXf\>qmHqmIRC'M5 S?(N?*=3!JH1x{afmR]dKrul+if_I?.<,;,>5TP7QJ0B7A6XR7VU5OQ5fjW~v~̿ķɷƴIJŲĭиѽƷ~vrwkth{o{othnatgusziust^ou~mm~uZmeEunLibA`V;B5 >+>-2)@>)su]mrYszgj}yb]UF'RE1G9%;&4","?>)_dJioVy{s2b^W&:1 8/C<'YW?D@'D=#@9$GE-KN1ZaHƹȸȱ¼÷~wxwysrxosksixk~p}oxjxjq{sqwersqsynvtXacCHD+A5#D2!I5 I5<.2+``O|pku`wzsdb[ =7'T81B=(ZW@ML5ikVjkZ;?,18"SYK}wu~ù~yzym|o}n{l{l{mzl}ptvpzlykzjzi{jvlifLTP6G@*=4!;0M@'PE,D<$fcPak^?quphd^)=5#<8#UT>orayEQ=?J;ƿ¼ùzǼ|xxƽtvztqstxkzl{n{nxk|msyutmYTM5@:"EA-^ZI@8%I?)gdK88"stdcbZ 52S75"FF2lmWinTFUA~}ETD»r{µĻp~Ϲ̶źļ¶l|ƽzrvwzmykykymzn{mztZ[DQT5qvS{eafQ==)73bcHIM3IO:ajWkrc>{}ydd]%42:7$9:#9@$@N5bp\p|kDRAyxź´°r}ȿŽnyξvstxs~q~±wemW9>)14FK0}mYePXcNwzuklf @C.HHI5LO:T\FNW>OW@>G3BM:IUDaqc|Ƶ;IJ̳ƽ½yɻοòƶſyzw||yx|Ȳνvr}gajTu{i^j]3=,4pro||{hjbFK7?E1>F3?G-AH.9A)4='8C.;H6[kXǵ˺Ⱥ¸|wxw|wvϿпø|yM_JFS@LVDozd}]i[slok||{eg_207"CJ6djUM=8?,?F1ZcI[fNuxs~~opm*0c>D2quijtaAO8ZiUxwJXI=N<ľƾ¼úƹ˽ƹpw9G6JQ=@J2>D,PWBQ}}|yzxX[S"/4%OWIp}gZkOdx_qs~g~kToWtu³ҼĮ˽ʾjymXeUen[EP:14#npi~~{{zVYR52;*S`JYjP^tX`y_ltpylsgmxεǰľúļƹɽrsw{Yf[OZL:A3\]W)z{z*1"[5>/:G6EW@SjNbepvbgGhLC`KqyǺн̵ԽǿſľȹɼɹʹĻ}V`Y7?536*10$O|}|NQJ(.$}'/#1=-7G3McLb{`ToS9Q9,B0J^Tʳ|t}[j_CNC*0$&&3/"oSPIJNH)*2&*3&*4'4B1AR=J\EDV@2C2->2L]TðѽϷ׾ĭǾǾŽȾ~}wt~gwn}JVK*2$''(#3,SOH#JOH9-4)(0$)2&*5'/=,;I8:H8,:,,;.EQGq{tʝȴŭ÷źzjk[Z\J]aOwqn~nFRB+,'!)!2*TPH1JOJF,4,&/%%0$$4')9,-:/,7-,8-7A8S\Tw{̺ʶҾǴȵŵʷĶto`C=+4+@;(HJ6=@0*)&* 2+UQI;;GAO$3(%5(#7+%9.'8.(8.*;0/=2:E;WbY{~Ǻ÷ǼͿ;vQM95*:+=6!>9%6,1$1$0%LG=BGWQ.B8T+A5)A5$=1#:.&;/(<1):0,:/;I=Zf[Ǿûɾö˺~sYWBD?(5.F>(YU@C=)/$. 0$2)FQMDM\[1JFS.JE.KE,F?)?7(<3&;1&;0.B58K>]h_Ǻöƾʿ{lbZFE=%ZR<>8"F@*B:(1%-2$5*DVQHWll7[YK/TQ,NJ(HC#C=#B:%B9-H=,D98I=Xf[õƹƸ̿ʼĶyiaVBC:#2(2(3)7.1&*.1%nvGv{?lo3ce2ae@fkYtxvyxsb_ZHG?-3(4*4,8/ + .!) U]WQzyx{~q}}l}~@Py{Ly}IzOQDy9r}:r~Cr}Pt}g}yob]TFG@0;7$:3!2(*!*$2.A<,b^Y3d_[zyy|j|}.NwzqGv}Mz~TSE{;w:t:lyEo{\oſ~uihZLN?0=0 1)-(2+0'0&;6&LL>glke%~~~}i{|ey|AItwIvxKy~Gz;w6r5n{8o|AuNbw}yplbVUG9D2#7&3%3+6273 .(83#gf^~FANfz{qoi]WQMD:>2&4%.--* *+#??0e[\R.ZZSRbgC[g75_on+^r(Yr"Ur#\x6pG<}5{BO[cmxkausN_]9B>() &(&&() 9,#gIC:1][U `tx Kmw/Gjxa3_tWr)bx;s:u-n.n/r6y?|=pJv]jrzsbPw{LuyLuzClp7[Z$:6%0)'/'#&62+B:3ZC92(a\Xdu{?gvI7eu|+bt-dv/gz0j~0m0n.k}']s0by8i}ArM{Zadgr{~{ysumw|t}wk|{hY~MotBjn;kp=jr9cl8ej5\_6WWF^[uBQMClpnjvz:al7_kN:es|1et3lx1ky/fu,^n;jx=n|4hu2er2cn+Wa!FL$CB=UOO^V6@7 "* 0B97TO$EE8MOjstp\{|Yx{b|~_z}Fms*[e-Ze-S`7Wav;[aHIgkv{|8cn lv_:fs:co5bm6ft/^l*Va/V^6Y^-MN84(6-)/$*0%&",!)91(A<%CDDG6WZ[pqbzzRtvCio@goEkt<+.(CI(JQ.S[=^dFejx@dkZ0\e8Gel??????????????????(0` %   !%(*,----,*($!  (19@GLPSVXZ[ZZXVSOKF?80' 3COX_dimprtuvwwvutqolhd^WNB3 6Tdnswz|~)*'RROgffrrpuvsturdgcYZVEEC }{xvrmcS58Ufpuy NPKҬ¹˾ʾ¼vwu23){xsneT7$9IW t>H9y񶽫yfRW=?@6 eTG7"  1,2%P_C铢Ǿͼle˽ì{kqY^>&&c'  DF??XbKDžyȿ˻vn˹ijskxlet_unwZpxTedC2/   NPLSzl̶xwǮžXkUgyb}|eya]o_[jK[]?@7!3)   oqjiznhĪsoGYKënssdsYlR_q`xm~cpSW]@JM0UR85, , KPBYo]fwTm}`żĸ}uqgyZTiRM\Fdr\U[EOXGR=WgUDJ7X`Hq}^fsZMV?prZ nyUi}Wxud|_sqýLZE~{ſnuelF68F2ļŻ|y-DH3`oSYrWű}_o[teoPgiXW\LIN>kpcZm`e{mpvkuk)&HG6EL:tpZjSu{:Q<*=0najO7:'JO6wm||l~WLW:PP7x~bWT:lm]Z 4VP8~m`sbs{00%2'1&OQ8cqPwklp~|F[B=M7FXDtyfNT:GJ6Z`Pmd{LO:KA-npZJE.80d[?mnKxR[Hr|YTS:D8%=0 ?@(MU;DM5KZCMdP8N8PU?CA*=:'RY=u`m{aunF>.PD,WN6ZS="7L='UI/YYAMO@T]LkTV;D?'>5$;6'V^MIUEBTBvwd|\ix[60>2RS8foRmy\IN7|MO=I2!R>%D0 x[XH?/1.FaS5K>%c`GtƻMN8FA2EF7PUGyzwlOT*=0PF1VS;NQ:OM8SQ;ehXC)P5U9"RA+B/J/  ?:(xgZ;xpOwwXuweWUDbbPtr~xek[u^RgQj{eDSAGM:OO@RTAG<*9%D(G1O=%K3"O8$SB+K4#P1^O8VC-`UJH$H% #ZN2e[?olM^lqOmt]`cMTQ:K?*G5&C3&C:*GQB[\tDT=_kRY`LA<+NI6@2$D1"QA+L8%M4"H'N0 K)W6$Q0Q+N*_H-RE0zxlm[:WC)Q.) M|vbmaG[G-`M3S;$XC1Q;+M6'M7'N:-I?0gnZR~uqZ|qTdRQS;HH1SM7K<*G2$M4$N2"K-Q3$O/ \E2O1V9)O*P+]I7\P;qbS:yPfO4N(* lK6!YG-XA(cO6[@&Z>)X?1\P=`YERH8FE4yDV@`Y:K@ML7qy]xy_QC0S>,\D.W=*X8%X4$V0 Y4#Y8%`;'^7$aG3dXFymR`Q5oXA$R+K&9(jfPebN{at\c]Ej;n~EWZKphBUITYDadH]W>WG3W?-V9+bJ9Z;+Z8)V6%a<*_?,cJ:xgVdI6u_xrbS8%p`EqeEfL.P#P/+^]H_Z;oltĩ۸ӹX0eP=shVgTDs\LraT_F8sZByckQ:nJ1aF)^?"T+R&S9$( 򏓄abIG7#O8&hRAeRAmkYyj}~T}{M|G}P]NAdcEaZYteb{iZcOc_GeWDcKlRBkTCwfXwhSrXFzgO{eM`JxT=dG)W3T0P.SB)G>0wYVIwymshxxrl\tzkgfYxy||azarcikXsr[{ycwhUc]Q]tmzxj\Lzn^uqbxjve|wVC{YDzZDdI.T4`I,ZI0QC.TK?ZB@5E=/MH2_YBh^C|ol\Żr}}lkt|pvboiWn`Rtyjsi{smrcQwdT|n_dQcNdOk\?T>#K1E'?/gd\0UYQ\VVKE;&`YDj}sz}mȶ~qqotcvp`{vyúǶ|move{eT}bPlVkWmX]H.{v_a_HA/>5 rrnklf gi]E;%I9$RI/tnyzj̿¹z}q~pte{qfXgVs`vbg`GI:&nrXLL7A>-wvs>6">0RF+UL0xu˷ïïʺɾ˺øźwsesd|lwexeyc}j|gjjKTA)H?'QT:Y\MWZSHY>4HB(NH-fkQµȹƿɻ{nwlqe}oqrv~u[d]?G8"8-gkS~| omi @:%_^I^`O}xȽ»{}p~nqo|mrmhPE>*M@*ZVDzuIH9hMP9\iUfrcvyrt}mJM6]fQtwptupDJ7GN7EP;SbP̽ùǾ}|Ľk{jR[FlthqXZR8ZeRi|ffk¼ƿƼcpdEM;xyv9@4};J7]y^:S?Ǿp|s69.ZYS/xyx9@7)5(2@27D9µïĵ}zlOM;RYJ*$WSLGjom *@7'>4);1APEŽǾǽǹ|PJ5E>)1%<3&`oww C_^*OM)F=@QH~ʾǽ~pL>+3(2%QI@P{~~Nqs};ce9cd:_^qûľuG=,4*0"RJB?i|}8P{I}:rT}{_RC5,2+D@3wwts|}Ehph-bu)_xF\{ZSJ<.#.,$ZZP;||{ny| MkxY5hx/k}3s6,! ,IZelquz  ~xtpkdYH+ AcrxSTQհ瀀~BC@wpb?$= hFP?ɺirWNPA X;"  ?F7z}r°İǹtmrzY\_>Srzitʻfxf¨ar_|z}]q[xj_dHA9" r {ql[ovin~aPcMq~f_hP`iK\eIA>(&wWaB{ph`s\ƾ^w`la\mWCP8UdOLT@iuZS\CWXMW26-Q]iJatVkkºQYF]j[spl~hAN6HS8l}cWhPɿ cg[ׇ}w|38+EK;EN=xs}t:B0=@,vkqm`mVs[`G($cmpZ|pxqmrMUJ1(EE1paqpqtAT0Y`Tyx_kQHB-F;(OP7`dL]_KUJ;P6N9%zC-.)\g[=~}\wjgUTM=dhTre}dRdOYcOAD2ID3OE2@'H,O5"P6"Q9$P3[L6rWC2J(LG9dX=i\@[L4_Q=N<*L7)I@0zndN[ENP:NF3G5%L4$M2"Q4$T:(Q3"P.Q._N9|mdPuPM,C6+ZJ2s\^H/^H6zt^ytdWbU_U]~xBNAchNeaIT@-[B.X:(V3#\6$`>*[9'^F2dS;~]U9O)"\\]N`]E}fȬ@vEKMuwIkdK`P]bI\S>\E5YC4X@3gP>cN=jSCr`Qp[EsbMcC*hO1[3Q/ ede^icQVE3iTClgUswW\VYIib^yi[gUgaKeQ@V\SZaUaE6fH8gH9u]FkSvZDkG/cC([3U8<3*ZKJC~r|tpgWi~fn¸Zvkjp]||cthUaf\qtjXI}jyscrbxd{ZEsS8%zzx|{zB7$K@'^[?{IJ˺ɾwiug}lkox]WJ1LF/`dS[VLYOL6UXBʾ{m~nrtfaHJ=(\YHy{v vvtHK6O[F˿|xV]Gem^`b[@UbL_s`ǻHQ?xzvDJ@FZDK^NʿļNRHXWQG|||3C:)<1GUKƺQK7:3!JD9ex||Hcc.OKF[TúOC12&TMD[}cz{YJx|Cs}oý}tgG@/:4$d`[3p{}Bht/f|LmsDC;0#OKAevus t{~SpxREny4bp8Y^ALE=LGQklUuzHip`pr>z{{??(  @$.22-#222 FjNPKijhffdJKHiE ?2p WO5uB=+bl\OM9X]CfjVO<'d[L:lcF~kcZH`aQUcMLI6L<+K0P3!T:&zp]\C, $"RsjT}qXkQhS^J\N:Y@/_B1fJ9{jWmY/dev/null # are you there? if [ "$?" != "0" ] then echo "$p is missing." exit 2 fi done } sendcmd() { echo "$@" sleep ${SLEEP_AFTER_CMD} } login() { if [ "$PASSWORD" = "" ] then sendcmd "AUTHENTICATE $(xxd -c 32 -g 0 ${TOR_COOKIE} | awk '{print $2}')" else sendcmd "AUTHENTICATE \"${PASSWORD}\"" fi } cmdpipe() { login sendcmd "$@" sendcmd "QUIT" } vecho() { if [ $VERBOSE -ge 1 ] then echo "$@" fi } myecho() { STR=$(cat) vecho "$STR" echo "$STR" | if [ "$(grep -c ^"250 ")" = 3 ] then exit 0 else exit 1 fi } filepipe() { login cat "$1" | while read line do sendcmd "$line" done sendcmd "QUIT" } while getopts ":a:c:s:p:P:f:vh" Option do case $Option in a) TOR_COOKIE="${OPTARG}";; c) CMD="${OPTARG}";; s) SLEEP_AFTER_CMD="${OPTARG}";; p) PASSWORD="${OPTARG}";; P) TORCTLPORT="${OPTARG}";; f) FILE="${OPTARG}";; v) VERBOSE=1;; h) usage;; *) usage;; esac done if [ -e "$FILE" ] then checkprogs filepipe "$FILE" | telnet $TORCTLIP $TORCTLPORT 2>/dev/null | myecho exit 4 fi if [ "$CMD" != "" ] then checkprogs cmdpipe $CMD | telnet $TORCTLIP $TORCTLPORT 2>/dev/null | myecho else usage fi tor-0.2.4.20/contrib/rc.subr0000644000175000017500000000212612120436355012425 00000000000000#!/bin/sh # $FreeBSD: ports/security/tor-devel/files/tor.in,v 1.1 2006/02/17 22:21:25 mnag Exp $ # # (rc.subr written by Peter Thoenen for Net/FreeBSD) # # REQUIRE: NETWORKING SERVERS USR # BEFORE: LOGIN # # Add the following lines to /etc/rc.conf to enable tor # # tor_enable (bool): Set to "NO" by default # Set it to "YES" to enable tor # tor_conf (str): Points to your tor conf file # Default: /usr/local/etc/tor/torrc # tor_user (str): Tor Daemon user. Default _tor # . /etc/rc.subr name="tor" rcvar=${name}_enable load_rc_config ${name} : ${tor_enable="NO"} : ${tor_conf="/usr/local/etc/tor/torrc"} : ${tor_user="_tor"} : ${tor_pidfile="/var/run/tor/tor.pid"} : ${tor_logfile="/var/log/tor"} : ${tor_datadir="/var/run/tor"} required_files=${tor_conf} required_dirs=${tor_datadir} command="/usr/local/bin/${name}" command_args="-f ${tor_conf} --pidfile ${tor_pidfile} --runasdaemon 1 --datadirectory ${tor_datadir} --user ${tor_user}" extra_commands="log" log_cmd="${name}_log" tor_log() { cat ${tor_logfile} } run_rc_command "$1" tor-0.2.4.20/contrib/tor-exit-notice.html0000644000175000017500000001501212144600040015030 00000000000000 This is a Tor Exit Router

This is a Tor Exit Router

Most likely you are accessing this website because you had some issue with the traffic coming from this IP. This router is part of the Tor Anonymity Network, which is dedicated to providing privacy to people who need it most: average computer users. This router IP should be generating no other traffic, unless it has been compromised.

How Tor works

Tor sees use by many important segments of the population, including whistle blowers, journalists, Chinese dissidents skirting the Great Firewall and oppressive censorship, abuse victims, stalker targets, the US military, and law enforcement, just to name a few. While Tor is not designed for malicious computer users, it is true that they can use the network for malicious ends. In reality however, the actual amount of abuse is quite low. This is largely because criminals and hackers have significantly better access to privacy and anonymity than do the regular users whom they prey upon. Criminals can and do build, sell, and trade far larger and more powerful networks than Tor on a daily basis. Thus, in the mind of this operator, the social need for easily accessible censorship-resistant private, anonymous communication trumps the risk of unskilled bad actors, who are almost always more easily uncovered by traditional police work than by extensive monitoring and surveillance anyway.

In terms of applicable law, the best way to understand Tor is to consider it a network of routers operating as common carriers, much like the Internet backbone. However, unlike the Internet backbone routers, Tor routers explicitly do not contain identifiable routing information about the source of a packet, and no single Tor node can determine both the origin and destination of a given transmission.

As such, there is little the operator of this router can do to help you track the connection further. This router maintains no logs of any of the Tor traffic, so there is little that can be done to trace either legitimate or illegitimate traffic (or to filter one from the other). Attempts to seize this router will accomplish nothing.

Furthermore, this machine also serves as a carrier of email, which means that its contents are further protected under the ECPA. 18 USC 2707 explicitly allows for civil remedies ($1000/account plus legal fees) in the event of a seizure executed without good faith or probable cause (it should be clear at this point that traffic with an originating IP address of FIXME_DNS_NAME should not constitute probable cause to seize the machine). Similar considerations exist for 1st amendment content on this machine.

If you are a representative of a company who feels that this router is being used to violate the DMCA, please be aware that this machine does not host or contain any illegal content. Also be aware that network infrastructure maintainers are not liable for the type of content that passes over their equipment, in accordance with DMCA "safe harbor" provisions. In other words, you will have just as much luck sending a takedown notice to the Internet backbone providers. Please consult EFF's prepared response for more information on this matter.

For more information, please consult the following documentation:

  1. Tor Overview
  2. Tor Abuse FAQ
  3. Tor Legal FAQ

That being said, if you still have a complaint about the router, you may email the maintainer. If complaints are related to a particular service that is being abused, I will consider removing that service from my exit policy, which would prevent my router from allowing that traffic to exit through it. I can only do this on an IP+destination port basis, however. Common P2P ports are already blocked.

You also have the option of blocking this IP address and others on the Tor network if you so desire. The Tor project provides a web service to fetch a list of all IP addresses of Tor exit nodes that allow exiting to a specified IP:port combination, and an official DNSRBL is also available to determine if a given IP address is actually a Tor exit server. Please be considerate when using these options. It would be unfortunate to deny all Tor users access to your site indefinitely simply because of a few bad apples.

tor-0.2.4.20/INSTALL0000644000175000017500000000404412144600040010504 00000000000000 Most users who realize that INSTALL files still exist should simply follow the directions at https://www.torproject.org/docs/tor-doc-unix If you got the source from git, run "./autogen.sh", which will run the various auto* programs. Then you can run ./configure, and refer to the above instructions. If it doesn't build for you: If you have problems finding libraries, try CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" \ ./configure or ./configure --with-libevent-dir=/usr/local rather than simply ./configure. If you have mysterious autoconf failures while linking openssl, consider setting your LD_LIBRARY_PATH to the openssl lib directory. For example, "setenv LD_LIBRARY_PATH /usr/athena/lib". Lastly, check out https://www.torproject.org/docs/faq#DoesntWork How to do static builds of tor: Tor supports linking each of the libraries it needs statically. Use the --enable-static-X ./configure option in conjunction with the --with-X-dir option for libevent, zlib, and openssl. For this to work sanely, libevent should be built with --disable-shared --enable-static --with-pic, and OpenSSL should be built with no-shared no-dso. If you need to build tor so that system libraries are also statically linked, use the --enable-static-tor ./configure option. This won't work on OS X unless you build the required crt0.o yourself. It is also incompatible with the --enable-gcc-hardening option. An example of how to build a mostly static tor: ./configure --enable-static-libevent \ --enable-static-openssl \ --enable-static-zlib \ --with-libevent-dir=/tmp/static-tor/libevent-1.4.14b-stable \ --with-openssl-dir=/tmp/static-tor/openssl-0.9.8r/ \ --with-zlib-dir=/tmp/static-tor/zlib-1.2.5 An example of how to build an entirely static tor: ./configure --enable-static-tor \ --with-libevent-dir=/tmp/static-tor/libevent-1.4.14b-stable \ --with-openssl-dir=/tmp/static-tor/openssl-0.9.8r/ \ --with-zlib-dir=/tmp/static-tor/zlib-1.2.5 tor-0.2.4.20/acinclude.m40000644000175000017500000002033112255745673011672 00000000000000dnl Helper macros for Tor configure.ac dnl Copyright (c) 2001-2004, Roger Dingledine dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson dnl Copyright (c) 2007-2008, Roger Dingledine, Nick Mathewson dnl Copyright (c) 2007-2013, The Tor Project, Inc. dnl See LICENSE for licensing information AC_DEFUN([TOR_EXTEND_CODEPATH], [ if test -d "$1/lib"; then LDFLAGS="-L$1/lib $LDFLAGS" else LDFLAGS="-L$1 $LDFLAGS" fi if test -d "$1/include"; then CPPFLAGS="-I$1/include $CPPFLAGS" else CPPFLAGS="-I$1 $CPPFLAGS" fi ]) AC_DEFUN([TOR_DEFINE_CODEPATH], [ if test x$1 = "x(system)"; then TOR_LDFLAGS_$2="" TOR_CPPFLAGS_$2="" else if test -d "$1/lib"; then TOR_LDFLAGS_$2="-L$1/lib" TOR_LIBDIR_$2="$1/lib" else TOR_LDFLAGS_$2="-L$1" TOR_LIBDIR_$2="$1" fi if test -d "$1/include"; then TOR_CPPFLAGS_$2="-I$1/include" else TOR_CPPFLAGS_$2="-I$1" fi fi AC_SUBST(TOR_CPPFLAGS_$2) AC_SUBST(TOR_LDFLAGS_$2) ]) dnl 1:flags AC_DEFUN([TOR_CHECK_CFLAGS], [ AS_VAR_PUSHDEF([VAR],[tor_cv_cflags_$1]) AC_CACHE_CHECK([whether the compiler accepts $1], VAR, [ tor_saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pedantic -Werror $1" AC_TRY_COMPILE([], [return 0;], [AS_VAR_SET(VAR,yes)], [AS_VAR_SET(VAR,no)]) CFLAGS="$tor_saved_CFLAGS" ]) if test x$VAR = xyes; then CFLAGS="$CFLAGS $1" fi AS_VAR_POPDEF([VAR]) ]) dnl 1:flags dnl 2:extra ldflags dnl 3:extra libraries AC_DEFUN([TOR_CHECK_LDFLAGS], [ AS_VAR_PUSHDEF([VAR],[tor_cv_ldflags_$1]) AC_CACHE_CHECK([whether the linker accepts $1], VAR, [ tor_saved_CFLAGS="$CFLAGS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_LIBS="$LIBS" CFLAGS="$CFLAGS -pedantic -Werror" LDFLAGS="$LDFLAGS $2 $1" LIBS="$LIBS $3" AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [fputs("", stdout)])], [AS_VAR_SET(VAR,yes)], [AS_VAR_SET(VAR,no)], [AC_TRY_LINK([], [return 0;], [AS_VAR_SET(VAR,yes)], [AS_VAR_SET(VAR,no)])]) CFLAGS="$tor_saved_CFLAGS" LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" ]) if test x$VAR = xyes; then LDFLAGS="$LDFLAGS $1" fi AS_VAR_POPDEF([VAR]) ]) dnl 1:libname AC_DEFUN([TOR_WARN_MISSING_LIB], [ h="" if test x$2 = xdevpkg; then h=" headers for" fi if test -f /etc/debian_version && test x"$tor_$1_$2_debian" != x; then AC_WARN([On Debian, you can install$h $1 using "apt-get install $tor_$1_$2_debian"]) if test x"$tor_$1_$2_debian" != x"$tor_$1_devpkg_debian"; then AC_WARN([ You will probably need $tor_$1_devpkg_debian too.]) fi fi if test -f /etc/fedora-release && test x"$tor_$1_$2_redhat" != x; then AC_WARN([On Fedora Core, you can install$h $1 using "yum install $tor_$1_$2_redhat"]) if test x"$tor_$1_$2_redhat" != x"$tor_$1_devpkg_redhat"; then AC_WARN([ You will probably need to install $tor_$1_devpkg_redhat too.]) fi else if test -f /etc/redhat-release && test x"$tor_$1_$2_redhat" != x; then AC_WARN([On most Redhat-based systems, you can get$h $1 by installing the $tor_$1_$2_redhat" RPM package]) if test x"$tor_$1_$2_redhat" != x"$tor_$1_devpkg_redhat"; then AC_WARN([ You will probably need to install $tor_$1_devpkg_redhat too.]) fi fi fi ]) dnl Look for a library, and its associated includes, and how to link dnl against it. dnl dnl TOR_SEARCH_LIBRARY(1:libname, 2:IGNORED, 3:linkargs, 4:headers, dnl 5:prototype, dnl 6:code, 7:IGNORED, 8:searchextra) dnl dnl Special variables: dnl ALT_{libname}_WITHVAL -- another possible value for --with-$1-dir. dnl Used to support renaming --with-ssl-dir to --with-openssl-dir dnl AC_DEFUN([TOR_SEARCH_LIBRARY], [ try$1dir="" AC_ARG_WITH($1-dir, [ --with-$1-dir=PATH Specify path to $1 installation ], [ if test x$withval != xno ; then try$1dir="$withval" fi ]) if test "x$try$1dir" = x && test "x$ALT_$1_WITHVAL" != x ; then try$1dir="$ALT_$1_WITHVAL" fi tor_saved_LIBS="$LIBS" tor_saved_LDFLAGS="$LDFLAGS" tor_saved_CPPFLAGS="$CPPFLAGS" AC_CACHE_CHECK([for $1 directory], tor_cv_library_$1_dir, [ tor_$1_dir_found=no tor_$1_any_linkable=no for tor_trydir in "$try$1dir" "(system)" "$prefix" /usr/local /usr/pkg $8; do LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS $3" CPPFLAGS="$tor_saved_CPPFLAGS" if test -z "$tor_trydir" ; then continue; fi # Skip the directory if it isn't there. if test ! -d "$tor_trydir" && test "$tor_trydir" != "(system)"; then continue; fi # If this isn't blank, try adding the directory (or appropriate # include/libs subdirectories) to the command line. if test "$tor_trydir" != "(system)"; then TOR_EXTEND_CODEPATH($tor_trydir) fi # Can we link against (but not necessarily run, or find the headers for) # the binary? AC_LINK_IFELSE([AC_LANG_PROGRAM([$5], [$6])], [linkable=yes], [linkable=no]) if test "$linkable" = yes; then tor_$1_any_linkable=yes # Okay, we can link against it. Can we find the headers? AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$4], [$6])], [buildable=yes], [buildable=no]) if test "$buildable" = yes; then tor_cv_library_$1_dir=$tor_trydir tor_$1_dir_found=yes break fi fi done if test "$tor_$1_dir_found" = no; then if test "$tor_$1_any_linkable" = no ; then AC_MSG_WARN([Could not find a linkable $1. If you have it installed somewhere unusual, you can specify an explicit path using --with-$1-dir]) TOR_WARN_MISSING_LIB($1, pkg) AC_MSG_ERROR([Missing libraries; unable to proceed.]) else AC_MSG_WARN([We found the libraries for $1, but we could not find the C header files. You may need to install a devel package.]) TOR_WARN_MISSING_LIB($1, devpkg) AC_MSG_ERROR([Missing headers; unable to proceed.]) fi fi LDFLAGS="$tor_saved_LDFLAGS" LIBS="$tor_saved_LIBS" CPPFLAGS="$tor_saved_CPPFLAGS" ]) dnl end cache check LIBS="$LIBS $3" if test "$tor_cv_library_$1_dir" != "(system)"; then TOR_EXTEND_CODEPATH($tor_cv_library_$1_dir) fi TOR_DEFINE_CODEPATH($tor_cv_library_$1_dir, $1) if test "$cross_compiling" != yes; then AC_CACHE_CHECK([whether we need extra options to link $1], tor_cv_library_$1_linker_option, [ orig_LDFLAGS="$LDFLAGS" runs=no linked_with=nothing if test -d "$tor_cv_library_$1_dir/lib"; then tor_trydir="$tor_cv_library_$1_dir/lib" else tor_trydir="$tor_cv_library_$1_dir" fi for tor_tryextra in "(none)" "-Wl,-R$tor_trydir" "-R$tor_trydir" \ "-Wl,-rpath,$tor_trydir" ; do if test "$tor_tryextra" = "(none)"; then LDFLAGS="$orig_LDFLAGS" else LDFLAGS="$tor_tryextra $orig_LDFLAGS" fi AC_RUN_IFELSE([AC_LANG_PROGRAM([$5], [$6])], [runnable=yes], [runnable=no]) if test "$runnable" = yes; then tor_cv_library_$1_linker_option=$tor_tryextra break fi done if test "$runnable" = no; then AC_MSG_ERROR([Found linkable $1 in $tor_cv_library_$1_dir, but it does not seem to run, even with -R. Maybe specify another using --with-$1-dir}]) fi LDFLAGS="$orig_LDFLAGS" ]) dnl end cache check check for extra options. if test "$tor_cv_library_$1_linker_option" != "(none)" ; then TOR_LDFLAGS_$1="$TOR_LDFLAGS_$1 $tor_cv_library_$1_linker_option" fi fi # cross-compile LIBS="$tor_saved_LIBS" LDFLAGS="$tor_saved_LDFLAGS" CPPFLAGS="$tor_saved_CPPFLAGS" ]) dnl end defun dnl Check whether the prototype for a function is present or missing. dnl Apple has a nasty habit of putting functions in their libraries (so that dnl AC_CHECK_FUNCS passes) but not actually declaring them in the headers. dnl dnl TOR_CHECK_PROTYPE(1:functionname, 2:macroname, 2: includes) AC_DEFUN([TOR_CHECK_PROTOTYPE], [ AC_CACHE_CHECK([for declaration of $1], tor_cv_$1_declared, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$3],[void *ptr= $1 ;])], tor_cv_$1_declared=yes,tor_cv_$1_declared=no)]) if test x$tor_cv_$1_declared != xno ; then AC_DEFINE($2, 1, [Defined if the prototype for $1 seems to be present.]) fi ]) tor-0.2.4.20/ChangeLog0000644000175000017500000310526012255745673011263 00000000000000Changes in version 0.2.4.20 - 2013-12-22 Tor 0.2.4.20 fixes potentially poor random number generation for users who 1) use OpenSSL 1.0.0 or later, 2) set "HardwareAccel 1" in their torrc file, 3) have "Sandy Bridge" or "Ivy Bridge" Intel processors, and 4) have no state file in their DataDirectory (as would happen on first start). Users who generated relay or hidden service identity keys in such a situation should discard them and generate new ones. This release also fixes a logic error that caused Tor clients to build many more preemptive circuits than they actually need. o Major bugfixes: - Do not allow OpenSSL engines to replace the PRNG, even when HardwareAccel is set. The only default builtin PRNG engine uses the Intel RDRAND instruction to replace the entire PRNG, and ignores all attempts to seed it with more entropy. That's cryptographically stupid: the right response to a new alleged entropy source is never to discard all previously used entropy sources. Fixes bug 10402; works around behavior introduced in OpenSSL 1.0.0. Diagnosis and investigation thanks to "coderman" and "rl1987". - Fix assertion failure when AutomapHostsOnResolve yields an IPv6 address. Fixes bug 10465; bugfix on 0.2.4.7-alpha. - Avoid launching spurious extra circuits when a stream is pending. This fixes a bug where any circuit that _wasn't_ unusable for new streams would be treated as if it were, causing extra circuits to be launched. Fixes bug 10456; bugfix on 0.2.4.12-alpha. o Minor bugfixes: - Avoid a crash bug when starting with a corrupted microdescriptor cache file. Fixes bug 10406; bugfix on 0.2.2.6-alpha. - If we fail to dump a previously cached microdescriptor to disk, avoid freeing duplicate data later on. Fixes bug 10423; bugfix on 0.2.4.13-alpha. Spotted by "bobnomnom". Changes in version 0.2.4.19 - 2013-12-11 The Tor 0.2.4 release series is dedicated to the memory of Aaron Swartz (1986-2013). Aaron worked on diverse projects including helping to guide Creative Commons, playing a key role in stopping SOPA/PIPA, bringing transparency to the U.S government's PACER documents, and contributing design and development for Tor and Tor2Web. Aaron was one of the latest martyrs in our collective fight for civil liberties and human rights, and his death is all the more painful because he was one of us. Tor 0.2.4.19, the first stable release in the 0.2.4 branch, features a new circuit handshake and link encryption that use ECC to provide better security and efficiency; makes relays better manage circuit creation requests; uses "directory guards" to reduce client enumeration risks; makes bridges collect and report statistics about the pluggable transports they support; cleans up and improves our geoip database; gets much closer to IPv6 support for clients, bridges, and relays; makes directory authorities use measured bandwidths rather than advertised ones when computing flags and thresholds; disables client-side DNS caching to reduce tracking risks; and fixes a big bug in bridge reachability testing. This release introduces two new design abstractions in the code: a new "channel" abstraction between circuits and or_connections to allow for implementing alternate relay-to-relay transports, and a new "circuitmux" abstraction storing the queue of circuits for a channel. The release also includes many stability, security, and privacy fixes. Changes in version 0.2.4.18-rc - 2013-11-16 Tor 0.2.4.18-rc is the fourth release candidate for the Tor 0.2.4.x series. It takes a variety of fixes from the 0.2.5.x branch to improve stability, performance, and better handling of edge cases. o Major features: - Re-enable TLS 1.1 and 1.2 when built with OpenSSL 1.0.1e or later. Resolves ticket 6055. (OpenSSL before 1.0.1 didn't have TLS 1.1 or 1.2, and OpenSSL from 1.0.1 through 1.0.1d had bugs that prevented renegotiation from working with TLS 1.1 or 1.2, so we had disabled them to solve bug 6033.) o Major bugfixes: - No longer stop reading or writing on cpuworker connections when our rate limiting buckets go empty. Now we should handle circuit handshake requests more promptly. Resolves bug 9731. - If we are unable to save a microdescriptor to the journal, do not drop it from memory and then reattempt downloading it. Fixes bug 9645; bugfix on 0.2.2.6-alpha. - Stop trying to bootstrap all our directory information from only our first guard. Discovered while fixing bug 9946; bugfix on 0.2.4.8-alpha. - The new channel code sometimes lost track of in-progress circuits, causing long-running clients to stop building new circuits. The fix is to always call circuit_n_chan_done(chan, 0) from channel_closed(). Fixes bug 9776; bugfix on 0.2.4.17-rc. o Minor bugfixes (on 0.2.4.x): - Correctly log long IPv6 exit policies, instead of truncating them or reporting an error. Fixes bug 9596; bugfix on 0.2.4.7-alpha. - Our default TLS ecdhe groups were backwards: we meant to be using P224 for relays (for performance win) and P256 for bridges (since it is more common in the wild). Instead we had it backwards. After reconsideration, we decided that the default should be P256 on all hosts, since its security is probably better, and since P224 is reportedly used quite little in the wild. Found by "skruffy" on IRC. Fix for bug 9780; bugfix on 0.2.4.8-alpha. - Free directory authority certificate download statuses on exit rather than leaking them. Fixes bug 9644; bugfix on 0.2.4.13-alpha. o Minor bugfixes (on 0.2.3.x and earlier): - If the guard we choose first doesn't answer, we would try the second guard, but once we connected to the second guard we would abandon it and retry the first one, slowing down bootstrapping. The fix is to treat all our initially chosen guards as acceptable to use. Fixes bug 9946; bugfix on 0.1.1.11-alpha. - Fix an assertion failure that would occur when disabling the ORPort setting on a running Tor process while accounting was enabled. Fixes bug 6979; bugfix on 0.2.2.18-alpha. - When examining the list of network interfaces to find our address, do not consider non-running or disabled network interfaces. Fixes bug 9904; bugfix on 0.2.3.11-alpha. Patch from "hantwister". - Avoid an off-by-one error when checking buffer boundaries when formatting the exit status of a pluggable transport helper. This is probably not an exploitable bug, but better safe than sorry. Fixes bug 9928; bugfix on 0.2.3.18-rc. Bug found by Pedro Ribeiro. o Minor features (protecting client timestamps): - Clients no longer send timestamps in their NETINFO cells. These were not used for anything, and they provided one small way for clients to be distinguished from each other as they moved from network to network or behind NAT. Implements part of proposal 222. - Clients now round timestamps in INTRODUCE cells down to the nearest 10 minutes. If a new Support022HiddenServices option is set to 0, or if it's set to "auto" and the feature is disabled in the consensus, the timestamp is sent as 0 instead. Implements part of proposal 222. - Stop sending timestamps in AUTHENTICATE cells. This is not such a big deal from a security point of view, but it achieves no actual good purpose, and isn't needed. Implements part of proposal 222. - Reduce down accuracy of timestamps in hidden service descriptors. Implements part of proposal 222. o Minor features (other): - Improve the circuit queue out-of-memory handler. Previously, when we ran low on memory, we'd close whichever circuits had the most queued cells. Now, we close those that have the *oldest* queued cells, on the theory that those are most responsible for us running low on memory. Based on analysis from a forthcoming paper by Jansen, Tschorsch, Johnson, and Scheuermann. Fixes bug 9093. - Generate bootstrapping status update events correctly when fetching microdescriptors. Fixes bug 9927. - Update to the October 2 2013 Maxmind GeoLite Country database. o Documentation fixes: - Clarify the usage and risks of setting the ContactInfo torrc line for your relay or bridge. Resolves ticket 9854. - Add anchors to the manpage so we can link to the html version of the documentation for specific options. Resolves ticket 9866. - Replace remaining references to DirServer in man page and log entries. Resolves ticket 10124. Changes in version 0.2.4.17-rc - 2013-09-05 Tor 0.2.4.17-rc is the third release candidate for the Tor 0.2.4.x series. It adds an emergency step to help us tolerate the massive influx of users: 0.2.4 clients using the new (faster and safer) "NTor" circuit-level handshakes now effectively jump the queue compared to the 0.2.3 clients using "TAP" handshakes. This release also fixes a big bug hindering bridge reachability tests. o Major features: - Relays now process the new "NTor" circuit-level handshake requests with higher priority than the old "TAP" circuit-level handshake requests. We still process some TAP requests to not totally starve 0.2.3 clients when NTor becomes popular. A new consensus parameter "NumNTorsPerTAP" lets us tune the balance later if we need to. Implements ticket 9574. o Major bugfixes: - If the circuit build timeout logic is disabled (via the consensus, or because we are an authority), then don't build testing circuits. Fixes bug 9657; bugfix on 0.2.2.14-alpha. - Bridges now send AUTH_CHALLENGE cells during their v3 handshakes; previously they did not, which prevented them from receiving successful connections from relays for self-test or bandwidth testing. Also, when a relay is extending a circuit to a bridge, it needs to send a NETINFO cell, even when the bridge hasn't sent an AUTH_CHALLENGE cell. Fixes bug 9546; bugfix on 0.2.3.6-alpha. - If the time to download the next old-style networkstatus is in the future, do not decline to consider whether to download the next microdescriptor networkstatus. Fixes bug 9564; bugfix on 0.2.3.14-alpha. o Minor bugfixes: - Avoid double-closing the listener socket in our socketpair() replacement (used on Windows) in the case where the addresses on our opened sockets don't match what we expected. Fixes bug 9400; bugfix on 0.0.2pre7. Found by Coverity. o Minor fixes (config options): - Avoid overflows when the user sets MaxCircuitDirtiness to a ridiculously high value, by imposing a (ridiculously high) 30-day maximum on MaxCircuitDirtiness. - Fix the documentation of HeartbeatPeriod to say that the heartbeat message is logged at notice, not at info. - Warn and fail if a server is configured not to advertise any ORPorts at all. (We need *something* to put in our descriptor, or we just won't work.) o Minor features: - Track how many "TAP" and "NTor" circuit handshake requests we get, and how many we complete, and log it every hour to help relay operators follow trends in network load. Addresses ticket 9658. - Update to the August 7 2013 Maxmind GeoLite Country database. Changes in version 0.2.4.16-rc - 2013-08-10 Tor 0.2.4.16-rc is the second release candidate for the Tor 0.2.4.x series. It fixes several crash bugs in the 0.2.4 branch. o Major bugfixes: - Fix a bug in the voting algorithm that could yield incorrect results when a non-naming authority declared too many flags. Fixes bug 9200; bugfix on 0.2.0.3-alpha. - Fix an uninitialized read that could in some cases lead to a remote crash while parsing INTRODUCE2 cells. Bugfix on 0.2.4.1-alpha. Anybody running a hidden service on the experimental 0.2.4.x branch should upgrade. (This is, so far as we know, unrelated to the recent news.) - Avoid an assertion failure when processing DNS replies without the answer types we expected. Fixes bug 9337; bugfix on 0.2.4.7-alpha. - Avoid a crash when using --hash-password. Fixes bug 9295; bugfix on 0.2.4.15-rc. Found by stem integration tests. o Minor bugfixes: - Fix an invalid memory read that occured when a pluggable transport proxy failed its configuration protocol. Fixes bug 9288; bugfix on 0.2.4.1-alpha. - When evaluating whether to use a connection that we haven't decided is canonical using a recent link protocol version, decide that it's canonical only if it used address _does_ match the desired address. Fixes bug 9309; bugfix on 0.2.4.4-alpha. Reported by skruffy. - Make the default behavior of NumDirectoryGuards be to track NumEntryGuards. Now a user who changes only NumEntryGuards will get the behavior she expects. Fixes bug 9354; bugfix on 0.2.4.8-alpha. - Fix a spurious compilation warning with some older versions of GCC on FreeBSD. Fixes bug 9254; bugfix on 0.2.4.14-alpha. o Minor features: - Update to the July 3 2013 Maxmind GeoLite Country database. Changes in version 0.2.4.15-rc - 2013-07-01 Tor 0.2.4.15-rc is the first release candidate for the Tor 0.2.4.x series. It fixes a few smaller bugs, but generally appears stable. Please test it and let us know whether it is! o Major bugfixes: - When receiving a new configuration file via the control port's LOADCONF command, do not treat the defaults file as absent. Fixes bug 9122; bugfix on 0.2.3.9-alpha. o Minor features: - Issue a warning when running with the bufferevents backend enabled. It's still not stable, and people should know that they're likely to hit unexpected problems. Closes ticket 9147. Changes in version 0.2.4.14-alpha - 2013-06-18 Tor 0.2.4.14-alpha fixes a pair of client guard enumeration problems present in 0.2.4.13-alpha. o Major bugfixes: - When we have too much memory queued in circuits (according to a new MaxMemInCellQueues option), close the circuits consuming the most memory. This prevents us from running out of memory as a relay if circuits fill up faster than they can be drained. Fixes bug 9063; bugfix on the 54th commit of Tor. This bug is a further fix beyond bug 6252, whose fix was merged into 0.2.3.21-rc. This change also fixes an earlier approach taken in 0.2.4.13-alpha, where we tried to solve this issue simply by imposing an upper limit on the number of queued cells for a single circuit. That approach proved to be problematic, since there are ways to provoke clients to send a number of cells in excess of any such reasonable limit. Fixes bug 9072; bugfix on 0.2.4.13-alpha. - Limit hidden service descriptors to at most ten introduction points, to slow one kind of guard enumeration. Fixes bug 9002; bugfix on 0.1.1.11-alpha. Changes in version 0.2.4.13-alpha - 2013-06-14 Tor 0.2.4.13-alpha fixes a variety of potential remote crash vulnerabilities, makes socks5 username/password circuit isolation actually actually work (this time for sure!), and cleans up a bunch of other issues in preparation for a release candidate. o Major bugfixes (robustness): - Close any circuit that has too many cells queued on it. Fixes bug 9063; bugfix on the 54th commit of Tor. This bug is a further fix beyond bug 6252, whose fix was merged into 0.2.3.21-rc. - Prevent the get_freelists() function from running off the end of the list of freelists if it somehow gets an unrecognized allocation. Fixes bug 8844; bugfix on 0.2.0.16-alpha. Reported by eugenis. - Avoid an assertion failure on OpenBSD (and perhaps other BSDs) when an exit connection with optimistic data succeeds immediately rather than returning EINPROGRESS. Fixes bug 9017; bugfix on 0.2.3.1-alpha. - Fix a directory authority crash bug when building a consensus using an older consensus as its basis. Fixes bug 8833. Bugfix on 0.2.4.12-alpha. o Major bugfixes: - Avoid a memory leak where we would leak a consensus body when we find that a consensus which we couldn't previously verify due to missing certificates is now verifiable. Fixes bug 8719; bugfix on 0.2.0.10-alpha. - We used to always request authority certificates by identity digest, meaning we'd get the newest one even when we wanted one with a different signing key. Then we would complain about being given a certificate we already had, and never get the one we really wanted. Now we use the "fp-sk/" resource as well as the "fp/" resource to request the one we want. Fixes bug 5595; bugfix on 0.2.0.8-alpha. - Follow the socks5 protocol when offering username/password authentication. The fix for bug 8117 exposed this bug, and it turns out real-world applications like Pidgin do care. Bugfix on 0.2.3.2-alpha; fixes bug 8879. - Prevent failures on Windows Vista and later when rebuilding the microdescriptor cache. Diagnosed by Robert Ransom. Fixes bug 8822; bugfix on 0.2.4.12-alpha. o Minor bugfixes: - Fix an impossible buffer overrun in the AES unit tests. Fixes bug 8845; bugfix on 0.2.0.7-alpha. Found by eugenis. - If for some reason we fail to write a microdescriptor while rebuilding the cache, do not let the annotations from that microdescriptor linger in the cache file, and do not let the microdescriptor stay recorded as present in its old location. Fixes bug 9047; bugfix on 0.2.2.6-alpha. - Fix a memory leak that would occur whenever a configuration option changed. Fixes bug 8718; bugfix on 0.2.3.3-alpha. - Paste the description for PathBias parameters from the man page into or.h, so the code documents them too. Fixes bug 7982; bugfix on 0.2.3.17-beta and 0.2.4.8-alpha. - Relays now treat a changed IPv6 ORPort as sufficient reason to publish an updated descriptor. Fixes bug 6026; bugfix on 0.2.4.1-alpha. - When launching a resolve request on behalf of an AF_UNIX control socket, omit the address field of the new entry connection, used in subsequent controller events, rather than letting tor_dup_addr() set it to "". Fixes bug 8639; bugfix on 0.2.4.12-alpha. o Minor bugfixes (log messages): - Fix a scaling issue in the path bias accounting code that resulted in "Bug:" log messages from either pathbias_scale_close_rates() or pathbias_count_build_success(). This represents a bugfix on a previous bugfix: the original fix attempted in 0.2.4.10-alpha was incomplete. Fixes bug 8235; bugfix on 0.2.4.1-alpha. - Give a less useless error message when the user asks for an IPv4 address on an IPv6-only port, or vice versa. Fixes bug 8846; bugfix on 0.2.4.7-alpha. o Minor features: - Downgrade "unexpected SENDME" warnings to protocol-warn for 0.2.4.x, to tolerate bug 8093 for now. - Add an "ignoring-advertised-bws" boolean to the flag-threshold lines in directory authority votes to describe whether they have enough measured bandwidths to ignore advertised (relay descriptor) bandwidth claims. Resolves ticket 8711. - Update to the June 5 2013 Maxmind GeoLite Country database. o Removed documentation: - Remove some of the older contents of doc/ as obsolete; move others to torspec.git. Fixes bug 8965. o Code simplification and refactoring: - Avoid using character buffers when constructing most directory objects: this approach was unwieldy and error-prone. Instead, build smartlists of strings, and concatenate them when done. Changes in version 0.2.4.12-alpha - 2013-04-18 Tor 0.2.4.12-alpha moves Tor forward on several fronts: it starts the process for lengthening the guard rotation period, makes directory authority opinions in the consensus a bit less gameable, makes socks5 username/password circuit isolation actually work, and fixes a wide variety of other issues. o Major features: - Raise the default time that a client keeps an entry guard from "1-2 months" to "2-3 months", as suggested by Tariq Elahi's WPES 2012 paper. (We would make it even longer, but we need better client load balancing first.) Also, make the guard lifetime controllable via a new GuardLifetime torrc option and a GuardLifetime consensus parameter. Start of a fix for bug 8240; bugfix on 0.1.1.11-alpha. - Directory authorities now prefer using measured bandwidths to advertised ones when computing flags and thresholds. Resolves ticket 8273. - Directory authorities that have more than a threshold number of relays with measured bandwidths now treat relays with unmeasured bandwidths as having bandwidth 0. Resolves ticket 8435. o Major bugfixes (assert / resource use): - Avoid a bug where our response to TLS renegotiation under certain network conditions could lead to a busy-loop, with 100% CPU consumption. Fixes bug 5650; bugfix on 0.2.0.16-alpha. - Avoid an assertion when we discover that we'd like to write a cell onto a closing connection: just discard the cell. Fixes another case of bug 7350; bugfix on 0.2.4.4-alpha. o Major bugfixes (client-side privacy): - When we mark a circuit as unusable for new circuits, have it continue to be unusable for new circuits even if MaxCircuitDirtiness is increased too much at the wrong time, or the system clock jumps backwards. Fixes bug 6174; bugfix on 0.0.2pre26. - If ClientDNSRejectInternalAddresses ("do not believe DNS queries which have resolved to internal addresses") is set, apply that rule to IPv6 as well. Fixes bug 8475; bugfix on 0.2.0.7-alpha. - When an exit relay rejects a stream with reason "exit policy", but we only know an exit policy summary (e.g. from the microdesc consensus) for it, do not mark the relay as useless for all exiting. Instead, mark just the circuit as unsuitable for that particular address. Fixes part of bug 7582; bugfix on 0.2.3.2-alpha. - Allow applications to get proper stream isolation with IsolateSOCKSAuth. Many SOCKS5 clients that want to offer username/password authentication also offer "no authentication". Tor had previously preferred "no authentication", so the applications never actually sent Tor their auth details. Now Tor selects username/password authentication if it's offered. You can disable this behavior on a per-SOCKSPort basis via PreferSOCKSNoAuth. Fixes bug 8117; bugfix on 0.2.3.3-alpha. o Major bugfixes (other): - When unable to find any working directory nodes to use as a directory guard, give up rather than adding the same non-working nodes to the directory guard list over and over. Fixes bug 8231; bugfix on 0.2.4.8-alpha. o Minor features: - Reject as invalid most directory objects containing a NUL. Belt-and-suspender fix for bug 8037. - In our testsuite, create temporary directories with a bit more entropy in their name to make name collisions less likely. Fixes bug 8638. - Add CACHED keyword to ADDRMAP events in the control protocol to indicate whether a DNS result will be cached or not. Resolves ticket 8596. - Update to the April 3 2013 Maxmind GeoLite Country database. o Minor features (build): - Detect and reject attempts to build Tor with threading support when OpenSSL has been compiled without threading support. Fixes bug 6673. - Clarify that when autoconf is checking for nacl, it is checking specifically for nacl with a fast curve25519 implementation. Fixes bug 8014. - Warn if building on a platform with an unsigned time_t: there are too many places where Tor currently assumes that time_t can hold negative values. We'd like to fix them all, but probably some will remain. o Minor bugfixes (build): - Fix some bugs in tor-fw-helper-natpmp when trying to build and run it on Windows. More bugs likely remain. Patch from Gisle Vanem. Fixes bug 7280; bugfix on 0.2.3.1-alpha. - Add the old src/or/micro-revision.i filename to CLEANFILES. On the off chance that somebody has one, it will go away as soon as they run "make clean". Fix for bug 7143; bugfix on 0.2.4.1-alpha. - Build Tor correctly on 32-bit platforms where the compiler can build but not run code using the "uint128_t" construction. Fixes bug 8587; bugfix on 0.2.4.8-alpha. - Fix compilation warning with some versions of clang that would prefer the -Wswitch-enum compiler flag to warn about switch statements with missing enum values, even if those switch statements have a "default:" statement. Fixes bug 8598; bugfix on 0.2.4.10-alpha. o Minor bugfixes (protocol): - Fix the handling of a TRUNCATE cell when it arrives while the circuit extension is in progress. Fixes bug 7947; bugfix on 0.0.7.1. - Fix a misframing issue when reading the version numbers in a VERSIONS cell. Previously we would recognize [00 01 00 02] as 'version 1, version 2, and version 0x100', when it should have only included versions 1 and 2. Fixes bug 8059; bugfix on 0.2.0.10-alpha. Reported pseudonymously. - Make the format and order of STREAM events for DNS lookups consistent among the various ways to launch DNS lookups. Fixes bug 8203; bugfix on 0.2.0.24-rc. Patch by "Desoxy." - Correct our check for which versions of Tor support the EXTEND2 cell. We had been willing to send it to Tor 0.2.4.7-alpha and later, when support was really added in version 0.2.4.8-alpha. Fixes bug 8464; bugfix on 0.2.4.8-alpha. o Minor bugfixes (other): - Correctly store microdescriptors and extrainfo descriptors with an internal NUL byte. Fixes bug 8037; bugfix on 0.2.0.1-alpha. Bug reported by "cypherpunks". - Increase the width of the field used to remember a connection's link protocol version to two bytes. Harmless for now, since the only currently recognized versions are one byte long. Reported pseudonymously. Fixes bug 8062; bugfix on 0.2.0.10-alpha. - If the state file's path bias counts are invalid (presumably from a buggy Tor prior to 0.2.4.10-alpha), make them correct. Also add additional checks and log messages to the scaling of Path Bias counts, in case there still are remaining issues with scaling. Should help resolve bug 8235. - Eliminate several instances where we use "Nickname=ID" to refer to nodes in logs. Use "Nickname (ID)" instead. (Elsewhere, we still use "$ID=Nickname", which is also acceptable.) Fixes bug 7065. Bugfix on 0.2.3.21-rc, 0.2.4.5-alpha, 0.2.4.8-alpha, and 0.2.4.10-alpha. o Minor bugfixes (syscalls): - Always check the return values of functions fcntl() and setsockopt(). We don't believe these are ever actually failing in practice, but better safe than sorry. Also, checking these return values should please analysis tools like Coverity. Patch from 'flupzor'. Fixes bug 8206; bugfix on all versions of Tor. - Use direct writes rather than stdio when building microdescriptor caches, in an attempt to mitigate bug 8031, or at least make it less common. o Minor bugfixes (config): - When rejecting a configuration because we were unable to parse a quoted string, log an actual error message. Fixes bug 7950; bugfix on 0.2.0.16-alpha. - Behave correctly when the user disables LearnCircuitBuildTimeout but doesn't tell us what they would like the timeout to be. Fixes bug 6304; bugfix on 0.2.2.14-alpha. - When autodetecting the number of CPUs, use the number of available CPUs in preference to the number of configured CPUs. Inform the user if this reduces the number of available CPUs. Fixes bug 8002; bugfix on 0.2.3.1-alpha. - Make it an error when you set EntryNodes but disable UseGuardNodes, since it will (surprisingly to some users) ignore EntryNodes. Fixes bug 8180; bugfix on 0.2.3.11-alpha. - Allow TestingTorNetworks to override the 4096-byte minimum for the Fast threshold. Otherwise they can't bootstrap until they've observed more traffic. Fixes bug 8508; bugfix on 0.2.4.10-alpha. - Fix some logic errors when the user manually overrides the PathsNeededToBuildCircuits option in torrc. Fixes bug 8599; bugfix on 0.2.4.10-alpha. o Minor bugfixes (log messages to help diagnose bugs): - If we fail to free a microdescriptor because of bug 7164, log the filename and line number from which we tried to free it. - Add another diagnostic to the heartbeat message: track and log overhead that TLS is adding to the data we write. If this is high, we are sending too little data to SSL_write at a time. Diagnostic for bug 7707. - Add more detail to a log message about relaxed timeouts, to help track bug 7799. - Warn more aggressively when flushing microdescriptors to a microdescriptor cache fails, in an attempt to mitigate bug 8031, or at least make it more diagnosable. - Improve debugging output to help track down bug 8185 ("Bug: outgoing relay cell has n_chan==NULL. Dropping.") - Log the purpose of a path-bias testing circuit correctly. Improves a log message from bug 8477; bugfix on 0.2.4.8-alpha. o Minor bugfixes (0.2.4.x log messages that were too noisy): - Don't attempt to relax the timeout of already opened 1-hop circuits. They might never timeout. This should eliminate some/all cases of the relaxed timeout log message. - Use circuit creation time for network liveness evaluation. This should eliminate warning log messages about liveness caused by changes in timeout evaluation. Fixes bug 6572; bugfix on 0.2.4.8-alpha. - Reduce a path bias length check from notice to info. The message is triggered when creating controller circuits. Fixes bug 8196; bugfix on 0.2.4.8-alpha. - Fix a path state issue that triggered a notice during relay startup. Fixes bug 8320; bugfix on 0.2.4.10-alpha. - Reduce occurrences of warns about circuit purpose in connection_ap_expire_building(). Fixes bug 8477; bugfix on 0.2.4.11-alpha. o Minor bugfixes (pre-0.2.4.x log messages that were too noisy): - If we encounter a write failure on a SOCKS connection before we finish our SOCKS handshake, don't warn that we closed the connection before we could send a SOCKS reply. Fixes bug 8427; bugfix on 0.1.0.1-rc. - Correctly recognize that [::1] is a loopback address. Fixes bug 8377; bugfix on 0.2.1.3-alpha. - Fix a directory authority warn caused when we have a large amount of badexit bandwidth. Fixes bug 8419; bugfix on 0.2.2.10-alpha. - Don't log inappropriate heartbeat messages when hibernating: a hibernating node is _expected_ to drop out of the consensus, decide it isn't bootstrapped, and so forth. Fixes bug 7302; bugfix on 0.2.3.1-alpha. - Don't complain about bootstrapping problems while hibernating. These complaints reflect a general code problem, but not one with any problematic effects (no connections are actually opened). Fixes part of bug 7302; bugfix on 0.2.3.2-alpha. o Documentation fixes: - Update tor-fw-helper.1.txt and tor-fw-helper.c to make option names match. Fixes bug 7768. - Make the torify manpage no longer refer to tsocks; torify hasn't supported tsocks since 0.2.3.14-alpha. - Make the tor manpage no longer reference tsocks. - Fix the GeoIPExcludeUnknown documentation to refer to ExcludeExitNodes rather than the currently nonexistent ExcludeEntryNodes. Spotted by "hamahangi" on tor-talk. o Removed files: - The tor-tsocks.conf is no longer distributed or installed. We recommend that tsocks users use torsocks instead. Resolves ticket 8290. Changes in version 0.2.4.11-alpha - 2013-03-11 Tor 0.2.4.11-alpha makes relay measurement by directory authorities more robust, makes hidden service authentication work again, and resolves a DPI fingerprint for Tor's SSL transport. o Major features (directory authorities): - Directory authorities now support a new consensus method (17) where they cap the published bandwidth of servers for which insufficient bandwidth measurements exist. Fixes part of bug 2286. - Directory authorities that set "DisableV2DirectoryInfo_ 1" no longer serve any v2 directory information. Now we can test disabling the old deprecated v2 directory format, and see whether doing so has any effect on network load. Begins to fix bug 6783. - Directory authorities now include inside each vote a statement of the performance thresholds they used when assigning flags. Implements ticket 8151. o Major bugfixes (directory authorities): - Stop marking every relay as having been down for one hour every time we restart a directory authority. These artificial downtimes were messing with our Stable and Guard flag calculations. Fixes bug 8218 (introduced by the fix for 1035). Bugfix on 0.2.2.23-alpha. o Major bugfixes (hidden services): - Allow hidden service authentication to succeed again. When we refactored the hidden service introduction code back in 0.2.4.1-alpha, we didn't update the code that checks whether authentication information is present, causing all authentication checks to return "false". Fix for bug 8207; bugfix on 0.2.4.1-alpha. Found by Coverity; this is CID 718615. o Minor features (relays, bridges): - Make bridge relays check once a minute for whether their IP address has changed, rather than only every 15 minutes. Resolves bugs 1913 and 1992. - Refactor resolve_my_address() so it returns the method by which we decided our public IP address (explicitly configured, resolved from explicit hostname, guessed from interfaces, learned by gethostname). Now we can provide more helpful log messages when a relay guesses its IP address incorrectly (e.g. due to unexpected lines in /etc/hosts). Resolves ticket 2267. - Teach bridge-using clients to avoid 0.2.2 bridges when making microdescriptor-related dir requests, and only fall back to normal descriptors if none of their bridges can handle microdescriptors (as opposed to the fix in ticket 4013, which caused them to fall back to normal descriptors if *any* of their bridges preferred them). Resolves ticket 4994. - Randomize the lifetime of our SSL link certificate, so censors can't use the static value for filtering Tor flows. Resolves ticket 8443; related to ticket 4014 which was included in 0.2.2.33. o Minor features (portability): - Tweak the curve25519-donna*.c implementations to tolerate systems that lack stdint.h. Fixes bug 3894; bugfix on 0.2.4.8-alpha. - Use Ville Laurikari's implementation of AX_CHECK_SIGN() to determine the signs of types during autoconf. This is better than our old approach, which didn't work when cross-compiling. - Detect the sign of enum values, rather than assuming that MSC is the only compiler where enum types are all signed. Fixes bug 7727; bugfix on 0.2.4.10-alpha. o Minor features (other): - Say "KBytes" rather than "KB" in the man page (for various values of K), to further reduce confusion about whether Tor counts in units of memory or fractions of units of memory. Resolves ticket 7054. - Clear the high bit on curve25519 public keys before passing them to our backend, in case we ever wind up using a backend that doesn't do so itself. If we used such a backend, and *didn't* clear the high bit, we could wind up in a situation where users with such backends would be distinguishable from users without. Fixes bug 8121; bugfix on 0.2.4.8-alpha. - Update to the March 6 2013 Maxmind GeoLite Country database. o Minor bugfixes (clients): - When we receive a RELAY_END cell with the reason DONE, or with no reason, before receiving a RELAY_CONNECTED cell, report the SOCKS status as "connection refused". Previously we reported these cases as success but then immediately closed the connection. Fixes bug 7902; bugfix on 0.1.0.1-rc. Reported by "oftc_must_be_destroyed". - Downgrade an assertion in connection_ap_expire_beginning to an LD_BUG message. The fix for bug 8024 should prevent this message from displaying, but just in case, a warn that we can diagnose is better than more assert crashes. Fixes bug 8065; bugfix on 0.2.4.8-alpha. - Lower path use bias thresholds to .80 for notice and .60 for warn. Also make the rate limiting flags for the path use bias log messages independent from the original path bias flags. Fixes bug 8161; bugfix on 0.2.4.10-alpha. o Minor bugfixes (relays): - Stop trying to resolve our hostname so often (e.g. every time we think about doing a directory fetch). Now we reuse the cached answer in some cases. Fixes bugs 1992 (bugfix on 0.2.0.20-rc) and 2410 (bugfix on 0.1.2.2-alpha). - Stop sending a stray "(null)" in some cases for the server status "EXTERNAL_ADDRESS" controller event. Resolves bug 8200; bugfix on 0.1.2.6-alpha. - When choosing which stream on a formerly stalled circuit to wake first, make better use of the platform's weak RNG. Previously, we had been using the % ("modulo") operator to try to generate a 1/N chance of picking each stream, but this behaves badly with many platforms' choice of weak RNG. Fixes bug 7801; bugfix on 0.2.2.20-alpha. - Use our own weak RNG when we need a weak RNG. Windows's rand() and Irix's random() only return 15 bits; Solaris's random() returns more bits but its RAND_MAX says it only returns 15, and so on. Motivated by the fix for bug 7801; bugfix on 0.2.2.20-alpha. o Minor bugfixes (directory authorities): - Directory authorities now use less space when formatting identical microdescriptor lines in directory votes. Fixes bug 8158; bugfix on 0.2.4.1-alpha. o Minor bugfixes (memory leaks spotted by Coverity -- bug 7816): - Avoid leaking memory if we fail to compute a consensus signature or we generate a consensus we can't parse. Bugfix on 0.2.0.5-alpha. - Fix a memory leak when receiving headers from an HTTPS proxy. Bugfix on 0.2.1.1-alpha. - Fix a memory leak during safe-cookie controller authentication. Bugfix on 0.2.3.13-alpha. - Avoid memory leak of IPv6 policy content if we fail to format it into a router descriptor. Bugfix on 0.2.4.7-alpha. o Minor bugfixes (other code correctness issues): - Avoid a crash if we fail to generate an extrainfo descriptor. Fixes bug 8208; bugfix on 0.2.3.16-alpha. Found by Coverity; this is CID 718634. - When detecting the largest possible file descriptor (in order to close all file descriptors when launching a new program), actually use _SC_OPEN_MAX. The old code for doing this was very, very broken. Fixes bug 8209; bugfix on 0.2.3.1-alpha. Found by Coverity; this is CID 743383. - Fix a copy-and-paste error when adding a missing A1 to a routerset because of GeoIPExcludeUnknown. Fix for Coverity CID 980650. Bugfix on 0.2.4.10-alpha. - Fix an impossible-to-trigger integer overflow when estimating how long our onionskin queue would take. (This overflow would require us to accept 4 million onionskins before processing 100 of them.) Fixes bug 8210; bugfix on 0.2.4.10-alpha. o Code simplification and refactoring: - Add a wrapper function for the common "log a message with a rate-limit" case. Changes in version 0.2.4.10-alpha - 2013-02-04 Tor 0.2.4.10-alpha adds defenses at the directory authority level from certain attacks that flood the network with relays; changes the queue for circuit create requests from a sized-based limit to a time-based limit; resumes building with MSVC on Windows; and fixes a wide variety of other issues. o Major bugfixes (directory authority): - When computing directory thresholds, ignore any rejected-as-sybil nodes during the computation so that they can't influence Fast, Guard, etc. (We should have done this for proposal 109.) Fixes bug 8146. - When marking a node as a likely sybil, reset its uptime metrics to zero, so that it cannot time towards getting marked as Guard, Stable, or HSDir. (We should have done this for proposal 109.) Fixes bug 8147. o Major bugfixes: - When a TLS write is partially successful but incomplete, remember that the flushed part has been flushed, and notice that bytes were actually written. Reported and fixed pseudonymously. Fixes bug 7708; bugfix on Tor 0.1.0.5-rc. - Reject bogus create and relay cells with 0 circuit ID or 0 stream ID: these could be used to create unexpected streams and circuits which would count as "present" to some parts of Tor but "absent" to others, leading to zombie circuits and streams or to a bandwidth denial-of-service. Fixes bug 7889; bugfix on every released version of Tor. Reported by "oftc_must_be_destroyed". - Rename all macros in our local copy of queue.h to begin with "TOR_". This change seems the only good way to permanently prevent conflicts with queue.h on various operating systems. Fixes bug 8107; bugfix on 0.2.4.6-alpha. o Major features (relay): - Instead of limiting the number of queued onionskins (aka circuit create requests) to a fixed, hard-to-configure number, we limit the size of the queue based on how many we expect to be able to process in a given amount of time. We estimate the time it will take to process an onionskin based on average processing time of previous onionskins. Closes ticket 7291. You'll never have to configure MaxOnionsPending again. o Major features (portability): - Resume building correctly with MSVC and Makefile.nmake. This patch resolves numerous bugs and fixes reported by ultramage, including 7305, 7308, 7309, 7310, 7312, 7313, 7315, 7316, and 7669. - Make the ntor and curve25519 code build correctly with MSVC. Fix on 0.2.4.8-alpha. o Minor features: - When directory authorities are computing thresholds for flags, never let the threshold for the Fast flag fall below 4096 bytes. Also, do not consider nodes with extremely low bandwidths when deciding thresholds for various directory flags. This change should raise our threshold for Fast relays, possibly in turn improving overall network performance; see ticket 1854. Resolves ticket 8145. - The Tor client now ignores sub-domain components of a .onion address. This change makes HTTP "virtual" hosting possible: http://foo.aaaaaaaaaaaaaaaa.onion/ and http://bar.aaaaaaaaaaaaaaaa.onion/ can be two different websites hosted on the same hidden service. Implements proposal 204. - We compute the overhead from passing onionskins back and forth to cpuworkers, and report it when dumping statistics in response to SIGUSR1. Supports ticket 7291. o Minor features (path selection): - When deciding whether we have enough descriptors to build circuits, instead of looking at raw relay counts, look at which fraction of (bandwidth-weighted) paths we're able to build. This approach keeps clients from building circuits if their paths are likely to stand out statistically. The default fraction of paths needed is taken from the consensus directory; you can override it with the new PathsNeededToBuildCircuits option. Fixes ticket 5956. - When any country code is listed in ExcludeNodes or ExcludeExitNodes, and we have GeoIP information, also exclude all nodes with unknown countries "??" and "A1". This behavior is controlled by the new GeoIPExcludeUnknown option: you can make such nodes always excluded with "GeoIPExcludeUnknown 1", and disable the feature with "GeoIPExcludeUnknown 0". Setting "GeoIPExcludeUnknown auto" gets you the default behavior. Implements feature 7706. - Path Use Bias: Perform separate accounting for successful circuit use. Keep separate statistics on stream attempt rates versus stream success rates for each guard. Provide configurable thresholds to determine when to emit log messages or disable use of guards that fail too many stream attempts. Resolves ticket 7802. o Minor features (log messages): - When learning a fingerprint for a bridge, log its corresponding transport type. Implements ticket 7896. - Improve the log message when "Bug/attack: unexpected sendme cell from client" occurs, to help us track bug 8093. o Minor bugfixes: - Remove a couple of extraneous semicolons that were upsetting the cparser library. Patch by Christian Grothoff. Fixes bug 7115; bugfix on 0.2.2.1-alpha. - Remove a source of rounding error during path bias count scaling; don't count cannibalized circuits as used for path bias until we actually try to use them; and fix a circuit_package_relay_cell() warning message about n_chan==NULL. Fixes bug 7802. - Detect nacl when its headers are in a nacl/ subdirectory. Also, actually link against nacl when we're configured to use it. Fixes bug 7972; bugfix on 0.2.4.8-alpha. - Compile correctly with the --disable-curve25519 option. Fixes bug 8153; bugfix on 0.2.4.8-alpha. o Build improvements: - Do not report status verbosely from autogen.sh unless the -v flag is specified. Fixes issue 4664. Patch from Onizuka. - Replace all calls to snprintf() outside of src/ext with tor_snprintf(). Also remove the #define to replace snprintf with _snprintf on Windows; they have different semantics, and all of our callers should be using tor_snprintf() anyway. Fixes bug 7304. - Try to detect if we are ever building on a platform where memset(...,0,...) does not set the value of a double to 0.0. Such platforms are permitted by the C standard, though in practice they're pretty rare (since IEEE 754 is nigh-ubiquitous). We don't currently support them, but it's better to detect them and fail than to perform erroneously. o Removed features: - Stop exporting estimates of v2 and v3 directory traffic shares in extrainfo documents. They were unneeded and sometimes inaccurate. Also stop exporting any v2 directory request statistics. Resolves ticket 5823. - Drop support for detecting and warning about versions of Libevent before 1.3e. Nothing reasonable ships with them any longer; warning the user about them shouldn't be needed. Resolves ticket 6826. o Code simplifications and refactoring: - Rename "isin" functions to "contains", for grammar. Resolves ticket 5285. - Rename Tor's logging function log() to tor_log(), to avoid conflicts with the natural logarithm function from the system libm. Resolves ticket 7599. Changes in version 0.2.4.9-alpha - 2013-01-15 Tor 0.2.4.9-alpha provides a quick fix to make the new ntor handshake work more robustly. o Major bugfixes: - Fix backward compatibility logic when receiving an embedded ntor handshake tunneled in a CREATE cell. This clears up the "Bug: couldn't format CREATED cell" warning. Fixes bug 7959; bugfix on 0.2.4.8-alpha. Changes in version 0.2.4.8-alpha - 2013-01-14 Tor 0.2.4.8-alpha introduces directory guards to reduce user enumeration risks, adds a new stronger and faster circuit handshake, and offers stronger and faster link encryption when both sides support it. o Major features: - Preliminary support for directory guards (proposal 207): when possible, clients now use their entry guards for non-anonymous directory requests. This can help prevent client enumeration. Note that this behavior only works when we have a usable consensus directory, and when options about what to download are more or less standard. In the future we should re-bootstrap from our guards, rather than re-bootstrapping from the preconfigured list of directory sources that ships with Tor. Resolves ticket 6526. - Tor relays and clients now support a better CREATE/EXTEND cell format, allowing the sender to specify multiple address, identity, and handshake types. Implements Robert Ransom's proposal 200; closes ticket 7199. o Major features (new circuit handshake): - Tor now supports a new circuit extension handshake designed by Ian Goldberg, Douglas Stebila, and Berkant Ustaoglu. Our original circuit extension handshake, later called "TAP", was a bit slow (especially on the relay side), had a fragile security proof, and used weaker keys than we'd now prefer. The new circuit handshake uses Dan Bernstein's "curve25519" elliptic-curve Diffie-Hellman function, making it significantly more secure than the older handshake, and significantly faster. Tor can use one of two built-in pure-C curve25519-donna implementations by Adam Langley, or it can link against the "nacl" library for a tuned version if present. The built-in version is very fast for 64-bit systems when building with GCC. The built-in 32-bit version is still faster than the old TAP protocol, but using libnacl is better on most such hosts. Clients don't currently use this protocol by default, since comparatively few clients support it so far. To try it, set UseNTorHandshake to 1. Implements proposal 216; closes ticket 7202. o Major features (better link encryption): - Relays can now enable the ECDHE TLS ciphersuites when available and appropriate. These ciphersuites let us negotiate forward-secure TLS secret keys more safely and more efficiently than with our previous use of Diffie-Hellman modulo a 1024-bit prime. By default, public relays prefer the (faster) P224 group, and bridges prefer the (more common) P256 group; you can override this with the TLSECGroup option. Enabling these ciphers was a little tricky, since for a long time, clients had been claiming to support them without actually doing so, in order to foil fingerprinting. But with the client-side implementation of proposal 198 in 0.2.3.17-beta, clients can now match the ciphers from recent Firefox versions *and* list the ciphers they actually mean, so relays can believe such clients when they advertise ECDHE support in their TLS ClientHello messages. This feature requires clients running 0.2.3.17-beta or later, and requires both sides to be running OpenSSL 1.0.0 or later with ECC support. OpenSSL 1.0.1, with the compile-time option "enable-ec_nistp_64_gcc_128", is highly recommended. Implements the relay side of proposal 198; closes ticket 7200. o Major bugfixes: - Avoid crashing when, as a relay without IPv6-exit support, a client insists on getting an IPv6 address or nothing. Fixes bug 7814; bugfix on 0.2.4.7-alpha. o Minor features: - Improve circuit build timeout handling for hidden services. In particular: adjust build timeouts more accurately depending upon the number of hop-RTTs that a particular circuit type undergoes. Additionally, launch intro circuits in parallel if they timeout, and take the first one to reply as valid. - Work correctly on Unix systems where EAGAIN and EWOULDBLOCK are separate error codes; or at least, don't break for that reason. Fixes bug 7935. Reported by "oftc_must_be_destroyed". - Update to the January 2 2013 Maxmind GeoLite Country database. o Minor features (testing): - Add benchmarks for DH (1024-bit multiplicative group) and ECDH (P-256) Diffie-Hellman handshakes to src/or/bench. - Add benchmark functions to test onion handshake performance. o Minor features (path bias detection): - Alter the Path Bias log messages to be more descriptive in terms of reporting timeouts and other statistics. - Create three levels of Path Bias log messages, as opposed to just two. These are configurable via consensus as well as via the torrc options PathBiasNoticeRate, PathBiasWarnRate, PathBiasExtremeRate. The default values are 0.70, 0.50, and 0.30 respectively. - Separate the log message levels from the decision to drop guards, which also is available via torrc option PathBiasDropGuards. PathBiasDropGuards still defaults to 0 (off). - Deprecate PathBiasDisableRate in favor of PathBiasDropGuards in combination with PathBiasExtremeRate. - Increase the default values for PathBiasScaleThreshold and PathBiasCircThreshold from (200, 20) to (300, 150). - Add in circuit usage accounting to path bias. If we try to use a built circuit but fail for any reason, it counts as path bias. Certain classes of circuits where the adversary gets to pick your destination node are exempt from this accounting. Usage accounting can be specifically disabled via consensus parameter or torrc. - Convert all internal path bias state to double-precision floating point, to avoid roundoff error and other issues. - Only record path bias information for circuits that have completed *two* hops. Assuming end-to-end tagging is the attack vector, this makes us more resilient to ambient circuit failure without any detection capability loss. o Minor bugfixes (log messages): - Rate-limit the "No circuits are opened. Relaxed timeout for a circuit with channel state open..." message to once per hour to keep it from filling the notice logs. Mitigates bug 7799 but does not fix the underlying cause. Bugfix on 0.2.4.7-alpha. - Avoid spurious warnings when configuring multiple client ports of which only some are nonlocal. Previously, we had claimed that some were nonlocal when in fact they weren't. Fixes bug 7836; bugfix on 0.2.3.3-alpha. o Code simplifications and refactoring: - Get rid of a couple of harmless clang warnings, where we compared enums to ints. These warnings are newly introduced in clang 3.2. - Split the onion.c file into separate modules for the onion queue and the different handshakes it supports. - Remove the marshalling/unmarshalling code for sending requests to cpuworkers over a socket, and instead just send structs. The recipient will always be the same Tor binary as the sender, so any encoding is overkill. Changes in version 0.2.4.7-alpha - 2012-12-24 Tor 0.2.4.7-alpha introduces a new approach to providing fallback directory mirrors for more robust bootstrapping; fixes more issues where clients with changing network conditions refuse to make any circuits; adds initial support for exiting to IPv6 addresses; resumes being able to update our GeoIP database, and includes the geoip6 file this time; turns off the client-side DNS cache by default due to privacy risks; and fixes a variety of other issues. o Major features (client resilience): - Add a new "FallbackDir" torrc option to use when we can't use a directory mirror from the consensus (either because we lack a consensus, or because they're all down). Currently, all authorities are fallbacks by default, and there are no other default fallbacks, but that will change. This option will allow us to give clients a longer list of servers to try to get a consensus from when first connecting to the Tor network, and thereby reduce load on the directory authorities. Implements proposal 206, "Preconfigured directory sources for bootstrapping". We also removed the old "FallbackNetworkstatus" option, since we never got it working well enough to use it. Closes bug 572. - If we have no circuits open, use a relaxed timeout (the 95th-percentile cutoff) until a circuit succeeds. This heuristic should allow Tor to succeed at building circuits even when the network connection drastically changes. Should help with bug 3443. o Major features (IPv6): - Relays can now exit to IPv6 addresses: make sure that you have IPv6 connectivity, then set the IPv6Exit flag to 1. Also make sure your exit policy reads as you would like: the address * applies to all address families, whereas *4 is IPv4 address only, and *6 is IPv6 addresses only. On the client side, you'll need to wait until the authorities have upgraded, wait for enough exits to support IPv6, apply the "IPv6Traffic" flag to a SocksPort, and use Socks5. Closes ticket 5547, implements proposal 117 as revised in proposal 208. We DO NOT recommend that clients with actual anonymity needs start using IPv6 over Tor yet, since not enough exits support it yet. o Major features (geoip database): - Maxmind began labelling Tor relays as being in country "A1", which breaks by-country node selection inside Tor. Now we use a script to replace "A1" ("Anonymous Proxy") entries in our geoip file with real country codes. This script fixes about 90% of "A1" entries automatically and uses manual country code assignments to fix the remaining 10%. See src/config/README.geoip for details. Fixes bug 6266. Also update to the December 5 2012 Maxmind GeoLite Country database, as modified above. o Major bugfixes (client-side DNS): - Turn off the client-side DNS cache by default. Updating and using the DNS cache is now configurable on a per-client-port level. SOCKSPort, DNSPort, etc lines may now contain {No,}Cache{IPv4,IPv6,}DNS lines to indicate that we shouldn't cache these types of DNS answers when we receive them from an exit node in response to an application request on this port, and {No,}UseCached{IPv4,IPv6,DNS} lines to indicate that if we have cached DNS answers of these types, we shouldn't use them. It's potentially risky to use cached DNS answers at the client, since doing so can indicate to one exit what answers we've gotten for DNS lookups in the past. With IPv6, this becomes especially problematic. Using cached DNS answers for requests on the same circuit would present less linkability risk, since all traffic on a circuit is already linkable, but it would also provide little performance benefit: the exit node caches DNS replies too. Implements a simplified version of Proposal 205. Implements ticket 7570. o Major bugfixes (other): - Alter circuit build timeout measurement to start at the point where we begin the CREATE/CREATE_FAST step (as opposed to circuit initialization). This should make our timeout measurements more uniform. Previously, we were sometimes including ORconn setup time in our circuit build time measurements. Should resolve bug 3443. - Fix an assertion that could trigger in hibernate_go_dormant() when closing an or_connection_t: call channel_mark_for_close() rather than connection_mark_for_close(). Fixes bug 7267. Bugfix on 0.2.4.4-alpha. - Include the geoip6 IPv6 GeoIP database in the tarball. Fixes bug 7655; bugfix on 0.2.4.6-alpha. o Minor features: - Add a new torrc option "ServerTransportListenAddr" to let bridge operators select the address where their pluggable transports will listen for connections. Resolves ticket 7013. - Allow an optional $ before the node identity digest in the controller command GETINFO ns/id/, for consistency with md/id/ and desc/id/. Resolves ticket 7059. - Log packaged cell fullness as part of the heartbeat message. Diagnosis to try to determine the extent of bug 7743. o Minor features (IPv6): - AutomapHostsOnResolve now supports IPv6 addresses. By default, we prefer to hand out virtual IPv6 addresses, since there are more of them and we can't run out. To override this behavior and make IPv4 addresses preferred, set NoPreferIPv6Automap on whatever SOCKSPort or DNSPort you're using for resolving. Implements ticket 7571. - AutomapHostsOnResolve responses are now randomized, to avoid annoying situations where Tor is restarted and applications connect to the wrong addresses. - Never try more than 1000 times to pick a new virtual address when AutomapHostsOnResolve is set. That's good enough so long as we aren't close to handing out our entire virtual address space; if you're getting there, it's best to switch to IPv6 virtual addresses anyway. o Minor bugfixes: - The ADDRMAP command can no longer generate an ill-formed error code on a failed MAPADDRESS. It now says "internal" rather than an English sentence fragment with spaces in the middle. Bugfix on Tor 0.2.0.19-alpha. - Fix log messages and comments to avoid saying "GMT" when we mean "UTC". Fixes bug 6113. - Compile on win64 using mingw64. Fixes bug 7260; patches from "yayooo". - Fix a crash when debugging unit tests on Windows: deallocate a shared library with FreeLibrary, not CloseHandle. Fixes bug 7306; bugfix on 0.2.2.17-alpha. Reported by "ultramage". o Renamed options: - The DirServer option is now DirAuthority, for consistency with current naming patterns. You can still use the old DirServer form. o Code simplification and refactoring: - Move the client-side address-map/virtual-address/DNS-cache code out of connection_edge.c into a new addressmap.c module. - Remove unused code for parsing v1 directories and "running routers" documents. Fixes bug 6887. Changes in version 0.2.3.25 - 2012-11-19 The Tor 0.2.3 release series is dedicated to the memory of Len "rabbi" Sassaman (1980-2011), a long-time cypherpunk, anonymity researcher, Mixmaster maintainer, Pynchon Gate co-designer, CodeCon organizer, programmer, and friend. Unstinting in his dedication to the cause of freedom, he inspired and helped many of us as we began our work on anonymity, and inspires us still. Please honor his memory by writing software to protect people's freedoms, and by helping others to do so. Tor 0.2.3.25, the first stable release in the 0.2.3 branch, features significantly reduced directory overhead (via microdescriptors), enormous crypto performance improvements for fast relays on new enough hardware, a new v3 TLS handshake protocol that can better resist fingerprinting, support for protocol obfuscation plugins (aka pluggable transports), better scalability for hidden services, IPv6 support for bridges, performance improvements like allowing clients to skip the first round-trip on the circuit ("optimistic data") and refilling token buckets more often, a new "stream isolation" design to isolate different applications on different circuits, and many stability, security, and privacy fixes. o Major bugfixes: - Tor tries to wipe potentially sensitive data after using it, so that if some subsequent security failure exposes Tor's memory, the damage will be limited. But we had a bug where the compiler was eliminating these wipe operations when it decided that the memory was no longer visible to a (correctly running) program, hence defeating our attempt at defense in depth. We fix that by using OpenSSL's OPENSSL_cleanse() operation, which a compiler is unlikely to optimize away. Future versions of Tor may use a less ridiculously heavy approach for this. Fixes bug 7352. Reported in an article by Andrey Karpov. o Minor bugfixes: - Fix a harmless bug when opting against publishing a relay descriptor because DisableNetwork is set. Fixes bug 7464; bugfix on 0.2.3.9-alpha. Changes in version 0.2.4.6-alpha - 2012-11-13 Tor 0.2.4.6-alpha fixes an assert bug that has been plaguing relays, makes our defense-in-depth memory wiping more reliable, and begins to count IPv6 addresses in bridge statistics, o Major bugfixes: - Fix an assertion failure that could occur when closing a connection with a spliced rendezvous circuit. Fix for bug 7212; bugfix on Tor 0.2.4.4-alpha. - Tor tries to wipe potentially sensitive data after using it, so that if some subsequent security failure exposes Tor's memory, the damage will be limited. But we had a bug where the compiler was eliminating these wipe operations when it decided that the memory was no longer visible to a (correctly running) program, hence defeating our attempt at defense in depth. We fix that by using OpenSSL's OPENSSL_cleanse() operation, which a compiler is unlikely to optimize away. Future versions of Tor may use a less ridiculously heavy approach for this. Fixes bug 7352. Reported in an article by Andrey Karpov. o Minor features: - Add GeoIP database for IPv6 addresses. The new config option is GeoIPv6File. - Bridge statistics now count bridge clients connecting over IPv6: bridge statistics files now list "bridge-ip-versions" and extra-info documents list "geoip6-db-digest". The control protocol "CLIENTS_SEEN" and "ip-to-country" queries now support IPv6. Initial implementation by "shkoo", addressing ticket 5055. o Minor bugfixes: - Warn when we are binding low ports when hibernation is enabled; previously we had warned when we were _advertising_ low ports with hibernation enabled. Fixes bug 7285; bugfix on 0.2.3.9-alpha. - Fix a harmless bug when opting against publishing a relay descriptor because DisableNetwork is set. Fixes bug 7464; bugfix on 0.2.3.9-alpha. - Add warning message when a managed proxy dies during configuration. Fixes bug 7195; bugfix on 0.2.4.2-alpha. - Fix a linking error when building tor-fw-helper without miniupnp. Fixes bug 7235; bugfix on 0.2.4.2-alpha. Fix by Anthony G. Basile. - Check for closing an or_connection_t without going through correct channel functions; emit a warning and then call connection_or_close_for_error() so we don't assert as in bugs 7212 and 7267. - Compile correctly on compilers without C99 designated initializer support. Fixes bug 7286; bugfix on 0.2.4.4-alpha. - Avoid a possible assert that can occur when channel_send_destroy() is called on a channel in CHANNEL_STATE_CLOSING, CHANNEL_STATE_CLOSED, or CHANNEL_STATE_ERROR when the Tor process is resumed after being blocked for a long interval. Fixes bug 7350; bugfix on 0.2.4.4-alpha. - Fix a memory leak on failing cases of channel_tls_process_certs_cell. Fixes bug 7422; bugfix on 0.2.4.4-alpha. o Code simplification and refactoring: - Start using OpenBSD's implementation of queue.h, so that we don't need to hand-roll our own pointer and list structures whenever we need them. (We can't rely on a sys/queue.h, since some operating systems don't have them, and the ones that do have them don't all present the same extensions.) Changes in version 0.2.4.5-alpha - 2012-10-25 Tor 0.2.4.5-alpha comes hard at the heels of 0.2.4.4-alpha, to fix two important security vulnerabilities that could lead to remotely triggerable relay crashes, fix a major bug that was preventing clients from choosing suitable exit nodes, and refactor some of our code. o Major bugfixes (security, also in 0.2.3.24-rc): - Fix a group of remotely triggerable assertion failures related to incorrect link protocol negotiation. Found, diagnosed, and fixed by "some guy from France". Fix for CVE-2012-2250; bugfix on 0.2.3.6-alpha. - Fix a denial of service attack by which any directory authority could crash all the others, or by which a single v2 directory authority could crash everybody downloading v2 directory information. Fixes bug 7191; bugfix on 0.2.0.10-alpha. o Major bugfixes (also in 0.2.3.24-rc): - When parsing exit policy summaries from microdescriptors, we had previously been ignoring the last character in each one, so that "accept 80,443,8080" would be treated by clients as indicating a node that allows access to ports 80, 443, and 808. That would lead to clients attempting connections that could never work, and ignoring exit nodes that would support their connections. Now clients parse these exit policy summaries correctly. Fixes bug 7192; bugfix on 0.2.3.1-alpha. o Minor bugfixes (also in 0.2.3.24-rc): - Clients now consider the ClientRejectInternalAddresses config option when using a microdescriptor consensus stanza to decide whether an exit relay would allow exiting to an internal address. Fixes bug 7190; bugfix on 0.2.3.1-alpha. o Minor bugfixes: - Only disable TLS session ticket support when running as a TLS server. Now clients will blend better with regular Firefox connections. Fixes bug 7189; bugfix on Tor 0.2.3.23-rc. o Code simplification and refactoring: - Start using OpenBSD's implementation of queue.h (originally by Niels Provos). - Move the entry node code from circuitbuild.c to its own file. - Move the circuit build timeout tracking code from circuitbuild.c to its own file. Changes in version 0.2.3.24-rc - 2012-10-25 Tor 0.2.3.24-rc fixes two important security vulnerabilities that could lead to remotely triggerable relay crashes, and fixes a major bug that was preventing clients from choosing suitable exit nodes. o Major bugfixes (security): - Fix a group of remotely triggerable assertion failures related to incorrect link protocol negotiation. Found, diagnosed, and fixed by "some guy from France". Fix for CVE-2012-2250; bugfix on 0.2.3.6-alpha. - Fix a denial of service attack by which any directory authority could crash all the others, or by which a single v2 directory authority could crash everybody downloading v2 directory information. Fixes bug 7191; bugfix on 0.2.0.10-alpha. o Major bugfixes: - When parsing exit policy summaries from microdescriptors, we had previously been ignoring the last character in each one, so that "accept 80,443,8080" would be treated by clients as indicating a node that allows access to ports 80, 443, and 808. That would lead to clients attempting connections that could never work, and ignoring exit nodes that would support their connections. Now clients parse these exit policy summaries correctly. Fixes bug 7192; bugfix on 0.2.3.1-alpha. o Minor bugfixes: - Clients now consider the ClientRejectInternalAddresses config option when using a microdescriptor consensus stanza to decide whether an exit relay would allow exiting to an internal address. Fixes bug 7190; bugfix on 0.2.3.1-alpha. Changes in version 0.2.4.4-alpha - 2012-10-20 Tor 0.2.4.4-alpha adds a new v3 directory authority, fixes a privacy vulnerability introduced by a change in OpenSSL, fixes a remotely triggerable assert, and adds new channel_t and circuitmux_t abstractions that will make it easier to test new connection transport and cell scheduling algorithms. o New directory authorities (also in 0.2.3.23-rc): - Add Faravahar (run by Sina Rabbani) as the ninth v3 directory authority. Closes ticket 5749. o Major bugfixes (security/privacy, also in 0.2.3.23-rc): - Disable TLS session tickets. OpenSSL's implementation was giving our TLS session keys the lifetime of our TLS context objects, when perfect forward secrecy would want us to discard anything that could decrypt a link connection as soon as the link connection was closed. Fixes bug 7139; bugfix on all versions of Tor linked against OpenSSL 1.0.0 or later. Found by Florent Daignière. - Discard extraneous renegotiation attempts once the V3 link protocol has been initiated. Failure to do so left us open to a remotely triggerable assertion failure. Fixes CVE-2012-2249; bugfix on 0.2.3.6-alpha. Reported by "some guy from France". o Internal abstraction features: - Introduce new channel_t abstraction between circuits and or_connection_t to allow for implementing alternate OR-to-OR transports. A channel_t is an abstract object which can either be a cell-bearing channel, which is responsible for authenticating and handshaking with the remote OR and transmitting cells to and from it, or a listening channel, which spawns new cell-bearing channels at the request of remote ORs. Implements part of ticket 6465. - Also new is the channel_tls_t subclass of channel_t, adapting it to the existing or_connection_t code. The V2/V3 protocol handshaking code which formerly resided in command.c has been moved below the channel_t abstraction layer and may be found in channeltls.c now. Implements the rest of ticket 6465. - Introduce new circuitmux_t storing the queue of circuits for a channel; this encapsulates and abstracts the queue logic and circuit selection policy, and allows the latter to be overridden easily by switching out a policy object. The existing EWMA behavior is now implemented as a circuitmux_policy_t. Resolves ticket 6816. o Required libraries: - Tor now requires OpenSSL 0.9.8 or later. OpenSSL 1.0.0 or later is strongly recommended. o Minor features: - Warn users who run hidden services on a Tor client with UseEntryGuards disabled that their hidden services will be vulnerable to http://freehaven.net/anonbib/#hs-attack06 (the attack which motivated Tor to support entry guards in the first place). Resolves ticket 6889. - Tor now builds correctly on Bitrig, an OpenBSD fork. Patch from dhill. Resolves ticket 6982. - Option OutboundBindAddress can be specified multiple times and accepts IPv6 addresses. Resolves ticket 6876. o Minor bugfixes (also in 0.2.3.23-rc): - Don't serve or accept v2 hidden service descriptors over a relay's DirPort. It's never correct to do so, and disabling it might make it more annoying to exploit any bugs that turn up in the descriptor-parsing code. Fixes bug 7149. - Fix two cases in src/or/transports.c where we were calling fmt_addr() twice in a parameter list. Bug found by David Fifield. Fixes bug 7014; bugfix on 0.2.3.9-alpha. - Fix memory leaks whenever we logged any message about the "path bias" detection. Fixes bug 7022; bugfix on 0.2.3.21-rc. - When relays refuse a "create" cell because their queue of pending create cells is too big (typically because their cpu can't keep up with the arrival rate), send back reason "resource limit" rather than reason "internal", so network measurement scripts can get a more accurate picture. Fixes bug 7037; bugfix on 0.1.1.11-alpha. o Minor bugfixes: - Command-line option "--version" implies "--quiet". Fixes bug 6997. - Free some more still-in-use memory at exit, to make hunting for memory leaks easier. Resolves bug 7029. - When a Tor client gets a "truncated" relay cell, the first byte of its payload specifies why the circuit was truncated. We were ignoring this 'reason' byte when tearing down the circuit, resulting in the controller not being told why the circuit closed. Now we pass the reason from the truncated cell to the controller. Bugfix on 0.1.2.3-alpha; fixes bug 7039. - Downgrade "Failed to hand off onionskin" messages to "debug" severity, since they're typically redundant with the "Your computer is too slow" messages. Fixes bug 7038; bugfix on 0.2.2.16-alpha. - Make clients running with IPv6 bridges connect over IPv6 again, even without setting new config options ClientUseIPv6 and ClientPreferIPv6ORPort. Fixes bug 6757; bugfix on 0.2.4.1-alpha. - Use square brackets around IPv6 addresses in numerous places that needed them, including log messages, HTTPS CONNECT proxy requests, TransportProxy statefile entries, and pluggable transport extra-info lines. Fixes bug 7011; patch by David Fifield. o Code refactoring and cleanup: - Source files taken from other packages now reside in src/ext; previously they were scattered around the rest of Tor. - Avoid use of reserved identifiers in our C code. The C standard doesn't like us declaring anything that starts with an underscore, so let's knock it off before we get in trouble. Fix for bug 1031; bugfix on the first Tor commit. Changes in version 0.2.3.23-rc - 2012-10-20 Tor 0.2.3.23-rc adds a new v3 directory authority, fixes a privacy vulnerability introduced by a change in OpenSSL, and fixes a variety of smaller bugs in preparation for the release. o New directory authorities: - Add Faravahar (run by Sina Rabbani) as the ninth v3 directory authority. Closes ticket 5749. o Major bugfixes (security/privacy): - Disable TLS session tickets. OpenSSL's implementation was giving our TLS session keys the lifetime of our TLS context objects, when perfect forward secrecy would want us to discard anything that could decrypt a link connection as soon as the link connection was closed. Fixes bug 7139; bugfix on all versions of Tor linked against OpenSSL 1.0.0 or later. Found by Florent Daignière. - Discard extraneous renegotiation attempts once the V3 link protocol has been initiated. Failure to do so left us open to a remotely triggerable assertion failure. Fixes CVE-2012-2249; bugfix on 0.2.3.6-alpha. Reported by "some guy from France". o Major bugfixes: - Fix a possible crash bug when checking for deactivated circuits in connection_or_flush_from_first_active_circuit(). Fixes bug 6341; bugfix on 0.2.2.7-alpha. Bug report and fix received pseudonymously. o Minor bugfixes (on 0.2.3.x): - Fix two cases in src/or/transports.c where we were calling fmt_addr() twice in a parameter list. Bug found by David Fifield. Fixes bug 7014; bugfix on 0.2.3.9-alpha. - Convert an assert in the pathbias code to a log message. The assert appears to only be triggerable by Tor2Web mode. Fixes bug 6866; bugfix on 0.2.3.17-beta. - Fix memory leaks whenever we logged any message about the "path bias" detection. Fixes bug 7022; bugfix on 0.2.3.21-rc. o Minor bugfixes (on 0.2.2.x and earlier): - Don't serve or accept v2 hidden service descriptors over a relay's DirPort. It's never correct to do so, and disabling it might make it more annoying to exploit any bugs that turn up in the descriptor-parsing code. Fixes bug 7149. - When relays refuse a "create" cell because their queue of pending create cells is too big (typically because their cpu can't keep up with the arrival rate), send back reason "resource limit" rather than reason "internal", so network measurement scripts can get a more accurate picture. Bugfix on 0.1.1.11-alpha; fixes bug 7037. - Correct file sizes when reading binary files on Cygwin, to avoid a bug where Tor would fail to read its state file. Fixes bug 6844; bugfix on 0.1.2.7-alpha. - Avoid undefined behaviour when parsing the list of supported rendezvous/introduction protocols in a hidden service descriptor. Previously, Tor would have confused (as-yet-unused) protocol version numbers greater than 32 with lower ones on many platforms. Fixes bug 6827; bugfix on 0.2.0.10-alpha. Found by George Kadianakis. o Documentation fixes: - Clarify that hidden services are TCP only. Fixes bug 6024. Changes in version 0.2.4.3-alpha - 2012-09-22 Tor 0.2.4.3-alpha fixes another opportunity for a remotely triggerable assertion, resumes letting relays test reachability of their DirPort, and cleans up a bunch of smaller bugs. o Security fixes: - Fix an assertion failure in tor_timegm() that could be triggered by a badly formatted directory object. Bug found by fuzzing with Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc. o Major bugfixes: - Fix a possible crash bug when checking for deactivated circuits in connection_or_flush_from_first_active_circuit(). Fixes bug 6341; bugfix on 0.2.2.7-alpha. Bug report and fix received pseudonymously. - Allow routers to detect that their own DirPorts are running. When we removed support for versions_supports_begindir, we also accidentally removed the mechanism we used to self-test our DirPort. Diagnosed with help from kargig. Fixes bugs 6814 and 6815; bugfix on 0.2.4.2-alpha. o Security features: - Switch to a completely time-invariant approach for picking nodes weighted by bandwidth. Our old approach would run through the part of the loop after it had made its choice slightly slower than it ran through the part of the loop before it had made its choice. Addresses ticket 6538. - Disable the use of Guard nodes when in Tor2WebMode. Guard usage by tor2web clients allows hidden services to identify tor2web clients through their repeated selection of the same rendezvous and introduction point circuit endpoints (their guards). Resolves ticket 6888. o Minor features: - Enable Tor to read configuration, state, and key information from a FIFO. Previously Tor would only read from files with a positive stat.st_size. Code from meejah; fixes bug 6044. o Minor bugfixes: - Correct file sizes when reading binary files on Cygwin, to avoid a bug where Tor would fail to read its state file. Fixes bug 6844; bugfix on 0.1.2.7-alpha. - Correctly handle votes with more than 31 flags. Fixes bug 6853; bugfix on 0.2.0.3-alpha. - When complaining about a client port on a public address, log which address we're complaining about. Fixes bug 4020; bugfix on 0.2.3.3-alpha. Patch by Tom Fitzhenry. - Convert an assert in the pathbias code to a log message. The assert appears to only be triggerable by Tor2Web mode. Fixes bug 6866; bugfix on 0.2.3.17-beta. - Our new buildsystem was overzealous about rebuilding manpages: it would rebuild them all whenever any one of them changed. Now our dependency checking should be correct. Fixes bug 6843; bugfix on 0.2.4.1-alpha. - Don't do reachability testing over IPv6 unless AuthDirPublishIPv6 is set. Fixes bug 6880. Bugfix on 0.2.4.1-alpha. - Correct log printout about which address family is preferred when connecting to a bridge with both an IPv4 and IPv6 OR port. Fixes bug 6884; bugfix on 0.2.4.1-alpha. o Minor bugfixes (code cleanliness): - Fix round_to_power_of_2() so it doesn't invoke undefined behavior with large values. This situation was untriggered, but nevertheless incorrect. Fixes bug 6831; bugfix on 0.2.0.1-alpha. - Reject consensus votes with more than 64 known-flags. We aren't even close to that limit yet, and our code doesn't handle it correctly. Fixes bug 6833; bugfix on 0.2.0.1-alpha. - Avoid undefined behaviour when parsing the list of supported rendezvous/introduction protocols in a hidden service descriptor. Previously, Tor would have confused (as-yet-unused) protocol version numbers greater than 32 with lower ones on many platforms. Fixes bug 6827; bugfix on 0.2.0.10-alpha. Found by George Kadianakis. - Fix handling of rendezvous client authorization types over 8. Fixes bug 6861; bugfix on 0.2.1.5-alpha. - Fix building with older versions of GCC (2.95, for one) that don't like preprocessor directives inside macro arguments. Found by grarpamp. Fixes bug 6842; bugfix on 0.2.4.2-alpha. - Switch weighted node selection rule from using a list of doubles to using a list of int64_t. This change should make the process slightly easier to debug and maintain. Needed to finish ticket 6538. o Code simplification and refactoring: - Move the generic "config" code into a new file, and have "config.c" hold only torrc- and state-related code. Resolves ticket 6823. - Move the core of our "choose a weighted element at random" logic into its own function, and give it unit tests. Now the logic is testable, and a little less fragile too. - Removed the testing_since field of node_t, which hasn't been used for anything since 0.2.0.9-alpha. o Documentation fixes: - Clarify that hidden services are TCP only. Fixes bug 6024. - Resolve a typo in torrc.sample.in. Fixes bug 6819; bugfix on 0.2.3.14-alpha. Changes in version 0.2.3.22-rc - 2012-09-11 Tor 0.2.3.22-rc fixes another opportunity for a remotely triggerable assertion. o Security fixes: - Fix an assertion failure in tor_timegm() that could be triggered by a badly formatted directory object. Bug found by fuzzing with Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc. o Minor bugfixes: - Avoid segfault when starting up having run with an extremely old version of Tor and parsing its state file. Fixes bug 6801; bugfix on 0.2.2.23-alpha. Changes in version 0.2.2.39 - 2012-09-11 Tor 0.2.2.39 fixes two more opportunities for remotely triggerable assertions. o Security fixes: - Fix an assertion failure in tor_timegm() that could be triggered by a badly formatted directory object. Bug found by fuzzing with Radamsa. Fixes bug 6811; bugfix on 0.2.0.20-rc. - Do not crash when comparing an address with port value 0 to an address policy. This bug could have been used to cause a remote assertion failure by or against directory authorities, or to allow some applications to crash clients. Fixes bug 6690; bugfix on 0.2.1.10-alpha. Changes in version 0.2.4.2-alpha - 2012-09-10 Tor 0.2.4.2-alpha enables port forwarding for pluggable transports, raises the default rate limiting even more, and makes the bootstrapping log messages less noisy. o Major features: - Automatically forward the TCP ports of pluggable transport proxies using tor-fw-helper if PortForwarding is enabled. Implements ticket 4567. o Major bugfixes: - Raise the default BandwidthRate/BandwidthBurst values from 5MB/10MB to 1GB/1GB. The previous defaults were intended to be "basically infinite", but it turns out they're now limiting our 100mbit+ relays and bridges. Fixes bug 6605; bugfix on 0.2.0.10-alpha (the last time we raised it). o Minor features: - Detect when we're running with a version of OpenSSL other than the one we compiled with. This has occasionally given people hard-to- track-down errors. - Log fewer lines at level "notice" about our OpenSSL and Libevent versions and capabilities when everything is going right. Resolves part of ticket 6736. - Directory authorities no long accept descriptors for any version of Tor before 0.2.2.35, or for any 0.2.3 release before 0.2.3.10-alpha. These versions are insecure, unsupported, or both. Implements ticket 6789. o Minor bugfixes: - Rename the (internal-use-only) UsingTestingNetworkDefaults option to start with a triple-underscore so the controller won't touch it. Patch by Meejah. Fixes bug 3155. Bugfix on 0.2.2.23-alpha. - Avoid segfault when starting up having run with an extremely old version of Tor and parsing its state file. Fixes bug 6801; bugfix on 0.2.2.23-alpha. - Rename the (testing-use-only) _UseFilteringSSLBufferevents option so it doesn't start with _. Fixes bug 3155. Bugfix on 0.2.3.1-alpha. - Don't follow the NULL pointer if microdescriptor generation fails. (This does not appear to be triggerable, but it's best to be safe.) Found by "f. tp.". Fixes bug 6797; bugfix on 0.2.4.1-alpha. - Fix mis-declared dependencies on src/common/crypto.c and src/or/tor_main.c that could break out-of-tree builds under some circumstances. Fixes bug 6778; bugfix on 0.2.4.1-alpha. - Avoid a warning when building common_sha1.i out of tree. Fixes bug 6778; bugfix on 0.2.4.1-alpha. - Fix a harmless (in this case) build warning for implicitly converting a strlen() to an int. Bugfix on 0.2.4.1-alpha. o Removed features: - Now that all versions before 0.2.2.x are disallowed, we no longer need to work around their missing features. Thus we can remove a bunch of compatibility code. o Code refactoring: - Tweak tor-fw-helper to accept an arbitrary amount of arbitrary TCP ports to forward. In the past it only accepted two ports: the ORPort and the DirPort. Changes in version 0.2.4.1-alpha - 2012-09-05 Tor 0.2.4.1-alpha lets bridges publish their pluggable transports to bridgedb; lets relays use IPv6 addresses and directory authorities advertise them; and switches to a cleaner build interface. This is the first alpha release in a new series, so expect there to be bugs. Users who would rather test out a more stable branch should stay with 0.2.3.x for now. o Major features (bridges): - Bridges now report the pluggable transports they support to the bridge authority, so it can pass the supported transports on to bridgedb and/or eventually do reachability testing. Implements ticket 3589. o Major features (IPv6): - Bridge authorities now accept IPv6 bridge addresses and include them in network status documents. Implements ticket 5534. - Clients who set "ClientUseIPv6 1" may connect to entry nodes over IPv6. Set "ClientPreferIPv6ORPort 1" to make this even more likely to happen. Implements ticket 5535. - All kind of relays, not just bridges, can now advertise an IPv6 OR port. Implements ticket 6362. - Directory authorities vote on IPv6 OR ports using the new consensus method 14. Implements ticket 6363. o Major features (build): - Switch to a nonrecursive Makefile structure. Now instead of each Makefile.am invoking other Makefile.am's, there is a master Makefile.am that includes the others. This change makes our build process slightly more maintainable, and improves parallelism for building with make -j. Original patch by Stewart Smith; various fixes by Jim Meyering. - Where available, we now use automake's "silent" make rules by default, so that warnings are easier to spot. You can get the old behavior with "make V=1". Patch by Stewart Smith for ticket 6522. o Minor features (code security and spec conformance): - Clear keys and key-derived material left on the stack in rendservice.c and rendclient.c. Check return value of crypto_pk_write_private_key_to_string() in end_service_load_keys(). These fixes should make us more forward-secure against cold-boot attacks and the like. Fixes bug 2385. - Reject EXTEND cells sent to nonexistent streams. According to the spec, an EXTEND cell sent to _any_ nonzero stream ID is invalid, but we were only checking for stream IDs that were currently in use. Found while hunting for more instances of bug 6271. Bugfix on 0.0.2pre8, which introduced incremental circuit construction. o Minor features (streamlining); - No longer include the "opt" prefix when generating routerinfos or v2 directories: it has been needless since Tor 0.1.2. Closes ticket 5124. - Remove some now-needless code that tried to aggressively flush OR connections as data was added to them. Since 0.2.0.1-alpha, our cell queue logic has saved us from the failure mode that this code was supposed to prevent. Removing this code will limit the number of baroque control flow paths through Tor's network logic. Reported pseudonymously on IRC. Fixes bug 6468; bugfix on 0.2.0.1-alpha. o Minor features (controller): - Add a "GETINFO signal/names" control port command. Implements ticket 3842. - Provide default values for all options via "GETINFO config/defaults". Implements ticket 4971. o Minor features (IPv6): - New config option "AuthDirHasIPv6Connectivity 1" that directory authorities should set if they have IPv6 connectivity and want to do reachability tests for IPv6 relays. Implements feature 5974. - A relay with an IPv6 OR port now sends that address in NETINFO cells (in addition to its other address). Implements ticket 6364. o Minor features (log messages): - Omit the first heartbeat log message, because it never has anything useful to say, and it clutters up the bootstrapping messages. Resolves ticket 6758. - Don't log about reloading the microdescriptor cache at startup. Our bootstrap warnings are supposed to tell the user when there's a problem, and our bootstrap notices say when there isn't. Resolves ticket 6759; bugfix on 0.2.2.6-alpha. - Don't log "I learned some more directory information" when we're reading cached directory information. Reserve it for when new directory information arrives in response to a fetch. Resolves ticket 6760. - Prevent rounding error in path bias counts when scaling them down, and use the correct scale factor default. Also demote some path bias related log messages down a level and make others less scary sounding. Fixes bug 6647. Bugfix against 0.2.3.17-beta. - We no longer warn so much when generating manpages from their asciidoc source. o Code simplifications and refactoring: - Enhance our internal sscanf replacement so that we can eliminate the last remaining uses of the system sscanf. (Though those uses of sscanf were safe, sscanf itself is generally error prone, so we want to eliminate when we can.) Fixes ticket 4195 and Coverity CID 448. - Move ipv6_preferred from routerinfo_t to node_t. Addresses bug 4620. - Move last_reachable and testing_since from routerinfo_t to node_t. Implements ticket 5529. - Add replaycache_t structure, functions and unit tests, then refactor rend_service_introduce() to be more clear to read, improve, debug, and test. Resolves bug 6177. - Finally remove support for malloc_good_size and malloc_usable_size. We had hoped that these functions would let us eke a little more memory out of our malloc implementation. Unfortunately, the only implementations that provided these functions are also ones that are already efficient about not overallocation: they never got us more than 7 or so bytes per allocation. Removing them saves us a little code complexity and a nontrivial amount of build complexity. o New requirements: - Tor maintainers now require Automake version 1.9 or later to build Tor from the Git repository. (Automake is not required when building from a source distribution.) Changes in version 0.2.3.21-rc - 2012-09-05 Tor 0.2.3.21-rc is the fourth release candidate for the Tor 0.2.3.x series. It fixes a trio of potential security bugs, fixes a bug where we were leaving some of the fast relays out of the microdescriptor consensus, resumes interpreting "ORPort 0" and "DirPort 0" correctly, and cleans up other smaller issues. o Major bugfixes (security): - Tear down the circuit if we get an unexpected SENDME cell. Clients could use this trick to make their circuits receive cells faster than our flow control would have allowed, or to gum up the network, or possibly to do targeted memory denial-of-service attacks on entry nodes. Fixes bug 6252. Bugfix on the 54th commit on Tor -- from July 2002, before the release of Tor 0.0.0. We had committed this patch previously, but we had to revert it because of bug 6271. Now that 6271 is fixed, this patch appears to work. - Reject any attempt to extend to an internal address. Without this fix, a router could be used to probe addresses on an internal network to see whether they were accepting connections. Fixes bug 6710; bugfix on 0.0.8pre1. - Do not crash when comparing an address with port value 0 to an address policy. This bug could have been used to cause a remote assertion failure by or against directory authorities, or to allow some applications to crash clients. Fixes bug 6690; bugfix on 0.2.1.10-alpha. o Major bugfixes: - Remove the upper bound on microdescriptor length. We were hitting the limit for routers with complex exit policies or family declarations, causing clients to not use them. Fixes the first piece of bug 6404; fix on 0.2.2.6-alpha. - Detect "ORPort 0" as meaning, uniformly, that we're not running as a relay. Previously, some of our code would treat the presence of any ORPort line as meaning that we should act like a relay, even though our new listener code would correctly not open any ORPorts for ORPort 0. Similar bugs in other Port options are also fixed. Fixes the first half of bug 6507; bugfix on 0.2.3.3-alpha. o Minor bugfixes: - Avoid a pair of double-free and use-after-mark bugs that can occur with certain timings in canceled and re-received DNS requests. Fixes bug 6472; bugfix on 0.0.7rc1. - Fix build and 64-bit compile warnings from --enable-openbsd-malloc. Fixes bug 6379. Bugfix on 0.2.0.20-rc. - Allow one-hop directory fetching circuits the full "circuit build timeout" period, rather than just half of it, before failing them and marking the relay down. This fix should help reduce cases where clients declare relays (or worse, bridges) unreachable because the TLS handshake takes a few seconds to complete. Fixes bug 6743; bugfix on 0.2.2.2-alpha, where we changed the timeout from a static 30 seconds. - Authorities no longer include any router in their microdescriptor consensuses for which they couldn't generate or agree on a microdescriptor. Fixes the second piece of bug 6404; fix on 0.2.2.6-alpha. - Detect and reject attempts to specify both "FooPort" and "FooPort 0" in the same configuration domain. (It's still okay to have a FooPort in your configuration file, and use "FooPort 0" on the command line to disable it.) Fixes the second half of bug 6507; bugfix on 0.2.3.3-alpha. - Make wildcarded addresses (that is, ones beginning with "*.") work when provided via the controller's MapAddress command. Previously, they were accepted, but we never actually noticed that they were wildcards. Fixes bug 6244; bugfix on 0.2.3.9-alpha. - Avoid crashing on a malformed state file where EntryGuardPathBias precedes EntryGuard. Fix for bug 6774; bugfix on 0.2.3.17-beta. - Add a (probably redundant) memory clear between iterations of the router status voting loop, to prevent future coding errors where data might leak between iterations of the loop. Resolves ticket 6514. o Minor bugfixes (log messages): - Downgrade "set buildtimeout to low value" messages to "info" severity; they were never an actual problem, there was never anything reasonable to do about them, and they tended to spam logs from time to time. Fixes bug 6251; bugfix on 0.2.2.2-alpha. - Downgrade path-bias warning messages to "info". We'll try to get them working better in 0.2.4. Add internal circuit construction state to protect against the noisy warn message "Unexpectedly high circuit_successes". Also add some additional rate-limited notice messages to help determine the root cause of the warn. Fixes bug 6475. Bugfix against 0.2.3.17-beta. - Move log message when unable to find a microdesc in a routerstatus entry to parse time. Previously we'd spam this warning every time we tried to figure out which microdescriptors to download. Fixes the third piece of bug 6404; fix on 0.2.3.18-rc. o Minor features: - Consider new, removed or changed IPv6 OR ports a non-cosmetic change when the authority is deciding whether to accept a newly uploaded descriptor. Implements ticket 6423. - Add missing documentation for consensus and microdesc files. Resolves ticket 6732. Changes in version 0.2.2.38 - 2012-08-12 Tor 0.2.2.38 fixes a remotely triggerable crash bug, and fixes a timing attack that could in theory leak path information. o Security fixes: - Avoid an uninitialized memory read when reading a vote or consensus document that has an unrecognized flavor name. This read could lead to a remote crash bug. Fixes bug 6530; bugfix on 0.2.2.6-alpha. - Try to leak less information about what relays a client is choosing to a side-channel attacker. Previously, a Tor client would stop iterating through the list of available relays as soon as it had chosen one, thus finishing a little earlier when it picked a router earlier in the list. If an attacker can recover this timing information (nontrivial but not proven to be impossible), they could learn some coarse-grained information about which relays a client was picking (middle nodes in particular are likelier to be affected than exits). The timing attack might be mitigated by other factors (see bug 6537 for some discussion), but it's best not to take chances. Fixes bug 6537; bugfix on 0.0.8rc1. Changes in version 0.2.3.20-rc - 2012-08-05 Tor 0.2.3.20-rc is the third release candidate for the Tor 0.2.3.x series. It fixes a pair of code security bugs and a potential anonymity issue, updates our RPM spec files, and cleans up other smaller issues. o Security fixes: - Avoid read-from-freed-memory and double-free bugs that could occur when a DNS request fails while launching it. Fixes bug 6480; bugfix on 0.2.0.1-alpha. - Avoid an uninitialized memory read when reading a vote or consensus document that has an unrecognized flavor name. This read could lead to a remote crash bug. Fixes bug 6530; bugfix on 0.2.2.6-alpha. - Try to leak less information about what relays a client is choosing to a side-channel attacker. Previously, a Tor client would stop iterating through the list of available relays as soon as it had chosen one, thus finishing a little earlier when it picked a router earlier in the list. If an attacker can recover this timing information (nontrivial but not proven to be impossible), they could learn some coarse-grained information about which relays a client was picking (middle nodes in particular are likelier to be affected than exits). The timing attack might be mitigated by other factors (see bug 6537 for some discussion), but it's best not to take chances. Fixes bug 6537; bugfix on 0.0.8rc1. o Minor features: - Try to make the warning when giving an obsolete SOCKSListenAddress a little more useful. - Terminate active server managed proxies if Tor stops being a relay. Addresses parts of bug 6274; bugfix on 0.2.3.6-alpha. - Provide a better error message about possible OSX Asciidoc failure reasons. Fixes bug 6436. - Warn when Tor is configured to use accounting in a way that can link a hidden service to some other hidden service or public address. Resolves ticket 6490. o Minor bugfixes: - Check return value of fputs() when writing authority certificate file. Fixes Coverity issue 709056; bugfix on 0.2.0.1-alpha. - Ignore ServerTransportPlugin lines when Tor is not configured as a relay. Fixes bug 6274; bugfix on 0.2.3.6-alpha. - When disabling guards for having too high a proportion of failed circuits, make sure to look at each guard. Fixes bug 6397; bugfix on 0.2.3.17-beta. o Packaging (RPM): - Update our default RPM spec files to work with mock and rpmbuild on RHEL/Fedora. They have an updated set of dependencies and conflicts, a fix for an ancient typo when creating the "_tor" user, and better instructions. Thanks to Ondrej Mikle for the patch series. Fixes bug 6043. o Testing: - Make it possible to set the TestingTorNetwork configuration option using AlternateDirAuthority and AlternateBridgeAuthority as an alternative to setting DirServer. Addresses ticket 6377. o Documentation: - Clarify the documentation for the Alternate*Authority options. Fixes bug 6387. - Fix some typos in the manpages. Patch from A. Costa. Fixes bug 6500. o Code simplification and refactoring: - Do not use SMARTLIST_FOREACH for any loop whose body exceeds 10 lines. Also, don't nest them. Doing so in the past has led to hard-to-debug code. The new style is to use the SMARTLIST_FOREACH_{BEGIN,END} pair. Addresses issue 6400. Changes in version 0.2.3.19-rc - 2012-07-06 Tor 0.2.3.19-rc is the second release candidate for the Tor 0.2.3.x series. It fixes the compile on Windows, reverts to a GeoIP database that isn't as broken, and fixes a flow control bug that has been around since the beginning of Tor. o Major bugfixes: - Fix a bug handling SENDME cells on nonexistent streams that could result in bizarre window values. Report and patch contributed pseudonymously. Fixes part of bug 6271. This bug was introduced before the first Tor release, in svn commit r152. - Revert to the May 1 2012 Maxmind GeoLite Country database. In the June 2012 database, Maxmind marked many Tor relays as country "A1", which will cause risky behavior for clients that set EntryNodes or ExitNodes. Addresses bug 6334; bugfix on 0.2.3.17-beta. - Instead of ENOBUFS on Windows, say WSAENOBUFS. Fixes compilation on Windows. Fixes bug 6296; bugfix on 0.2.3.18-rc. o Minor bugfixes: - Fix wrong TCP port range in parse_port_range(). Fixes bug 6218; bugfix on 0.2.1.10-alpha. Changes in version 0.2.3.18-rc - 2012-06-28 Tor 0.2.3.18-rc is the first release candidate for the Tor 0.2.3.x series. It fixes a few smaller bugs, but generally appears stable. Please test it and let us know whether it is! o Major bugfixes: - Allow wildcarded mapaddress targets to be specified on the controlport. Partially fixes bug 6244; bugfix on 0.2.3.9-alpha. - Make our linker option detection code more robust against linkers such as on FreeBSD 8, where a bad combination of options completes successfully but makes an unrunnable binary. Fixes bug 6173; bugfix on 0.2.3.17-beta. o Minor bugfixes (on 0.2.2.x and earlier): - Avoid a false positive in the util/threads unit test by increasing the maximum timeout time. Fixes bug 6227; bugfix on 0.2.0.4-alpha. - Replace "Sending publish request" log messages with "Launching upload", so that they no longer confusingly imply that we're sending something to a directory we might not even be connected to yet. Fixes bug 3311; bugfix on 0.2.0.10-alpha. - Make sure to set *socket_error in all error cases in connection_connect(), so it can't produce a warning about errno being zero from errno_to_orconn_end_reason(). Bugfix on 0.2.1.1-alpha; resolves ticket 6028. - Downgrade "Got a certificate, but we already have it" log messages from warning to info, except when we're a dirauth. Fixes bug 5238; bugfix on 0.2.1.7-alpha. - When checking for requested signatures on the latest consensus before serving it to a client, make sure to check the right consensus flavor. Bugfix on 0.2.2.6-alpha. - Downgrade "eventdns rejected address" message to LOG_PROTOCOL_WARN. Fixes bug 5932; bugfix on 0.2.2.7-alpha. o Minor bugfixes (on 0.2.3.x): - Make format_helper_exit_status() avoid unnecessary space padding and stop confusing log_from_pipe(). Fixes ticket 5557; bugfix on 0.2.3.1-alpha. - Downgrade a message about cleaning the microdescriptor cache to "info" from "notice". Fixes bug 6238; bugfix on 0.2.3.1-alpha. - Log a BUG message at severity INFO if we have a networkstatus with a missing entry for some microdescriptor. Continues on a patch to 0.2.3.2-alpha. - Improve the log message when a managed proxy fails to launch. Fixes bug 5099; bugfix on 0.2.3.6-alpha. - Don't do DNS lookups when parsing corrupted managed proxy protocol messages. Fixes bug 6226; bugfix on 0.2.3.6-alpha. - When formatting wildcarded address mappings for the controller, be sure to include "*." as appropriate. Partially fixes bug 6244; bugfix on 0.2.3.9-alpha. - Avoid a warning caused by using strcspn() from glibc with clang 3.0. Bugfix on 0.2.3.13-alpha. - Stop logging messages about running with circuit timeout learning enabled at severity LD_BUG. Fixes bug 6169; bugfix on 0.2.3.17-beta. - Disable a spurious warning about reading on a marked and flushing connection. We shouldn't be doing that, but apparently we sometimes do. Fixes bug 6203; bugfix on 0.2.3.17-beta. - Fix a bug that stopped AllowDotExit from working on addresses that had an entry in the DNS cache. Fixes bug 6211; bugfix on 0.2.3.17-beta. o Code simplification, refactoring, unit tests: - Move tor_gettimeofday_cached() into compat_libevent.c, and use Libevent's notion of cached time when possible. - Remove duplicate code for invoking getrlimit() from control.c. - Add a unit test for the environment_variable_names_equal function. o Documentation: - Document the --defaults-torrc option, and the new (in 0.2.3) semantics for overriding, extending, and clearing lists of options. Closes bug 4748. Changes in version 0.2.3.17-beta - 2012-06-15 Tor 0.2.3.17-beta enables compiler and linker hardening by default, gets our TLS handshake back on track for being able to blend in with Firefox, fixes a big bug in 0.2.3.16-alpha that broke Tor's interaction with Vidalia, and otherwise continues to get us closer to a release candidate. o Major features: - Enable gcc and ld hardening by default. Resolves ticket 5210. - Update TLS cipher list to match Firefox 8 and later. Resolves ticket 4744. - Implement the client side of proposal 198: remove support for clients falsely claiming to support standard ciphersuites that they can actually provide. As of modern OpenSSL versions, it's not necessary to fake any standard ciphersuite, and doing so prevents us from using better ciphersuites in the future, since servers can't know whether an advertised ciphersuite is really supported or not. Some hosts -- notably, ones with very old versions of OpenSSL or where OpenSSL has been built with ECC disabled -- will stand out because of this change; TBB users should not be affected. o Major bugfixes: - Change the default value for DynamicDHGroups (introduced in 0.2.3.9-alpha) to 0. This feature can make Tor relays less identifiable by their use of the mod_ssl DH group, but at the cost of some usability (#4721) and bridge tracing (#6087) regressions. Resolves ticket 5598. - Send a CRLF at the end of each STATUS_* control protocol event. This bug tickled a bug in Vidalia which would make it freeze. Fixes bug 6094; bugfix on 0.2.3.16-alpha. o Minor bugfixes: - Disable writing on marked-for-close connections when they are blocked on bandwidth, to prevent busy-looping in Libevent. Fixes bug 5263; bugfix on 0.0.2pre13, where we first added a special case for flushing marked connections. - Detect SSL handshake even when the initial attempt to write the server hello fails. Fixes bug 4592; bugfix on 0.2.0.13-alpha. - Change the AllowDotExit rules so they should actually work. We now enforce AllowDotExit only immediately after receiving an address via SOCKS or DNSPort: other sources are free to provide .exit addresses after the resolution occurs. Fixes bug 3940; bugfix on 0.2.2.1-alpha. - Fix a (harmless) integer overflow in cell statistics reported by some fast relays. Fixes bug 5849; bugfix on 0.2.2.1-alpha. - Make sure circuitbuild.c checks LearnCircuitBuildTimeout in all the right places and never depends on the consensus parameters or computes adaptive timeouts when it is disabled. Fixes bug 5049; bugfix on 0.2.2.14-alpha. - When building Tor on Windows with -DUNICODE (not default), ensure that error messages, filenames, and DNS server names are always NUL-terminated when we convert them to a single-byte encoding. Fixes bug 5909; bugfix on 0.2.2.16-alpha. - Make Tor build correctly again with -DUNICODE -D_UNICODE defined. Fixes bug 6097; bugfix on 0.2.2.16-alpha. - Fix an edge case where TestingTorNetwork is set but the authorities and relays all have an uptime of zero, where the private Tor network could briefly lack support for hidden services. Fixes bug 3886; bugfix on 0.2.2.18-alpha. - Correct the manpage's descriptions for the default values of DirReqStatistics and ExtraInfoStatistics. Fixes bug 2865; bugfix on 0.2.3.1-alpha. - Fix the documentation for the --hush and --quiet command line options, which changed their behavior back in 0.2.3.3-alpha. - Fix compilation warning with clang 3.1. Fixes bug 6141; bugfix on 0.2.3.11-alpha. o Minor features: - Rate-limit the "Weighted bandwidth is 0.000000" message, and add more information to it, so that we can track it down in case it returns again. Mitigates bug 5235. - Check CircuitBuildTimeout and LearnCircuitBuildTimeout in options_validate(); warn if LearnCircuitBuildTimeout is disabled and CircuitBuildTimeout is set unreasonably low. Resolves ticket 5452. - Warn the user when HTTPProxy, but no other proxy type, is configured. This can cause surprising behavior: it doesn't send all of Tor's traffic over the HTTPProxy -- it sends unencrypted directory traffic only. Resolves ticket 4663. - Issue a notice if a guard completes less than 40% of your circuits. Threshold is configurable by torrc option PathBiasNoticeRate and consensus parameter pb_noticepct. There is additional, off-by- default code to disable guards which fail too many circuits. Addresses ticket 5458. - Update to the June 6 2012 Maxmind GeoLite Country database. o Code simplifications and refactoring: - Remove validate_pluggable_transports_config(): its warning message is now handled by connection_or_connect(). Changes in version 0.2.2.37 - 2012-06-06 Tor 0.2.2.37 introduces a workaround for a critical renegotiation bug in OpenSSL 1.0.1 (where 20% of the Tor network can't talk to itself currently). o Major bugfixes: - Work around a bug in OpenSSL that broke renegotiation with TLS 1.1 and TLS 1.2. Without this workaround, all attempts to speak the v2 Tor connection protocol when both sides were using OpenSSL 1.0.1 would fail. Resolves ticket 6033. - When waiting for a client to renegotiate, don't allow it to add any bytes to the input buffer. This fixes a potential DoS issue. Fixes bugs 5934 and 6007; bugfix on 0.2.0.20-rc. - Fix an edge case where if we fetch or publish a hidden service descriptor, we might build a 4-hop circuit and then use that circuit for exiting afterwards -- even if the new last hop doesn't obey our ExitNodes config option. Fixes bug 5283; bugfix on 0.2.0.10-alpha. o Minor bugfixes: - Fix a build warning with Clang 3.1 related to our use of vasprintf. Fixes bug 5969. Bugfix on 0.2.2.11-alpha. o Minor features: - Tell GCC and Clang to check for any errors in format strings passed to the tor_v*(print|scan)f functions. Changes in version 0.2.3.16-alpha - 2012-06-05 Tor 0.2.3.16-alpha introduces a workaround for a critical renegotiation bug in OpenSSL 1.0.1 (where 20% of the Tor network can't talk to itself currently). It also fixes a variety of smaller bugs and other cleanups that get us closer to a release candidate. o Major bugfixes (general): - Work around a bug in OpenSSL that broke renegotiation with TLS 1.1 and TLS 1.2. Without this workaround, all attempts to speak the v2 Tor connection protocol when both sides were using OpenSSL 1.0.1 would fail. Resolves ticket 6033. - When waiting for a client to renegotiate, don't allow it to add any bytes to the input buffer. This fixes a potential DoS issue. Fixes bugs 5934 and 6007; bugfix on 0.2.0.20-rc. - Pass correct OR address to managed proxies (like obfsproxy), even when ORListenAddress is used. Fixes bug 4865; bugfix on 0.2.3.9-alpha. - The advertised platform of a router now includes only its operating system's name (e.g., "Linux", "Darwin", "Windows 7"), and not its service pack level (for Windows) or its CPU architecture (for Unix). We also no longer include the "git-XYZ" tag in the version. Resolves part of bug 2988. o Major bugfixes (clients): - If we are unable to find any exit that supports our predicted ports, stop calling them predicted, so that we don't loop and build hopeless circuits indefinitely. Fixes bug 3296; bugfix on 0.0.9pre6, which introduced predicted ports. - Fix an edge case where if we fetch or publish a hidden service descriptor, we might build a 4-hop circuit and then use that circuit for exiting afterwards -- even if the new last hop doesn't obey our ExitNodes config option. Fixes bug 5283; bugfix on 0.2.0.10-alpha. - Check at each new consensus whether our entry guards were picked long enough ago that we should rotate them. Previously, we only did this check at startup, which could lead to us holding a guard indefinitely. Fixes bug 5380; bugfix on 0.2.1.14-rc. - When fetching a bridge descriptor from a bridge authority, always do so anonymously, whether we have been able to open circuits or not. Partial fix for bug 1938; bugfix on 0.2.0.7-alpha. This behavior makes it *safer* to use UpdateBridgesFromAuthority, but we'll need to wait for bug 6010 before it's actually usable. o Major bugfixes (directory authorities): - When computing weight parameters, behave more robustly in the presence of a bad bwweightscale value. Previously, the authorities would crash if they agreed on a sufficiently broken weight_scale value: now, they use a reasonable default and carry on. Partial fix for 5786; bugfix on 0.2.2.17-alpha. - Check more thoroughly to prevent a rogue authority from double-voting on any consensus directory parameter. Previously, authorities would crash in this case if the total number of votes for any parameter exceeded the number of active voters, but would let it pass otherwise. Partial fix for bug 5786; bugfix on 0.2.2.2-alpha. o Minor features: - Rate-limit log messages when asked to connect anonymously to a private address. When these hit, they tended to hit fast and often. Also, don't bother trying to connect to addresses that we are sure will resolve to 127.0.0.1: getting 127.0.0.1 in a directory reply makes us think we have been lied to, even when the address the client tried to connect to was "localhost." Resolves ticket 2822. - Allow packagers to insert an extra string in server descriptor platform lines by setting the preprocessor variable TOR_BUILD_TAG. Resolves the rest of ticket 2988. - Raise the threshold of server descriptors needed (75%) and exit server descriptors needed (50%) before we will declare ourselves bootstrapped. This will make clients start building circuits a little later, but makes the initially constructed circuits less skewed and less in conflict with further directory fetches. Fixes ticket 3196. - Close any connection that sends unrecognized junk before the handshake. Solves an issue noted in bug 4369. - Improve log messages about managed transports. Resolves ticket 5070. - Tag a bridge's descriptor as "never to be sent unencrypted". This shouldn't matter, since bridges don't open non-anonymous connections to the bridge authority and don't allow unencrypted directory connections from clients, but we might as well make sure. Closes bug 5139. - Expose our view of whether we have gone dormant to the controller, via a new "GETINFO dormant" value. Torbutton and other controllers can use this to avoid doing periodic requests through Tor while it's dormant (bug 4718). Fixes bug 5954. - Tell GCC and Clang to check for any errors in format strings passed to the tor_v*(print|scan)f functions. - Update to the May 1 2012 Maxmind GeoLite Country database. o Minor bugfixes (already included in 0.2.2.36): - Reject out-of-range times like 23:59:61 in parse_rfc1123_time(). Fixes bug 5346; bugfix on 0.0.8pre3. - Correct parsing of certain date types in parse_http_time(). Without this patch, If-Modified-Since would behave incorrectly. Fixes bug 5346; bugfix on 0.2.0.2-alpha. Patch from Esteban Manchado Velázques. - Make our number-parsing functions always treat too-large values as an error, even when those values exceed the width of the underlying type. Previously, if the caller provided these functions with minima or maxima set to the extreme values of the underlying integer type, these functions would return those values on overflow rather than treating overflow as an error. Fixes part of bug 5786; bugfix on 0.0.9. - If we hit the error case where routerlist_insert() replaces an existing (old) server descriptor, make sure to remove that server descriptor from the old_routers list. Fix related to bug 1776. Bugfix on 0.2.2.18-alpha. - Clarify the behavior of MaxCircuitDirtiness with hidden service circuits. Fixes issue 5259. o Minor bugfixes (coding cleanup, on 0.2.2.x and earlier): - Prevent a null-pointer dereference when receiving a data cell for a nonexistent stream when the circuit in question has an empty deliver window. We don't believe this is triggerable, since we don't currently allow deliver windows to become empty, but the logic is tricky enough that it's better to make the code robust. Fixes bug 5541; bugfix on 0.0.2pre14. - Fix a memory leak when trying to launch a DNS request when the network is disabled or the nameservers are unconfigurable. Fixes bug 5916; bugfix on Tor 0.1.2.1-alpha (for the unconfigurable nameserver case) and on 0.2.3.9-alpha (for the DisableNetwork case). - Don't hold a Windows file handle open for every file mapping; the file mapping handle is sufficient. Fixes bug 5951; bugfix on 0.1.2.1-alpha. - Avoid O(n^2) performance characteristics when parsing a large extrainfo cache. Fixes bug 5828; bugfix on 0.2.0.1-alpha. - Format more doubles with %f, not %lf. Patch from grarpamp to make Tor build correctly on older BSDs again. Fixes bug 3894; bugfix on Tor 0.2.0.8-alpha. - Make our replacement implementation of strtok_r() compatible with the standard behavior of strtok_r(). Patch by nils. Fixes bug 5091; bugfix on 0.2.2.1-alpha. - Fix a NULL-pointer dereference on a badly formed SETCIRCUITPURPOSE command. Found by mikeyc. Fixes bug 5796; bugfix on 0.2.2.9-alpha. - Fix a build warning with Clang 3.1 related to our use of vasprintf. Fixes bug 5969. Bugfix on 0.2.2.11-alpha. - Defensively refactor rend_mid_rendezvous() so that protocol violations and length checks happen in the beginning. Fixes bug 5645. - Set _WIN32_WINNT to 0x0501 consistently throughout the code, so that IPv6 stuff will compile on MSVC, and compilation issues will be easier to track down. Fixes bug 5861. o Minor bugfixes (correctness, on 0.2.2.x and earlier): - Exit nodes now correctly report EADDRINUSE and EADDRNOTAVAIL as resource exhaustion, so that clients can adjust their load to try other exits. Fixes bug 4710; bugfix on 0.1.0.1-rc, which started using END_STREAM_REASON_RESOURCELIMIT. - Don't check for whether the address we're using for outbound connections has changed until after the outbound connection has completed. On Windows, getsockname() doesn't succeed until the connection is finished. Fixes bug 5374; bugfix on 0.1.1.14-alpha. - If the configuration tries to set MyFamily on a bridge, refuse to do so, and warn about the security implications. Fixes bug 4657; bugfix on 0.2.0.3-alpha. - If the client fails to set a reasonable set of ciphersuites during its v2 handshake renegotiation, allow the renegotiation to continue nevertheless (i.e. send all the required certificates). Fixes bug 4591; bugfix on 0.2.0.20-rc. - When we receive a SIGHUP and the controller __ReloadTorrcOnSIGHUP option is set to 0 (which Vidalia version 0.2.16 now does when a SAVECONF attempt fails), perform other actions that SIGHUP usually causes (like reopening the logs). Fixes bug 5095; bugfix on 0.2.1.9-alpha. - If we fail to write a microdescriptor to the disk cache, do not continue replacing the old microdescriptor file. Fixes bug 2954; bugfix on 0.2.2.6-alpha. - Exit nodes don't need to fetch certificates for authorities that they don't recognize; only directory authorities, bridges, and caches need to do that. Fixes part of bug 2297; bugfix on 0.2.2.11-alpha. - Correctly handle checking the permissions on the parent directory of a control socket in the root directory. Bug found by Esteban Manchado Velázquez. Fixes bug 5089; bugfix on Tor 0.2.2.26-beta. - When told to add a bridge with the same digest as a preexisting bridge but a different addr:port, change the addr:port as requested. Previously we would not notice the change. Fixes half of bug 5603; fix on 0.2.2.26-beta. - End AUTHCHALLENGE error messages (in the control protocol) with a CRLF. Fixes bug 5760; bugfix on 0.2.2.36 and 0.2.3.13-alpha. o Minor bugfixes (on 0.2.3.x): - Turn an assertion (that the number of handshakes received as a server is not < 1) into a warning. Fixes bug 4873; bugfix on 0.2.3.1-alpha. - Format IPv4 addresses correctly in ADDRMAP events. (Previously, we had reversed them when the answer was cached.) Fixes bug 5723; bugfix on 0.2.3.1-alpha. - Work correctly on Linux systems with accept4 support advertised in their headers, but without accept4 support in the kernel. Fix by murb. Fixes bug 5762; bugfix on 0.2.3.1-alpha. - When told to add a bridge with the same addr:port as a preexisting bridge but a different transport, change the transport as requested. Previously we would not notice the change. Fixes half of bug 5603; fix on 0.2.3.2-alpha. - Avoid a "double-reply" warning when replying to a SOCKS request with a parse error. Patch from Fabian Keil. Fixes bug 4108; bugfix on 0.2.3.4-alpha. - Fix a bug where a bridge authority crashes if it has seen no directory requests when it's time to write statistics to disk. Fixes bug 5891; bugfix on 0.2.3.6-alpha. Also fixes bug 5508 in a better way. - Don't try to open non-control listeners when DisableNetwork is set. Previously, we'd open all listeners, then immediately close them. Fixes bug 5604; bugfix on 0.2.3.9-alpha. - Don't abort the managed proxy protocol if the managed proxy sends us an unrecognized line; ignore it instead. Fixes bug 5910; bugfix on 0.2.3.9-alpha. - Fix a compile warning in crypto.c when compiling with clang 3.1. Fixes bug 5969, bugfix on 0.2.3.9-alpha. - Fix a compilation issue on GNU Hurd, which doesn't have PATH_MAX. Fixes bug 5355; bugfix on 0.2.3.11-alpha. - Remove bogus definition of "_WIN32" from src/win32/orconfig.h, to unbreak the MSVC build. Fixes bug 5858; bugfix on 0.2.3.12-alpha. - Resolve numerous small warnings and build issues with MSVC. Resolves bug 5859. o Documentation fixes: - Improve the manual's documentation for the NT Service command-line options. Addresses ticket 3964. - Clarify SessionGroup documentation slightly; resolves ticket 5437. - Document the changes to the ORPort and DirPort options, and the fact that {OR/Dir}ListenAddress is now unnecessary (and therefore deprecated). Resolves ticket 5597. o Removed files: - Remove the torrc.bridge file: we don't use it for anything, and it had become badly desynchronized from torrc.sample. Resolves bug 5622. Changes in version 0.2.2.36 - 2012-05-24 Tor 0.2.2.36 updates the addresses for two of the eight directory authorities, fixes some potential anonymity and security issues, and fixes several crash bugs. Tor 0.2.1.x has reached its end-of-life. Those Tor versions have many known flaws, and nobody should be using them. You should upgrade. If you're using a Linux or BSD and its packages are obsolete, stop using those packages and upgrade anyway. o Directory authority changes: - Change IP address for maatuska (v3 directory authority). - Change IP address for ides (v3 directory authority), and rename it to turtles. o Security fixes: - When building or running with any version of OpenSSL earlier than 0.9.8s or 1.0.0f, disable SSLv3 support. These OpenSSL versions have a bug (CVE-2011-4576) in which their block cipher padding includes uninitialized data, potentially leaking sensitive information to any peer with whom they make a SSLv3 connection. Tor does not use SSL v3 by default, but a hostile client or server could force an SSLv3 connection in order to gain information that they shouldn't have been able to get. The best solution here is to upgrade to OpenSSL 0.9.8s or 1.0.0f (or later). But when building or running with a non-upgraded OpenSSL, we disable SSLv3 entirely to make sure that the bug can't happen. - Never use a bridge or a controller-supplied node as an exit, even if its exit policy allows it. Found by wanoskarnet. Fixes bug 5342. Bugfix on 0.1.1.15-rc (for controller-purpose descriptors) and 0.2.0.3-alpha (for bridge-purpose descriptors). - Only build circuits if we have a sufficient threshold of the total descriptors that are marked in the consensus with the "Exit" flag. This mitigates an attack proposed by wanoskarnet, in which all of a client's bridges collude to restrict the exit nodes that the client knows about. Fixes bug 5343. - Provide controllers with a safer way to implement the cookie authentication mechanism. With the old method, if another locally running program could convince a controller that it was the Tor process, then that program could trick the controller into telling it the contents of an arbitrary 32-byte file. The new "SAFECOOKIE" authentication method uses a challenge-response approach to prevent this attack. Fixes bug 5185; implements proposal 193. o Major bugfixes: - Avoid logging uninitialized data when unable to decode a hidden service descriptor cookie. Fixes bug 5647; bugfix on 0.2.1.5-alpha. - Avoid a client-side assertion failure when receiving an INTRODUCE2 cell on a general purpose circuit. Fixes bug 5644; bugfix on 0.2.1.6-alpha. - Fix builds when the path to sed, openssl, or sha1sum contains spaces, which is pretty common on Windows. Fixes bug 5065; bugfix on 0.2.2.1-alpha. - Correct our replacements for the timeradd() and timersub() functions on platforms that lack them (for example, Windows). The timersub() function is used when expiring circuits, while timeradd() is currently unused. Bug report and patch by Vektor. Fixes bug 4778; bugfix on 0.2.2.24-alpha. - Fix the SOCKET_OK test that we use to tell when socket creation fails so that it works on Win64. Fixes part of bug 4533; bugfix on 0.2.2.29-beta. Bug found by wanoskarnet. o Minor bugfixes: - Reject out-of-range times like 23:59:61 in parse_rfc1123_time(). Fixes bug 5346; bugfix on 0.0.8pre3. - Make our number-parsing functions always treat too-large values as an error, even when those values exceed the width of the underlying type. Previously, if the caller provided these functions with minima or maxima set to the extreme values of the underlying integer type, these functions would return those values on overflow rather than treating overflow as an error. Fixes part of bug 5786; bugfix on 0.0.9. - Older Linux kernels erroneously respond to strange nmap behavior by having accept() return successfully with a zero-length socket. When this happens, just close the connection. Previously, we would try harder to learn the remote address: but there was no such remote address to learn, and our method for trying to learn it was incorrect. Fixes bugs 1240, 4745, and 4747. Bugfix on 0.1.0.3-rc. Reported and diagnosed by "r1eo". - Correct parsing of certain date types in parse_http_time(). Without this patch, If-Modified-Since would behave incorrectly. Fixes bug 5346; bugfix on 0.2.0.2-alpha. Patch from Esteban Manchado Velázques. - Change the BridgePassword feature (part of the "bridge community" design, which is not yet implemented) to use a time-independent comparison. The old behavior might have allowed an adversary to use timing to guess the BridgePassword value. Fixes bug 5543; bugfix on 0.2.0.14-alpha. - Detect and reject certain misformed escape sequences in configuration values. Previously, these values would cause us to crash if received in a torrc file or over an authenticated control port. Bug found by Esteban Manchado Velázquez, and independently by Robert Connolly from Matta Consulting who further noted that it allows a post-authentication heap overflow. Patch by Alexander Schrijver. Fixes bugs 5090 and 5402 (CVE 2012-1668); bugfix on 0.2.0.16-alpha. - Fix a compile warning when using the --enable-openbsd-malloc configure option. Fixes bug 5340; bugfix on 0.2.0.20-rc. - During configure, detect when we're building with clang version 3.0 or lower and disable the -Wnormalized=id and -Woverride-init CFLAGS. clang doesn't support them yet. - When sending an HTTP/1.1 proxy request, include a Host header. Fixes bug 5593; bugfix on 0.2.2.1-alpha. - Fix a NULL-pointer dereference on a badly formed SETCIRCUITPURPOSE command. Found by mikeyc. Fixes bug 5796; bugfix on 0.2.2.9-alpha. - If we hit the error case where routerlist_insert() replaces an existing (old) server descriptor, make sure to remove that server descriptor from the old_routers list. Fix related to bug 1776. Bugfix on 0.2.2.18-alpha. o Minor bugfixes (documentation and log messages): - Fix a typo in a log message in rend_service_rendezvous_has_opened(). Fixes bug 4856; bugfix on Tor 0.0.6. - Update "ClientOnly" man page entry to explain that there isn't really any point to messing with it. Resolves ticket 5005. - Document the GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays directory authority option (introduced in Tor 0.2.2.34). - Downgrade the "We're missing a certificate" message from notice to info: people kept mistaking it for a real problem, whereas it is seldom the problem even when we are failing to bootstrap. Fixes bug 5067; bugfix on 0.2.0.10-alpha. - Correctly spell "connect" in a log message on failure to create a controlsocket. Fixes bug 4803; bugfix on 0.2.2.26-beta. - Clarify the behavior of MaxCircuitDirtiness with hidden service circuits. Fixes issue 5259. o Minor features: - Directory authorities now reject versions of Tor older than 0.2.1.30, and Tor versions between 0.2.2.1-alpha and 0.2.2.20-alpha inclusive. These versions accounted for only a small fraction of the Tor network, and have numerous known security issues. Resolves issue 4788. - Update to the May 1 2012 Maxmind GeoLite Country database. - Feature removal: - When sending or relaying a RELAY_EARLY cell, we used to convert it to a RELAY cell if the connection was using the v1 link protocol. This was a workaround for older versions of Tor, which didn't handle RELAY_EARLY cells properly. Now that all supported versions can handle RELAY_EARLY cells, and now that we're enforcing the "no RELAY_EXTEND commands except in RELAY_EARLY cells" rule, remove this workaround. Addresses bug 4786. Changes in version 0.2.3.15-alpha - 2012-04-30 Tor 0.2.3.15-alpha fixes a variety of smaller bugs, including making the development branch build on Windows again. o Minor bugfixes (on 0.2.2.x and earlier): - Make sure that there are no unhandled pending TLS errors before reading from a TLS stream. We had checks in 0.1.0.3-rc, but lost them in 0.1.0.5-rc when we refactored read_to_buf_tls(). Bugfix on 0.1.0.5-rc; fixes bug 4528. - Fix an assert that directory authorities could trigger on sighup during some configuration state transitions. We now don't treat it as a fatal error when the new descriptor we just generated in init_keys() isn't accepted. Fixes bug 4438; bugfix on 0.2.1.9-alpha. - After we pick a directory mirror, we would refuse to use it if it's in our ExcludeExitNodes list, resulting in mysterious failures to bootstrap for people who just wanted to avoid exiting from certain locations. Fixes bug 5623; bugfix on 0.2.2.25-alpha. - When building with --enable-static-tor on OpenBSD, do not erroneously attempt to link -lrt. Fixes bug 5103. o Minor bugfixes (on 0.2.3.x): - When Tor is built with kernel headers from a recent (last few years) Linux kernel, do not fail to run on older (pre-2.6.28 Linux kernels). Fixes bug 5112; bugfix on 0.2.3.1-alpha. - Fix cross-compilation issues with mingw. Bugfixes on 0.2.3.6-alpha and 0.2.3.12-alpha. - Fix compilation with miniupnpc version 1.6; patch from Anthony G. Basile. Fixes bug 5434; bugfix on 0.2.3.12-alpha. - Fix compilation with MSVC, which had defined MS_WINDOWS. Bugfix on 0.2.3.13-alpha; found and fixed by Gisle Vanem. - Fix compilation on platforms without unistd.h, or where environ is defined in stdlib.h. Fixes bug 5704; bugfix on 0.2.3.13-alpha. o Minor features: - Directory authorities are now a little more lenient at accepting older router descriptors, or newer router descriptors that don't make big changes. This should help ameliorate past and future issues where routers think they have uploaded valid descriptors, but the authorities don't think so. Fix for ticket 2479. - Make the code that clients use to detect an address change be IPv6-aware, so that it won't fill clients' logs with error messages when trying to get the IPv4 address of an IPv6 connection. Implements ticket 5537. o Removed features: - Remove the GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays option; authorities needed to use it for a while to keep the network working as people upgraded to 0.2.1.31, 0.2.2.34, or 0.2.3.6-alpha, but that was six months ago. As of now, it should no longer be needed or used. Changes in version 0.2.3.14-alpha - 2012-04-23 Tor 0.2.3.14-alpha fixes yet more bugs to get us closer to a release candidate. It also dramatically speeds up AES: fast relays should consider switching to the newer OpenSSL library. o Directory authority changes: - Change IP address for ides (v3 directory authority), and rename it to turtles. o Major bugfixes: - Avoid logging uninitialized data when unable to decode a hidden service descriptor cookie. Fixes bug 5647; bugfix on 0.2.1.5-alpha. - Avoid a client-side assertion failure when receiving an INTRODUCE2 cell on a general purpose circuit. Fixes bug 5644; bugfix on 0.2.1.6-alpha. - If authorities are unable to get a v2 consensus document from other directory authorities, they no longer fall back to fetching them from regular directory caches. Fixes bug 5635; bugfix on 0.2.2.26-beta, where routers stopped downloading v2 consensus documents entirely. - When we start a Tor client with a normal consensus already cached, be willing to download a microdescriptor consensus. Fixes bug 4011; fix on 0.2.3.1-alpha. o Major features (performance): - When built to use OpenSSL 1.0.1, and built for an x86 or x86_64 instruction set, take advantage of OpenSSL's AESNI, bitsliced, or vectorized AES implementations as appropriate. These can be much, much faster than other AES implementations. o Minor bugfixes (0.2.2.x and earlier): - Don't launch more than 10 service-side introduction-point circuits for a hidden service in five minutes. Previously, we would consider launching more introduction-point circuits if at least one second had passed without any introduction-point circuits failing. Fixes bug 4607; bugfix on 0.0.7pre1. - Change the BridgePassword feature (part of the "bridge community" design, which is not yet implemented) to use a time-independent comparison. The old behavior might have allowed an adversary to use timing to guess the BridgePassword value. Fixes bug 5543; bugfix on 0.2.0.14-alpha. - Enforce correct return behavior of tor_vsscanf() when the '%%' pattern is used. Fixes bug 5558. Bugfix on 0.2.1.13. - When sending an HTTP/1.1 proxy request, include a Host header. Fixes bug 5593; bugfix on 0.2.2.1-alpha. - Don't log that we have "decided to publish new relay descriptor" unless we are actually publishing a descriptor. Fixes bug 3942; bugfix on 0.2.2.28-beta. o Minor bugfixes (0.2.3.x): - Fix a bug where a bridge authority crashes (on a failed assert) if it has seen no directory requests when it's time to write statistics to disk. Fixes bug 5508. Bugfix on 0.2.3.6-alpha. - Fix bug stomping on ORPort option NoListen and ignoring option NoAdvertise. Fixes bug 5151; bugfix on 0.2.3.9-alpha. - In the testsuite, provide a large enough buffer in the tor_sscanf unit test. Otherwise we'd overrun that buffer and crash during the unit tests. Found by weasel. Fixes bug 5449; bugfix on 0.2.3.12-alpha. - Make sure we create the keys directory if it doesn't exist and we're about to store the dynamic Diffie-Hellman parameters. Fixes bug 5572; bugfix on 0.2.3.13-alpha. - Fix a small memory leak when trying to decode incorrect base16 authenticator during SAFECOOKIE authentication. Found by Coverity Scan. Fixes CID 507. Bugfix on 0.2.3.13-alpha. o Minor features: - Add more information to a log statement that might help track down bug 4091. If you're seeing "Bug: tor_addr_is_internal() called with a non-IP address" messages (or any Bug messages, for that matter!), please let us know about it. - Relays now understand an IPv6 address when they get one from a directory server. Resolves ticket 4875. - Resolve IPv6 addresses in bridge and entry statistics to country code "??" which means we at least count them. Resolves ticket 5053; improves on 0.2.3.9-alpha. - Update to the April 3 2012 Maxmind GeoLite Country database. - Begin a doc/state-contents.txt file to explain the contents of the Tor state file. Fixes bug 2987. o Default torrc changes: - Stop listing "socksport 9050" in torrc.sample. We open a socks port on 9050 by default anyway, so this should not change anything in practice. - Stop mentioning the deprecated *ListenAddress options in torrc.sample. Fixes bug 5438. - Document unit of bandwidth related options in sample torrc. Fixes bug 5621. o Removed features: - The "torify" script no longer supports the "tsocks" socksifier tool, since tsocks doesn't support DNS and UDP right for Tor. Everyone should be using torsocks instead. Fixes bugs 3530 and 5180. Based on a patch by "ugh". o Code refactoring: - Change the symmetric cipher interface so that creating and initializing a stream cipher are no longer separate functions. - Remove all internal support for unpadded RSA. We never used it, and it would be a bad idea to start. Changes in version 0.2.3.13-alpha - 2012-03-26 Tor 0.2.3.13-alpha fixes a variety of stability and correctness bugs in managed pluggable transports, as well as providing other cleanups that get us closer to a release candidate. o Directory authority changes: - Change IP address for maatuska (v3 directory authority). o Security fixes: - Provide controllers with a safer way to implement the cookie authentication mechanism. With the old method, if another locally running program could convince a controller that it was the Tor process, then that program could trick the controller into telling it the contents of an arbitrary 32-byte file. The new "SAFECOOKIE" authentication method uses a challenge-response approach to prevent this attack. Fixes bug 5185, implements proposal 193. - Never use a bridge or a controller-supplied node as an exit, even if its exit policy allows it. Found by wanoskarnet. Fixes bug 5342. Bugfix on 0.1.1.15-rc (for controller-purpose descriptors) and 0.2.0.3-alpha (for bridge-purpose descriptors). - Only build circuits if we have a sufficient threshold of the total descriptors that are marked in the consensus with the "Exit" flag. This mitigates an attack proposed by wanoskarnet, in which all of a client's bridges collude to restrict the exit nodes that the client knows about. Fixes bug 5343. o Major bugfixes (on Tor 0.2.3.x): - Avoid an assert when managed proxies like obfsproxy are configured, and we receive HUP signals or setconf attempts too rapidly. This situation happens most commonly when Vidalia tries to attach to Tor or tries to configure the Tor it's attached to. Fixes bug 5084; bugfix on 0.2.3.6-alpha. - Fix a relay-side pluggable transports bug where managed proxies were unreachable from the Internet, because Tor asked them to bind on localhost. Fixes bug 4725; bugfix on 0.2.3.9-alpha. - Stop discarding command-line arguments when TestingTorNetwork is set. Discovered by Kevin Bauer. Fixes bug 5373; bugfix on 0.2.3.9-alpha, where task 4552 added support for two layers of torrc files. - Resume allowing the unit tests to run in gdb. This was accidentally made impossible when the DisableDebuggerAttachment option was introduced. Fixes bug 5448; bugfix on 0.2.3.9-alpha. - Resume building with nat-pmp support. Fixes bug 4955; bugfix on 0.2.3.11-alpha. Reported by Anthony G. Basile. o Minor bugfixes (on 0.2.2.x and earlier): - Ensure we don't cannibalize circuits that are longer than three hops already, so we don't end up making circuits with 5 or more hops. Patch contributed by wanoskarnet. Fixes bug 5231; bugfix on 0.1.0.1-rc which introduced cannibalization. - Detect and reject certain misformed escape sequences in configuration values. Previously, these values would cause us to crash if received in a torrc file or over an authenticated control port. Bug found by Esteban Manchado Velázquez, and independently by Robert Connolly from Matta Consulting who further noted that it allows a post-authentication heap overflow. Patch by Alexander Schrijver. Fixes bugs 5090 and 5402 (CVE 2012-1668); bugfix on 0.2.0.16-alpha. - Fix a compile warning when using the --enable-openbsd-malloc configure option. Fixes bug 5340; bugfix on 0.2.0.20-rc. - Directory caches no longer refuse to clean out descriptors because of missing v2 networkstatus documents, unless they're configured to retrieve v2 networkstatus documents. Fixes bug 4838; bugfix on 0.2.2.26-beta. Patch by Daniel Bryg. - Update to the latest version of the tinytest unit testing framework. This includes a couple of bugfixes that can be relevant for running forked unit tests on Windows, and removes all reserved identifiers. o Minor bugfixes (on 0.2.3.x): - On a failed pipe() call, don't leak file descriptors. Fixes bug 4296; bugfix on 0.2.3.1-alpha. - Spec conformance: on a v3 handshake, do not send a NETINFO cell until after we have received a CERTS cell. Fixes bug 4361; bugfix on 0.2.3.6-alpha. Patch by "frosty". - When binding to an IPv6 address, set the IPV6_V6ONLY socket option, so that the IP stack doesn't decide to use it for IPv4 too. Fixes bug 4760; bugfix on 0.2.3.9-alpha. - Ensure that variables set in Tor's environment cannot override environment variables that Tor passes to a managed pluggable-transport proxy. Previously, Tor would pass every variable in its environment to managed proxies along with the new ones, in such a way that on many operating systems, the inherited environment variables would override those which Tor tried to explicitly set. Bugfix on 0.2.3.12-alpha for most Unixoid systems; bugfix on 0.2.3.9-alpha for Windows. o Minor features: - A wide variety of new unit tests by Esteban Manchado Velázquez. - Shorten links in the tor-exit-notice file. Patch by Christian Kujau. - Update to the March 6 2012 Maxmind GeoLite Country database. Changes in version 0.2.3.12-alpha - 2012-02-13 Tor 0.2.3.12-alpha lets fast exit relays scale better, allows clients to use bridges that run Tor 0.2.2.x, and resolves several big bugs when Tor is configured to use a pluggable transport like obfsproxy. o Major bugfixes: - Fix builds when the path to sed, openssl, or sha1sum contains spaces, which is pretty common on Windows. Fixes bug 5065; bugfix on 0.2.2.1-alpha. - Set the SO_REUSEADDR socket option before we call bind() on outgoing connections. This change should allow busy exit relays to stop running out of available sockets as quickly. Fixes bug 4950; bugfix on 0.2.2.26-beta. - Allow 0.2.3.x clients to use 0.2.2.x bridges. Previously the client would ask the bridge for microdescriptors, which are only supported in 0.2.3.x, and then fail to bootstrap when it didn't get the answers it wanted. Fixes bug 4013; bugfix on 0.2.3.2-alpha. - Properly set up obfsproxy's environment when in managed mode. The Tor Browser Bundle needs LD_LIBRARY_PATH to be passed to obfsproxy, and when you run your Tor as a daemon, there's no HOME. Fixes bugs 5076 and 5082; bugfix on 0.2.3.6-alpha. o Minor features: - Use the dead_strip option when building Tor on OS X. This reduces binary size by almost 19% when linking openssl and libevent statically, which we do for Tor Browser Bundle. - Fix broken URLs in the sample torrc file, and tell readers about the OutboundBindAddress, ExitPolicyRejectPrivate, and PublishServerDescriptor options. Addresses bug 4652. - Update to the February 7 2012 Maxmind GeoLite Country database. o Minor bugfixes: - Downgrade the "We're missing a certificate" message from notice to info: people kept mistaking it for a real problem, whereas it is seldom the problem even when we are failing to bootstrap. Fixes bug 5067; bugfix on 0.2.0.10-alpha. - Don't put "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200" in a managed pluggable transport server proxy's environment. Previously, we would put it there, even though Tor doesn't implement an 'extended server port' yet, and even though Tor almost certainly isn't listening at that address. For now, we set it to an empty string to avoid crashing older obfsproxies. Bugfix on 0.2.3.6-alpha. - Log the heartbeat message every HeartbeatPeriod seconds, not every HeartbeatPeriod + 1 seconds. Fixes bug 4942; bugfix on 0.2.3.1-alpha. Bug reported by Scott Bennett. - Calculate absolute paths correctly on Windows. Fixes bug 4973; bugfix on 0.2.3.11-alpha. - Update "ClientOnly" man page entry to explain that there isn't really any point to messing with it. Resolves ticket 5005. - Use the correct CVE number for CVE-2011-4576 in our comments and log messages. Found by "fermenthor". Resolves bug 5066; bugfix on 0.2.3.11-alpha. o Code simplifications and refactoring: - Use the _WIN32 macro throughout our code to detect Windows. (Previously we had used the obsolete 'WIN32' and the idiosyncratic 'MS_WINDOWS'.) Changes in version 0.2.3.11-alpha - 2012-01-22 Tor 0.2.3.11-alpha marks feature-freeze for the 0.2.3 tree. It deploys the last step of the plan to limit maximum circuit length, includes a wide variety of hidden service performance and correctness fixes, works around an OpenSSL security flaw if your distro is too stubborn to upgrade, and fixes a bunch of smaller issues. o Major features: - Now that Tor 0.2.0.x is completely deprecated, enable the final part of "Proposal 110: Avoiding infinite length circuits" by refusing all circuit-extend requests that do not use a relay_early cell. This change helps Tor resist a class of denial-of-service attacks by limiting the maximum circuit length. - Adjust the number of introduction points that a hidden service will try to maintain based on how long its introduction points remain in use and how many introductions they handle. Fixes part of bug 3825. - Try to use system facilities for enumerating local interface addresses, before falling back to our old approach (which was binding a UDP socket, and calling getsockname() on it). That approach was scaring OS X users whose draconian firewall software warned about binding to UDP sockets, regardless of whether packets were sent. Now we try to use getifaddrs(), SIOCGIFCONF, or GetAdaptersAddresses(), depending on what the system supports. Resolves ticket 1827. o Major security workaround: - When building or running with any version of OpenSSL earlier than 0.9.8s or 1.0.0f, disable SSLv3 support. These OpenSSL versions have a bug (CVE-2011-4576) in which their block cipher padding includes uninitialized data, potentially leaking sensitive information to any peer with whom they make a SSLv3 connection. Tor does not use SSL v3 by default, but a hostile client or server could force an SSLv3 connection in order to gain information that they shouldn't have been able to get. The best solution here is to upgrade to OpenSSL 0.9.8s or 1.0.0f (or later). But when building or running with a non-upgraded OpenSSL, we disable SSLv3 entirely to make sure that the bug can't happen. o Major bugfixes: - Fix the SOCKET_OK test that we use to tell when socket creation fails so that it works on Win64. Fixes part of bug 4533; bugfix on 0.2.2.29-beta. Bug found by wanoskarnet. - Correct our replacements for the timeradd() and timersub() functions on platforms that lack them (for example, Windows). The timersub() function is used when expiring circuits, while timeradd() is currently unused. Bug report and patch by Vektor. Fixes bug 4778; bugfix on 0.2.2.24-alpha and 0.2.3.1-alpha. - Do not use OpenSSL 1.0.0's counter mode: it has a critical bug that was fixed in OpenSSL 1.0.0a. We test for the counter mode bug at runtime, not compile time, because some distributions hack their OpenSSL to mis-report its version. Fixes bug 4779; bugfix on 0.2.3.9-alpha. Found by Pascal. o Minor features (controller): - Use absolute path names when reporting the torrc filename in the control protocol, so a controller can more easily find the torrc file. Resolves bug 1101. - Extend the control protocol to report flags that control a circuit's path selection in CIRC events and in replies to 'GETINFO circuit-status'. Implements part of ticket 2411. - Extend the control protocol to report the hidden service address and current state of a hidden-service-related circuit in CIRC events and in replies to 'GETINFO circuit-status'. Implements part of ticket 2411. - When reporting the path to the cookie file to the controller, give an absolute path. Resolves ticket 4881. - Allow controllers to request an event notification whenever a circuit is cannibalized or its purpose is changed. Implements part of ticket 3457. - Include the creation time of a circuit in CIRC and CIRC2 control-port events and the list produced by the 'GETINFO circuit-status' control-port command. o Minor features (directory authorities): - Directory authorities now reject versions of Tor older than 0.2.1.30, and Tor versions between 0.2.2.1-alpha and 0.2.2.20-alpha inclusive. These versions accounted for only a small fraction of the Tor network, and have numerous known security issues. Resolves issue 4788. - Authority operators can now vote for all relays in a given set of countries to be BadDir/BadExit/Invalid/Rejected. - Provide two consensus parameters (FastFlagMinThreshold and FastFlagMaxThreshold) to control the range of allowable bandwidths for the Fast directory flag. These allow authorities to run experiments on appropriate requirements for being a "Fast" node. The AuthDirFastGuarantee config value still applies. Implements ticket 3946. - Document the GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays directory authority option (introduced in Tor 0.2.2.34). o Minor features (other): - Don't disable the DirPort when we cannot exceed our AccountingMax limit during this interval because the effective bandwidthrate is low enough. This is useful in a situation where AccountMax is only used as an additional safeguard or to provide statistics. - Prepend an informative header to generated dynamic_dh_params files. - If EntryNodes are given, but UseEntryGuards is set to 0, warn that EntryNodes will have no effect. Resolves issue 2571. - Log more useful messages when we fail to disable debugger attachment. - Log which authority we're missing votes from when we go to fetch them from the other auths. - Log (at debug level) whenever a circuit's purpose is changed. - Add missing documentation for the MaxClientCircuitsPending, UseMicrodescriptors, UserspaceIOCPBuffers, and _UseFilteringSSLBufferevents options, all introduced during the 0.2.3.x series. - Update to the January 3 2012 Maxmind GeoLite Country database. o Minor bugfixes (hidden services): - Don't close hidden service client circuits which have almost finished connecting to their destination when they reach the normal circuit-build timeout. Previously, we would close introduction circuits which are waiting for an acknowledgement from the introduction point, and rendezvous circuits which have been specified in an INTRODUCE1 cell sent to a hidden service, after the normal CBT. Now, we mark them as 'timed out', and launch another rendezvous attempt in parallel. This behavior change can be disabled using the new CloseHSClientCircuitsImmediatelyOnTimeout option. Fixes part of bug 1297; bugfix on 0.2.2.2-alpha. - Don't close hidden-service-side rendezvous circuits when they reach the normal circuit-build timeout. This behaviour change can be disabled using the new CloseHSServiceRendCircuitsImmediatelyOnTimeout option. Fixes the remaining part of bug 1297; bugfix on 0.2.2.2-alpha. - Make sure we never mark the wrong rendezvous circuit as having had its introduction cell acknowleged by the introduction-point relay. Previously, when we received an INTRODUCE_ACK cell on a client-side hidden-service introduction circuit, we might have marked a rendezvous circuit other than the one we specified in the INTRODUCE1 cell as INTRO_ACKED, which would have produced a warning message and interfered with the hidden service connection-establishment process. Fixes bug 4759; bugfix on 0.2.3.3-alpha, when we added the stream-isolation feature which might cause Tor to open multiple rendezvous circuits for the same hidden service. - Don't trigger an assertion failure when we mark a new client-side hidden-service introduction circuit for close during the process of creating it. Fixes bug 4796; bugfix on 0.2.3.6-alpha. Reported by murb. o Minor bugfixes (log messages): - Correctly spell "connect" in a log message on failure to create a controlsocket. Fixes bug 4803; bugfix on 0.2.2.26-beta and 0.2.3.2-alpha. - Fix a typo in a log message in rend_service_rendezvous_has_opened(). Fixes bug 4856; bugfix on Tor 0.0.6. - Fix the log message describing how we work around discovering that our version is the ill-fated OpenSSL 0.9.8l. Fixes bug 4837; bugfix on 0.2.2.9-alpha. - When logging about a disallowed .exit name, do not also call it an "invalid onion address". Fixes bug 3325; bugfix on 0.2.2.9-alpha. o Minor bugfixes (build fixes): - During configure, detect when we're building with clang version 3.0 or lower and disable the -Wnormalized=id and -Woverride-init CFLAGS. clang doesn't support them yet. - During configure, search for library containing cos function as libm lives in libcore on some platforms (BeOS/Haiku). Linking against libm was hard-coded before. Fixes the first part of bug 4727; bugfix on 0.2.2.2-alpha. Patch and analysis by Martin Hebnes Pedersen. - Detect attempts to build Tor on (as yet hypothetical) versions of Windows where sizeof(intptr_t) != sizeof(SOCKET). Partial fix for bug 4533. Bugfix on 0.2.2.28-beta. - Preprocessor directives should not be put inside the arguments of a macro. This would break compilation with GCC releases prior to version 3.3. We would never recommend such an old GCC version, but it is apparently required for binary compatibility on some platforms (namely, certain builds of Haiku). Fixes the other part of bug 4727; bugfix on 0.2.3.3-alpha. Patch and analysis by Martin Hebnes Pedersen. o Minor bugfixes (other): - Older Linux kernels erroneously respond to strange nmap behavior by having accept() return successfully with a zero-length socket. When this happens, just close the connection. Previously, we would try harder to learn the remote address: but there was no such remote address to learn, and our method for trying to learn it was incorrect. Fixes bugs 1240, 4745, and 4747. Bugfix on 0.1.0.3-rc. Reported and diagnosed by "r1eo". - Fix null-pointer access that could occur if TLS allocation failed. Fixes bug 4531; bugfix on 0.2.0.20-rc. Found by "troll_un". This was erroneously listed as fixed in 0.2.3.9-alpha, but the fix had accidentally been reverted. - Fix our implementation of crypto_random_hostname() so it can't overflow on ridiculously large inputs. (No Tor version has ever provided this kind of bad inputs, but let's be correct in depth.) Fixes bug 4413; bugfix on 0.2.2.9-alpha. Fix by Stephen Palmateer. - Find more places in the code that should have been testing for invalid sockets using the SOCKET_OK macro. Required for a fix for bug 4533. Bugfix on 0.2.2.28-beta. - Fix an assertion failure when, while running with bufferevents, a connection finishes connecting after it is marked for close, but before it is closed. Fixes bug 4697; bugfix on 0.2.3.1-alpha. - test_util_spawn_background_ok() hardcoded the expected value for ENOENT to 2. This isn't portable as error numbers are platform specific, and particularly the hurd has ENOENT at 0x40000002. Construct expected string at runtime, using the correct value for ENOENT. Fixes bug 4733; bugfix on 0.2.3.1-alpha. - Reject attempts to disable DisableDebuggerAttachment while Tor is running. Fixes bug 4650; bugfix on 0.2.3.9-alpha. - Use an appropriate-width type for sockets in tor-fw-helper on win64. Fixes bug 1983 at last. Bugfix on 0.2.3.9-alpha. o Feature removal: - When sending or relaying a RELAY_EARLY cell, we used to convert it to a RELAY cell if the connection was using the v1 link protocol. This was a workaround for older versions of Tor, which didn't handle RELAY_EARLY cells properly. Now that all supported versions can handle RELAY_EARLY cells, and now that we're enforcing the "no RELAY_EXTEND commands except in RELAY_EARLY cells" rule, remove this workaround. Addresses bug 4786. o Code simplifications and refactoring: - Use OpenSSL's built-in SSL_state_string_long() instead of our own homebrewed ssl_state_to_string() replacement. Patch from Emile Snyder. Fixes bug 4653. - Use macros to indicate OpenSSL versions, so we don't need to worry about accidental hexadecimal bit shifts. - Remove some workaround code for OpenSSL 0.9.6 (which is no longer supported). - Convert more instances of tor_snprintf+tor_strdup into tor_asprintf. - Use the smartlist_add_asprintf() alias more consistently. - Use a TOR_INVALID_SOCKET macro when initializing a socket to an invalid value, rather than just -1. - Rename a handful of old identifiers, mostly related to crypto structures and crypto functions. By convention, our "create an object" functions are called "type_new()", our "free an object" functions are called "type_free()", and our types indicate that they are types only with a final "_t". But a handful of older types and functions broke these rules, with function names like "type_create" or "subsystem_op_type", or with type names like type_env_t. Changes in version 0.2.3.10-alpha - 2011-12-16 Tor 0.2.3.10-alpha fixes a critical heap-overflow security issue in Tor's buffers code. Absolutely everybody should upgrade. The bug relied on an incorrect calculation when making data continuous in one of our IO buffers, if the first chunk of the buffer was misaligned by just the wrong amount. The miscalculation would allow an attacker to overflow a piece of heap-allocated memory. To mount this attack, the attacker would need to either open a SOCKS connection to Tor's SocksPort (usually restricted to localhost), or target a Tor instance configured to make its connections through a SOCKS proxy (which Tor does not do by default). Good security practice requires that all heap-overflow bugs should be presumed to be exploitable until proven otherwise, so we are treating this as a potential code execution attack. Please upgrade immediately! This bug does not affect bufferevents-based builds of Tor. Special thanks to "Vektor" for reporting this issue to us! This release also contains a few minor bugfixes for issues discovered in 0.2.3.9-alpha. o Major bugfixes: - Fix a heap overflow bug that could occur when trying to pull data into the first chunk of a buffer, when that chunk had already had some data drained from it. Fixes CVE-2011-2778; bugfix on 0.2.0.16-alpha. Reported by "Vektor". o Minor bugfixes: - If we can't attach streams to a rendezvous circuit when we finish connecting to a hidden service, clear the rendezvous circuit's stream-isolation state and try to attach streams again. Previously, we cleared rendezvous circuits' isolation state either too early (if they were freshly built) or not at all (if they had been built earlier and were cannibalized). Bugfix on 0.2.3.3-alpha; fixes bug 4655. - Fix compilation of the libnatpmp helper on non-Windows. Bugfix on 0.2.3.9-alpha; fixes bug 4691. Reported by Anthony G. Basile. - Fix an assertion failure when a relay with accounting enabled starts up while dormant. Fixes bug 4702; bugfix on 0.2.3.9-alpha. o Minor features: - Update to the December 6 2011 Maxmind GeoLite Country database. Changes in version 0.2.2.35 - 2011-12-16 Tor 0.2.2.35 fixes a critical heap-overflow security issue in Tor's buffers code. Absolutely everybody should upgrade. The bug relied on an incorrect calculation when making data continuous in one of our IO buffers, if the first chunk of the buffer was misaligned by just the wrong amount. The miscalculation would allow an attacker to overflow a piece of heap-allocated memory. To mount this attack, the attacker would need to either open a SOCKS connection to Tor's SocksPort (usually restricted to localhost), or target a Tor instance configured to make its connections through a SOCKS proxy (which Tor does not do by default). Good security practice requires that all heap-overflow bugs should be presumed to be exploitable until proven otherwise, so we are treating this as a potential code execution attack. Please upgrade immediately! This bug does not affect bufferevents-based builds of Tor. Special thanks to "Vektor" for reporting this issue to us! Tor 0.2.2.35 also fixes several bugs in previous versions, including crash bugs for unusual configurations, and a long-term bug that would prevent Tor from starting on Windows machines with draconian AV software. With this release, we remind everyone that 0.2.0.x has reached its formal end-of-life. Those Tor versions have many known flaws, and nobody should be using them. You should upgrade -- ideally to the 0.2.2.x series. If you're using a Linux or BSD and its packages are obsolete, stop using those packages and upgrade anyway. The Tor 0.2.1.x series is also approaching its end-of-life: it will no longer receive support after some time in early 2012. o Major bugfixes: - Fix a heap overflow bug that could occur when trying to pull data into the first chunk of a buffer, when that chunk had already had some data drained from it. Fixes CVE-2011-2778; bugfix on 0.2.0.16-alpha. Reported by "Vektor". - Initialize Libevent with the EVENT_BASE_FLAG_NOLOCK flag enabled, so that it doesn't attempt to allocate a socketpair. This could cause some problems on Windows systems with overzealous firewalls. Fix for bug 4457; workaround for Libevent versions 2.0.1-alpha through 2.0.15-stable. - If we mark an OR connection for close based on a cell we process, don't process any further cells on it. We already avoid further reads on marked-for-close connections, but now we also discard the cells we'd already read. Fixes bug 4299; bugfix on 0.2.0.10-alpha, which was the first version where we might mark a connection for close based on processing a cell on it. - Correctly sanity-check that we don't underflow on a memory allocation (and then assert) for hidden service introduction point decryption. Bug discovered by Dan Rosenberg. Fixes bug 4410; bugfix on 0.2.1.5-alpha. - Fix a memory leak when we check whether a hidden service descriptor has any usable introduction points left. Fixes bug 4424. Bugfix on 0.2.2.25-alpha. - Don't crash when we're running as a relay and don't have a GeoIP file. Bugfix on 0.2.2.34; fixes bug 4340. This backports a fix we've had in the 0.2.3.x branch already. - When running as a client, do not print a misleading (and plain wrong) log message that we're collecting "directory request" statistics: clients don't collect statistics. Also don't create a useless (because empty) stats file in the stats/ directory. Fixes bug 4353; bugfix on 0.2.2.34. o Minor bugfixes: - Detect failure to initialize Libevent. This fix provides better detection for future instances of bug 4457. - Avoid frequent calls to the fairly expensive cull_wedged_cpuworkers function. This was eating up hideously large amounts of time on some busy servers. Fixes bug 4518; bugfix on 0.0.9.8. - Resolve an integer overflow bug in smartlist_ensure_capacity(). Fixes bug 4230; bugfix on Tor 0.1.0.1-rc. Based on a patch by Mansour Moufid. - Don't warn about unused log_mutex in log.c when building with --disable-threads using a recent GCC. Fixes bug 4437; bugfix on 0.1.0.6-rc which introduced --disable-threads. - When configuring, starting, or stopping an NT service, stop immediately after the service configuration attempt has succeeded or failed. Fixes bug 3963; bugfix on 0.2.0.7-alpha. - When sending a NETINFO cell, include the original address received for the other side, not its canonical address. Found by "troll_un"; fixes bug 4349; bugfix on 0.2.0.10-alpha. - Fix a typo in a hibernation-related log message. Fixes bug 4331; bugfix on 0.2.2.23-alpha; found by "tmpname0901". - Fix a memory leak in launch_direct_bridge_descriptor_fetch() that occurred when a client tried to fetch a descriptor for a bridge in ExcludeNodes. Fixes bug 4383; bugfix on 0.2.2.25-alpha. - Backport fixes for a pair of compilation warnings on Windows. Fixes bug 4521; bugfix on 0.2.2.28-beta and on 0.2.2.29-beta. - If we had ever tried to call tor_addr_to_str on an address of unknown type, we would have done a strdup on an uninitialized buffer. Now we won't. Fixes bug 4529; bugfix on 0.2.1.3-alpha. Reported by "troll_un". - Correctly detect and handle transient lookup failures from tor_addr_lookup. Fixes bug 4530; bugfix on 0.2.1.5-alpha. Reported by "troll_un". - Fix null-pointer access that could occur if TLS allocation failed. Fixes bug 4531; bugfix on 0.2.0.20-rc. Found by "troll_un". - Use tor_socket_t type for listener argument to accept(). Fixes bug 4535; bugfix on 0.2.2.28-beta. Found by "troll_un". o Minor features: - Add two new config options for directory authorities: AuthDirFastGuarantee sets a bandwidth threshold for guaranteeing the Fast flag, and AuthDirGuardBWGuarantee sets a bandwidth threshold that is always sufficient to satisfy the bandwidth requirement for the Guard flag. Now it will be easier for researchers to simulate Tor networks with different values. Resolves ticket 4484. - When Tor ignores a hidden service specified in its configuration, include the hidden service's directory in the warning message. Previously, we would only tell the user that some hidden service was ignored. Bugfix on 0.0.6; fixes bug 4426. - Update to the December 6 2011 Maxmind GeoLite Country database. o Packaging changes: - Make it easier to automate expert package builds on Windows, by removing an absolute path from makensis.exe command. Changes in version 0.2.1.32 - 2011-12-16 Tor 0.2.1.32 backports important security and privacy fixes for oldstable. This release is intended only for package maintainers and others who cannot use the 0.2.2 stable series. All others should be using Tor 0.2.2.x or newer. The Tor 0.2.1.x series will reach formal end-of-life some time in early 2012; we will stop releasing patches for it then. o Major bugfixes (also included in 0.2.2.x): - Correctly sanity-check that we don't underflow on a memory allocation (and then assert) for hidden service introduction point decryption. Bug discovered by Dan Rosenberg. Fixes bug 4410; bugfix on 0.2.1.5-alpha. - Fix a heap overflow bug that could occur when trying to pull data into the first chunk of a buffer, when that chunk had already had some data drained from it. Fixes CVE-2011-2778; bugfix on 0.2.0.16-alpha. Reported by "Vektor". o Minor features: - Update to the December 6 2011 Maxmind GeoLite Country database. Changes in version 0.2.3.9-alpha - 2011-12-08 Tor 0.2.3.9-alpha introduces initial IPv6 support for bridges, adds a "DisableNetwork" security feature that bundles can use to avoid touching the network until bridges are configured, moves forward on the pluggable transport design, fixes a flaw in the hidden service design that unnecessarily prevented clients with wrong clocks from reaching hidden services, and fixes a wide variety of other issues. o Major features: - Clients can now connect to private bridges over IPv6. Bridges still need at least one IPv4 address in order to connect to other relays. Note that we don't yet handle the case where the user has two bridge lines for the same bridge (one IPv4, one IPv6). Implements parts of proposal 186. - New "DisableNetwork" config option to prevent Tor from launching any connections or accepting any connections except on a control port. Bundles and controllers can set this option before letting Tor talk to the rest of the network, for example to prevent any connections to a non-bridge address. Packages like Orbot can also use this option to instruct Tor to save power when the network is off. - Clients and bridges can now be configured to use a separate "transport" proxy. This approach makes the censorship arms race easier by allowing bridges to use protocol obfuscation plugins. It implements the "managed proxy" part of proposal 180 (ticket 3472). - When using OpenSSL 1.0.0 or later, use OpenSSL's counter mode implementation. It makes AES_CTR about 7% faster than our old one (which was about 10% faster than the one OpenSSL used to provide). Resolves ticket 4526. - Add a "tor2web mode" for clients that want to connect to hidden services non-anonymously (and possibly more quickly). As a safety measure to try to keep users from turning this on without knowing what they are doing, tor2web mode must be explicitly enabled at compile time, and a copy of Tor compiled to run in tor2web mode cannot be used as a normal Tor client. Implements feature 2553. - Add experimental support for running on Windows with IOCP and no kernel-space socket buffers. This feature is controlled by a new "UserspaceIOCPBuffers" config option (off by default), which has no effect unless Tor has been built with support for bufferevents, is running on Windows, and has enabled IOCP. This may, in the long run, help solve or mitigate bug 98. - Use a more secure consensus parameter voting algorithm. Now at least three directory authorities or a majority of them must vote on a given parameter before it will be included in the consensus. Implements proposal 178. o Major bugfixes: - Hidden services now ignore the timestamps on INTRODUCE2 cells. They used to check that the timestamp was within 30 minutes of their system clock, so they could cap the size of their replay-detection cache, but that approach unnecessarily refused service to clients with wrong clocks. Bugfix on 0.2.1.6-alpha, when the v3 intro-point protocol (the first one which sent a timestamp field in the INTRODUCE2 cell) was introduced; fixes bug 3460. - Only use the EVP interface when AES acceleration is enabled, to avoid a 5-7% performance regression. Resolves issue 4525; bugfix on 0.2.3.8-alpha. o Privacy/anonymity features (bridge detection): - Make bridge SSL certificates a bit more stealthy by using random serial numbers, in the same fashion as OpenSSL when generating self-signed certificates. Implements ticket 4584. - Introduce a new config option "DynamicDHGroups", enabled by default, which provides each bridge with a unique prime DH modulus to be used during SSL handshakes. This option attempts to help against censors who might use the Apache DH modulus as a static identifier for bridges. Addresses ticket 4548. o Minor features (new/different config options): - New configuration option "DisableDebuggerAttachment" (on by default) to prevent basic debugging attachment attempts by other processes. Supports Mac OS X and Gnu/Linux. Resolves ticket 3313. - Allow MapAddress directives to specify matches against super-domains, as in "MapAddress *.torproject.org *.torproject.org.torserver.exit". Implements issue 933. - Slightly change behavior of "list" options (that is, config options that can appear more than once) when they appear both in torrc and on the command line. Previously, the command-line options would be appended to the ones from torrc. Now, the command-line options override the torrc options entirely. This new behavior allows the user to override list options (like exit policies and ports to listen on) from the command line, rather than simply appending to the list. - You can get the old (appending) command-line behavior for "list" options by prefixing the option name with a "+". - You can remove all the values for a "list" option from the command line without adding any new ones by prefixing the option name with a "/". - Add experimental support for a "defaults" torrc file to be parsed before the regular torrc. Torrc options override the defaults file's options in the same way that the command line overrides the torrc. The SAVECONF controller command saves only those options which differ between the current configuration and the defaults file. HUP reloads both files. (Note: This is an experimental feature; its behavior will probably be refined in future 0.2.3.x-alpha versions to better meet packagers' needs.) Implements task 4552. o Minor features: - Try to make the introductory warning message that Tor prints on startup more useful for actually finding help and information. Resolves ticket 2474. - Running "make version" now displays the version of Tor that we're about to build. Idea from katmagic; resolves issue 4400. - Expire old or over-used hidden service introduction points. Required by fix for bug 3460. - Move the replay-detection cache for the RSA-encrypted parts of INTRODUCE2 cells to the introduction point data structures. Previously, we would use one replay-detection cache per hidden service. Required by fix for bug 3460. - Reduce the lifetime of elements of hidden services' Diffie-Hellman public key replay-detection cache from 60 minutes to 5 minutes. This replay-detection cache is now used only to detect multiple INTRODUCE2 cells specifying the same rendezvous point, so we can avoid launching multiple simultaneous attempts to connect to it. o Minor bugfixes (on Tor 0.2.2.x and earlier): - Resolve an integer overflow bug in smartlist_ensure_capacity(). Fixes bug 4230; bugfix on Tor 0.1.0.1-rc. Based on a patch by Mansour Moufid. - Fix a minor formatting issue in one of tor-gencert's error messages. Fixes bug 4574. - Prevent a false positive from the check-spaces script, by disabling the "whitespace between function name and (" check for functions named 'op()'. - Fix a log message suggesting that people contact a non-existent email address. Fixes bug 3448. - Fix null-pointer access that could occur if TLS allocation failed. Fixes bug 4531; bugfix on 0.2.0.20-rc. Found by "troll_un". - Report a real bootstrap problem to the controller on router identity mismatch. Previously we just said "foo", which probably made a lot of sense at the time. Fixes bug 4169; bugfix on 0.2.1.1-alpha. - If we had ever tried to call tor_addr_to_str() on an address of unknown type, we would have done a strdup() on an uninitialized buffer. Now we won't. Fixes bug 4529; bugfix on 0.2.1.3-alpha. Reported by "troll_un". - Correctly detect and handle transient lookup failures from tor_addr_lookup(). Fixes bug 4530; bugfix on 0.2.1.5-alpha. Reported by "troll_un". - Use tor_socket_t type for listener argument to accept(). Fixes bug 4535; bugfix on 0.2.2.28-beta. Found by "troll_un". - Initialize conn->addr to a valid state in spawn_cpuworker(). Fixes bug 4532; found by "troll_un". o Minor bugfixes (on Tor 0.2.3.x): - Fix a compile warning in tor_inet_pton(). Bugfix on 0.2.3.8-alpha; fixes bug 4554. - Don't send two ESTABLISH_RENDEZVOUS cells when opening a new circuit for use as a hidden service client's rendezvous point. Fixes bugs 4641 and 4171; bugfix on 0.2.3.3-alpha. Diagnosed with help from wanoskarnet. - Restore behavior of overriding SocksPort, ORPort, and similar options from the command line. Bugfix on 0.2.3.3-alpha. o Build fixes: - Properly handle the case where the build-tree is not the same as the source tree when generating src/common/common_sha1.i, src/or/micro-revision.i, and src/or/or_sha1.i. Fixes bug 3953; bugfix on 0.2.0.1-alpha. o Code simplifications, cleanups, and refactorings: - Remove the pure attribute from all functions that used it previously. In many cases we assigned it incorrectly, because the functions might assert or call impure functions, and we don't have evidence that keeping the pure attribute is worthwhile. Implements changes suggested in ticket 4421. - Remove some dead code spotted by coverity. Fixes cid 432. Bugfix on 0.2.3.1-alpha, closes bug 4637. Changes in version 0.2.3.8-alpha - 2011-11-22 Tor 0.2.3.8-alpha fixes some crash and assert bugs, including a socketpair-related bug that has been bothering Windows users. It adds support to serve microdescriptors to controllers, so Vidalia's network map can resume listing relays (once Vidalia implements its side), and adds better support for hardware AES acceleration. Finally, it starts the process of adjusting the bandwidth cutoff for getting the "Fast" flag from 20KB to (currently) 32KB -- preliminary results show that tiny relays harm performance more than they help network capacity. o Major bugfixes: - Initialize Libevent with the EVENT_BASE_FLAG_NOLOCK flag enabled, so that it doesn't attempt to allocate a socketpair. This could cause some problems on Windows systems with overzealous firewalls. Fix for bug 4457; workaround for Libevent versions 2.0.1-alpha through 2.0.15-stable. - Correctly sanity-check that we don't underflow on a memory allocation (and then assert) for hidden service introduction point decryption. Bug discovered by Dan Rosenberg. Fixes bug 4410; bugfix on 0.2.1.5-alpha. - Remove the artificially low cutoff of 20KB to guarantee the Fast flag. In the past few years the average relay speed has picked up, and while the "top 7/8 of the network get the Fast flag" and "all relays with 20KB or more of capacity get the Fast flag" rules used to have the same result, now the top 7/8 of the network has a capacity more like 32KB. Bugfix on 0.2.1.14-rc. Fixes bug 4489. - Fix a rare assertion failure when checking whether a v0 hidden service descriptor has any usable introduction points left, and we don't have enough information to build a circuit to the first intro point named in the descriptor. The HS client code in 0.2.3.x no longer uses v0 HS descriptors, but this assertion can trigger on (and crash) v0 HS authorities. Fixes bug 4411. Bugfix on 0.2.3.1-alpha; diagnosed by frosty_un. - Make bridge authorities not crash when they are asked for their own descriptor. Bugfix on 0.2.3.7-alpha, reported by Lucky Green. - When running as a client, do not print a misleading (and plain wrong) log message that we're collecting "directory request" statistics: clients don't collect statistics. Also don't create a useless (because empty) stats file in the stats/ directory. Fixes bug 4353; bugfix on 0.2.2.34 and 0.2.3.7-alpha. o Major features: - Allow Tor controllers like Vidalia to obtain the microdescriptor for a relay by identity digest or nickname. Previously, microdescriptors were only available by their own digests, so a controller would have to ask for and parse the whole microdescriptor consensus in order to look up a single relay's microdesc. Fixes bug 3832; bugfix on 0.2.3.1-alpha. - Use OpenSSL's EVP interface for AES encryption, so that all AES operations can use hardware acceleration (if present). Resolves ticket 4442. o Minor bugfixes (on 0.2.2.x and earlier): - Detect failure to initialize Libevent. This fix provides better detection for future instances of bug 4457. - Avoid frequent calls to the fairly expensive cull_wedged_cpuworkers function. This was eating up hideously large amounts of time on some busy servers. Fixes bug 4518; bugfix on 0.0.9.8. - Don't warn about unused log_mutex in log.c when building with --disable-threads using a recent GCC. Fixes bug 4437; bugfix on 0.1.0.6-rc which introduced --disable-threads. - Allow manual 'authenticate' commands to the controller interface from netcat (nc) as well as telnet. We were rejecting them because they didn't come with the expected whitespace at the end of the command. Bugfix on 0.1.1.1-alpha; fixes bug 2893. - Fix some (not actually triggerable) buffer size checks in usage of tor_inet_ntop. Fixes bug 4434; bugfix on Tor 0.2.0.1-alpha. Patch by Anders Sundman. - Fix parsing of some corner-cases with tor_inet_pton(). Fixes bug 4515; bugfix on 0.2.0.1-alpha; fix by Anders Sundman. - When configuring, starting, or stopping an NT service, stop immediately after the service configuration attempt has succeeded or failed. Fixes bug 3963; bugfix on 0.2.0.7-alpha. - When sending a NETINFO cell, include the original address received for the other side, not its canonical address. Found by "troll_un"; fixes bug 4349; bugfix on 0.2.0.10-alpha. - Rename the bench_{aes,dmap} functions to test_*, so that tinytest can pick them up when the tests aren't disabled. Bugfix on 0.2.2.4-alpha which introduced tinytest. - Fix a memory leak when we check whether a hidden service descriptor has any usable introduction points left. Fixes bug 4424. Bugfix on 0.2.2.25-alpha. - Fix a memory leak in launch_direct_bridge_descriptor_fetch() that occurred when a client tried to fetch a descriptor for a bridge in ExcludeNodes. Fixes bug 4383; bugfix on 0.2.2.25-alpha. o Minor bugfixes (on 0.2.3.x): - Make util unit tests build correctly with MSVC. Bugfix on 0.2.3.3-alpha. Patch by Gisle Vanem. - Successfully detect AUTH_CHALLENGE cells with no recognized authentication type listed. Fixes bug 4367; bugfix on 0.2.3.6-alpha. Found by frosty_un. - If a relay receives an AUTH_CHALLENGE cell it can't answer, it should still send a NETINFO cell to allow the connection to become open. Fixes bug 4368; fix on 0.2.3.6-alpha; bug found by "frosty". - Log less loudly when we get an invalid authentication certificate from a source other than a directory authority: it's not unusual to see invalid certs because of clock skew. Fixes bug 4370; bugfix on 0.2.3.6-alpha. - Tolerate servers with more clock skew in their authentication certificates than previously. Fixes bug 4371; bugfix on 0.2.3.6-alpha. - Fix a couple of compile warnings on Windows. Fixes bug 4469; bugfix on 0.2.3.4-alpha and 0.2.3.6-alpha. o Minor features: - Add two new config options for directory authorities: AuthDirFastGuarantee sets a bandwidth threshold for guaranteeing the Fast flag, and AuthDirGuardBWGuarantee sets a bandwidth threshold that is always sufficient to satisfy the bandwidth requirement for the Guard flag. Now it will be easier for researchers to simulate Tor networks with different values. Resolves ticket 4484. - When Tor ignores a hidden service specified in its configuration, include the hidden service's directory in the warning message. Previously, we would only tell the user that some hidden service was ignored. Bugfix on 0.0.6; fixes bug 4426. - When we fail to initialize Libevent, retry with IOCP disabled so we don't need to turn on multi-threading support in Libevent, which in turn requires a working socketpair(). This is a workaround for bug 4457, which affects Libevent versions from 2.0.1-alpha through 2.0.15-stable. - Detect when we try to build on a platform that doesn't define AF_UNSPEC to 0. We don't work there, so refuse to compile. - Update to the November 1 2011 Maxmind GeoLite Country database. o Packaging changes: - Make it easier to automate expert package builds on Windows, by removing an absolute path from makensis.exe command. o Code simplifications and refactoring: - Remove some redundant #include directives throughout the code. Patch from Andrea Gelmini. - Unconditionally use OpenSSL's AES implementation instead of our old built-in one. OpenSSL's AES has been better for a while, and relatively few servers should still be on any version of OpenSSL that doesn't have good optimized assembly AES. - Use the name "CERTS" consistently to refer to the new cell type; we were calling it CERT in some places and CERTS in others. o Testing: - Numerous new unit tests for functions in util.c and address.c by Anders Sundman. - The long-disabled benchmark tests are now split into their own ./src/test/bench binary. - The benchmark tests can now use more accurate timers than gettimeofday() when such timers are available. Changes in version 0.2.3.7-alpha - 2011-10-30 Tor 0.2.3.7-alpha fixes a crash bug in 0.2.3.6-alpha introduced by the new v3 handshake. It also resolves yet another bridge address enumeration issue. o Major bugfixes: - If we mark an OR connection for close based on a cell we process, don't process any further cells on it. We already avoid further reads on marked-for-close connections, but now we also discard the cells we'd already read. Fixes bug 4299; bugfix on 0.2.0.10-alpha, which was the first version where we might mark a connection for close based on processing a cell on it. - Fix a double-free bug that would occur when we received an invalid certificate in a CERT cell in the new v3 handshake. Fixes bug 4343; bugfix on 0.2.3.6-alpha. - Bridges no longer include their address in NETINFO cells on outgoing OR connections, to allow them to blend in better with clients. Removes another avenue for enumerating bridges. Reported by "troll_un". Fixes bug 4348; bugfix on 0.2.0.10-alpha, when NETINFO cells were introduced. o Trivial fixes: - Fixed a typo in a hibernation-related log message. Fixes bug 4331; bugfix on 0.2.2.23-alpha; found by "tmpname0901". Changes in version 0.2.3.6-alpha - 2011-10-26 Tor 0.2.3.6-alpha includes the fix from 0.2.2.34 for a critical anonymity vulnerability where an attacker can deanonymize Tor users. Everybody should upgrade. This release also features support for a new v3 connection handshake protocol, and fixes to make hidden service connections more robust. o Major features: - Implement a new handshake protocol (v3) for authenticating Tors to each other over TLS. It should be more resistant to fingerprinting than previous protocols, and should require less TLS hacking for future Tor implementations. Implements proposal 176. - Allow variable-length padding cells to disguise the length of Tor's TLS records. Implements part of proposal 184. o Privacy/anonymity fixes (clients): - Clients and bridges no longer send TLS certificate chains on outgoing OR connections. Previously, each client or bridge would use the same cert chain for all outgoing OR connections until its IP address changes, which allowed any relay that the client or bridge contacted to determine which entry guards it is using. Fixes CVE-2011-2768. Bugfix on 0.0.9pre5; found by "frosty_un". - If a relay receives a CREATE_FAST cell on a TLS connection, it no longer considers that connection as suitable for satisfying a circuit EXTEND request. Now relays can protect clients from the CVE-2011-2768 issue even if the clients haven't upgraded yet. - Directory authorities no longer assign the Guard flag to relays that haven't upgraded to the above "refuse EXTEND requests to client connections" fix. Now directory authorities can protect clients from the CVE-2011-2768 issue even if neither the clients nor the relays have upgraded yet. There's a new "GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays" config option to let us transition smoothly, else tomorrow there would be no guard relays. o Major bugfixes (hidden services): - Improve hidden service robustness: when an attempt to connect to a hidden service ends, be willing to refetch its hidden service descriptors from each of the HSDir relays responsible for them immediately. Previously, we would not consider refetching the service's descriptors from each HSDir for 15 minutes after the last fetch, which was inconvenient if the hidden service was not running during the first attempt. Bugfix on 0.2.0.18-alpha; fixes bug 3335. - When one of a hidden service's introduction points appears to be unreachable, stop trying it. Previously, we would keep trying to build circuits to the introduction point until we lost the descriptor, usually because the user gave up and restarted Tor. Partly fixes bug 3825. - Don't launch a useless circuit after failing to use one of a hidden service's introduction points. Previously, we would launch a new introduction circuit, but not set the hidden service which that circuit was intended to connect to, so it would never actually be used. A different piece of code would then create a new introduction circuit correctly. Bug reported by katmagic and found by Sebastian Hahn. Bugfix on 0.2.1.13-alpha; fixes bug 4212. o Major bugfixes (other): - Bridges now refuse CREATE or CREATE_FAST cells on OR connections that they initiated. Relays could distinguish incoming bridge connections from client connections, creating another avenue for enumerating bridges. Fixes CVE-2011-2769. Bugfix on 0.2.0.3-alpha. Found by "frosty_un". - Don't update the AccountingSoftLimitHitAt state file entry whenever tor gets started. This prevents a wrong average bandwidth estimate, which would cause relays to always start a new accounting interval at the earliest possible moment. Fixes bug 2003; bugfix on 0.2.2.7-alpha. Reported by BryonEldridge, who also helped immensely in tracking this bug down. - Fix a crash bug when changing node restrictions while a DNS lookup is in-progress. Fixes bug 4259; bugfix on 0.2.2.25-alpha. Bugfix by "Tey'". o Minor bugfixes (on 0.2.2.x and earlier): - When a hidden service turns an extra service-side introduction circuit into a general-purpose circuit, free the rend_data and intro_key fields first, so we won't leak memory if the circuit is cannibalized for use as another service-side introduction circuit. Bugfix on 0.2.1.7-alpha; fixes bug 4251. - Rephrase the log message emitted if the TestSocks check is successful. Patch from Fabian Keil; fixes bug 4094. - Bridges now skip DNS self-tests, to act a little more stealthily. Fixes bug 4201; bugfix on 0.2.0.3-alpha, which first introduced bridges. Patch by "warms0x". - Remove a confusing dollar sign from the example fingerprint in the man page, and also make the example fingerprint a valid one. Fixes bug 4309; bugfix on 0.2.1.3-alpha. - Fix internal bug-checking logic that was supposed to catch failures in digest generation so that it will fail more robustly if we ask for a nonexistent algorithm. Found by Coverity Scan. Bugfix on 0.2.2.1-alpha; fixes Coverity CID 479. - Report any failure in init_keys() calls launched because our IP address has changed. Spotted by Coverity Scan. Bugfix on 0.1.1.4-alpha; fixes CID 484. o Minor bugfixes (on 0.2.3.x): - Fix a bug in configure.in that kept it from building a configure script with autoconf versions earlier than 2.61. Fixes bug 2430; bugfix on 0.2.3.1-alpha. - Don't warn users that they are exposing a client port to the Internet if they have specified an RFC1918 address. Previously, we would warn if the user had specified any non-loopback address. Bugfix on 0.2.3.3-alpha. Fixes bug 4018; reported by Tas. - Fix memory leaks in the failing cases of the new SocksPort and ControlPort code. Found by Coverity Scan. Bugfix on 0.2.3.3-alpha; fixes coverity CIDs 485, 486, and 487. o Minor features: - When a hidden service's introduction point times out, consider trying it again during the next attempt to connect to the HS. Previously, we would not try it again unless a newly fetched descriptor contained it. Required by fixes for bugs 1297 and 3825. - The next version of Windows will be called Windows 8, and it has a major version of 6, minor version of 2. Correctly identify that version instead of calling it "Very recent version". Resolves ticket 4153; reported by funkstar. - The Bridge Authority now writes statistics on how many bridge descriptors it gave out in total, and how many unique descriptors it gave out. It also lists how often the most and least commonly fetched descriptors were given out, as well as the median and 25th/75th percentile. Implements tickets 4200 and 4294. - Update to the October 4 2011 Maxmind GeoLite Country database. o Code simplifications and refactoring: - Remove some old code to remember statistics about which descriptors we've served as a directory mirror. The feature wasn't used and is outdated now that microdescriptors are around. - Rename Tor functions that turn strings into addresses, so that "parse" indicates that no hostname resolution occurs, and "lookup" indicates that hostname resolution may occur. This should help prevent mistakes in the future. Fixes bug 3512. Changes in version 0.2.2.34 - 2011-10-26 Tor 0.2.2.34 fixes a critical anonymity vulnerability where an attacker can deanonymize Tor users. Everybody should upgrade. The attack relies on four components: 1) Clients reuse their TLS cert when talking to different relays, so relays can recognize a user by the identity key in her cert. 2) An attacker who knows the client's identity key can probe each guard relay to see if that identity key is connected to that guard relay right now. 3) A variety of active attacks in the literature (starting from "Low-Cost Traffic Analysis of Tor" by Murdoch and Danezis in 2005) allow a malicious website to discover the guard relays that a Tor user visiting the website is using. 4) Clients typically pick three guards at random, so the set of guards for a given user could well be a unique fingerprint for her. This release fixes components #1 and #2, which is enough to block the attack; the other two remain as open research problems. Special thanks to "frosty_un" for reporting the issue to us! Clients should upgrade so they are no longer recognizable by the TLS certs they present. Relays should upgrade so they no longer allow a remote attacker to probe them to test whether unpatched clients are currently connected to them. This release also fixes several vulnerabilities that allow an attacker to enumerate bridge relays. Some bridge enumeration attacks still remain; see for example proposal 188. o Privacy/anonymity fixes (clients): - Clients and bridges no longer send TLS certificate chains on outgoing OR connections. Previously, each client or bridge would use the same cert chain for all outgoing OR connections until its IP address changes, which allowed any relay that the client or bridge contacted to determine which entry guards it is using. Fixes CVE-2011-2768. Bugfix on 0.0.9pre5; found by "frosty_un". - If a relay receives a CREATE_FAST cell on a TLS connection, it no longer considers that connection as suitable for satisfying a circuit EXTEND request. Now relays can protect clients from the CVE-2011-2768 issue even if the clients haven't upgraded yet. - Directory authorities no longer assign the Guard flag to relays that haven't upgraded to the above "refuse EXTEND requests to client connections" fix. Now directory authorities can protect clients from the CVE-2011-2768 issue even if neither the clients nor the relays have upgraded yet. There's a new "GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays" config option to let us transition smoothly, else tomorrow there would be no guard relays. o Privacy/anonymity fixes (bridge enumeration): - Bridge relays now do their directory fetches inside Tor TLS connections, like all the other clients do, rather than connecting directly to the DirPort like public relays do. Removes another avenue for enumerating bridges. Fixes bug 4115; bugfix on 0.2.0.35. - Bridges relays now build circuits for themselves in a more similar way to how clients build them. Removes another avenue for enumerating bridges. Fixes bug 4124; bugfix on 0.2.0.3-alpha, when bridges were introduced. - Bridges now refuse CREATE or CREATE_FAST cells on OR connections that they initiated. Relays could distinguish incoming bridge connections from client connections, creating another avenue for enumerating bridges. Fixes CVE-2011-2769. Bugfix on 0.2.0.3-alpha. Found by "frosty_un". o Major bugfixes: - Fix a crash bug when changing node restrictions while a DNS lookup is in-progress. Fixes bug 4259; bugfix on 0.2.2.25-alpha. Bugfix by "Tey'". - Don't launch a useless circuit after failing to use one of a hidden service's introduction points. Previously, we would launch a new introduction circuit, but not set the hidden service which that circuit was intended to connect to, so it would never actually be used. A different piece of code would then create a new introduction circuit correctly. Bug reported by katmagic and found by Sebastian Hahn. Bugfix on 0.2.1.13-alpha; fixes bug 4212. o Minor bugfixes: - Change an integer overflow check in the OpenBSD_Malloc code so that GCC is less likely to eliminate it as impossible. Patch from Mansour Moufid. Fixes bug 4059. - When a hidden service turns an extra service-side introduction circuit into a general-purpose circuit, free the rend_data and intro_key fields first, so we won't leak memory if the circuit is cannibalized for use as another service-side introduction circuit. Bugfix on 0.2.1.7-alpha; fixes bug 4251. - Bridges now skip DNS self-tests, to act a little more stealthily. Fixes bug 4201; bugfix on 0.2.0.3-alpha, which first introduced bridges. Patch by "warms0x". - Fix internal bug-checking logic that was supposed to catch failures in digest generation so that it will fail more robustly if we ask for a nonexistent algorithm. Found by Coverity Scan. Bugfix on 0.2.2.1-alpha; fixes Coverity CID 479. - Report any failure in init_keys() calls launched because our IP address has changed. Spotted by Coverity Scan. Bugfix on 0.1.1.4-alpha; fixes CID 484. o Minor bugfixes (log messages and documentation): - Remove a confusing dollar sign from the example fingerprint in the man page, and also make the example fingerprint a valid one. Fixes bug 4309; bugfix on 0.2.1.3-alpha. - The next version of Windows will be called Windows 8, and it has a major version of 6, minor version of 2. Correctly identify that version instead of calling it "Very recent version". Resolves ticket 4153; reported by funkstar. - Downgrade log messages about circuit timeout calibration from "notice" to "info": they don't require or suggest any human intervention. Patch from Tom Lowenthal. Fixes bug 4063; bugfix on 0.2.2.14-alpha. o Minor features: - Turn on directory request statistics by default and include them in extra-info descriptors. Don't break if we have no GeoIP database. Backported from 0.2.3.1-alpha; implements ticket 3951. - Update to the October 4 2011 Maxmind GeoLite Country database. Changes in version 0.2.1.31 - 2011-10-26 Tor 0.2.1.31 backports important security and privacy fixes for oldstable. This release is intended only for package maintainers and others who cannot use the 0.2.2 stable series. All others should be using Tor 0.2.2.x or newer. o Security fixes (also included in 0.2.2.x): - Replace all potentially sensitive memory comparison operations with versions whose runtime does not depend on the data being compared. This will help resist a class of attacks where an adversary can use variations in timing information to learn sensitive data. Fix for one case of bug 3122. (Safe memcmp implementation by Robert Ransom based partially on code by DJB.) - Fix an assert in parsing router descriptors containing IPv6 addresses. This one took down the directory authorities when somebody tried some experimental code. Bugfix on 0.2.1.3-alpha. o Privacy/anonymity fixes (also included in 0.2.2.x): - Clients and bridges no longer send TLS certificate chains on outgoing OR connections. Previously, each client or bridge would use the same cert chain for all outgoing OR connections until its IP address changes, which allowed any relay that the client or bridge contacted to determine which entry guards it is using. Fixes CVE-2011-2768. Bugfix on 0.0.9pre5; found by "frosty_un". - If a relay receives a CREATE_FAST cell on a TLS connection, it no longer considers that connection as suitable for satisfying a circuit EXTEND request. Now relays can protect clients from the CVE-2011-2768 issue even if the clients haven't upgraded yet. - Bridges now refuse CREATE or CREATE_FAST cells on OR connections that they initiated. Relays could distinguish incoming bridge connections from client connections, creating another avenue for enumerating bridges. Fixes CVE-2011-2769. Bugfix on 0.2.0.3-alpha. Found by "frosty_un". - When receiving a hidden service descriptor, check that it is for the hidden service we wanted. Previously, Tor would store any hidden service descriptors that a directory gave it, whether it wanted them or not. This wouldn't have let an attacker impersonate a hidden service, but it did let directories pre-seed a client with descriptors that it didn't want. Bugfix on 0.0.6. - Avoid linkability based on cached hidden service descriptors: forget all hidden service descriptors cached as a client when processing a SIGNAL NEWNYM command. Fixes bug 3000; bugfix on 0.0.6. - Make the bridge directory authority refuse to answer directory requests for "all" descriptors. It used to include bridge descriptors in its answer, which was a major information leak. Found by "piebeer". Bugfix on 0.2.0.3-alpha. - Don't attach new streams to old rendezvous circuits after SIGNAL NEWNYM. Previously, we would keep using an existing rendezvous circuit if it remained open (i.e. if it were kept open by a long-lived stream, or if a new stream were attached to it before Tor could notice that it was old and no longer in use). Bugfix on 0.1.1.15-rc; fixes bug 3375. o Minor bugfixes (also included in 0.2.2.x): - When we restart our relay, we might get a successful connection from the outside before we've started our reachability tests, triggering a warning: "ORPort found reachable, but I have no routerinfo yet. Failing to inform controller of success." This bug was harmless unless Tor is running under a controller like Vidalia, in which case the controller would never get a REACHABILITY_SUCCEEDED status event. Bugfix on 0.1.2.6-alpha; fixes bug 1172. - Build correctly on OSX with zlib 1.2.4 and higher with all warnings enabled. Fixes bug 1526. - Remove undocumented option "-F" from tor-resolve: it hasn't done anything since 0.2.1.16-rc. - Avoid signed/unsigned comparisons by making SIZE_T_CEILING unsigned. None of the cases where we did this before were wrong, but by making this change we avoid warnings. Fixes bug 2475; bugfix on 0.2.1.28. - Fix a rare crash bug that could occur when a client was configured with a large number of bridges. Fixes bug 2629; bugfix on 0.2.1.2-alpha. Bugfix by trac user "shitlei". - Correct the warning displayed when a rendezvous descriptor exceeds the maximum size. Fixes bug 2750; bugfix on 0.2.1.5-alpha. Found by John Brooks. - Fix an uncommon assertion failure when running with DNSPort under heavy load. Fixes bug 2933; bugfix on 0.2.0.1-alpha. - When warning about missing zlib development packages during compile, give the correct package names. Bugfix on 0.2.0.1-alpha. - Require that introduction point keys and onion keys have public exponent 65537. Bugfix on 0.2.0.10-alpha. - Do not crash when our configuration file becomes unreadable, for example due to a permissions change, between when we start up and when a controller calls SAVECONF. Fixes bug 3135; bugfix on 0.0.9pre6. - Fix warnings from GCC 4.6's "-Wunused-but-set-variable" option. Fixes bug 3208. - Always NUL-terminate the sun_path field of a sockaddr_un before passing it to the kernel. (Not a security issue: kernels are smart enough to reject bad sockaddr_uns.) Found by Coverity; CID #428. Bugfix on Tor 0.2.0.3-alpha. - Don't stack-allocate the list of supplementary GIDs when we're about to log them. Stack-allocating NGROUPS_MAX gid_t elements could take up to 256K, which is way too much stack. Found by Coverity; CID #450. Bugfix on 0.2.1.7-alpha. o Minor bugfixes (only in 0.2.1.x): - Resume using micro-version numbers in 0.2.1.x: our Debian packages rely on them. Bugfix on 0.2.1.30. - Use git revisions instead of svn revisions when generating our micro-version numbers. Bugfix on 0.2.1.15-rc; fixes bug 2402. o Minor features (also included in 0.2.2.x): - Adjust the expiration time on our SSL session certificates to better match SSL certs seen in the wild. Resolves ticket 4014. - Allow nameservers with IPv6 address. Resolves bug 2574. - Update to the October 4 2011 Maxmind GeoLite Country database. Changes in version 0.2.3.5-alpha - 2011-09-28 Tor 0.2.3.5-alpha fixes two bugs that make it possible to enumerate bridge relays; fixes an assertion error that many users started hitting today; and adds the ability to refill token buckets more often than once per second, allowing significant performance improvements. o Security fixes: - Bridge relays now do their directory fetches inside Tor TLS connections, like all the other clients do, rather than connecting directly to the DirPort like public relays do. Removes another avenue for enumerating bridges. Fixes bug 4115; bugfix on 0.2.0.35. - Bridges relays now build circuits for themselves in a more similar way to how clients build them. Removes another avenue for enumerating bridges. Fixes bug 4124; bugfix on 0.2.0.3-alpha, when bridges were introduced. o Major bugfixes: - Fix an "Assertion md->held_by_node == 1 failed" error that could occur when the same microdescriptor was referenced by two node_t objects at once. Fix for bug 4118; bugfix on Tor 0.2.3.1-alpha. o Major features (networking): - Add a new TokenBucketRefillInterval option to refill token buckets more frequently than once per second. This should improve network performance, alleviate queueing problems, and make traffic less bursty. Implements proposal 183; closes ticket 3630. Design by Florian Tschorsch and Björn Scheuermann; implementation by Florian Tschorsch. o Minor bugfixes: - Change an integer overflow check in the OpenBSD_Malloc code so that GCC is less likely to eliminate it as impossible. Patch from Mansour Moufid. Fixes bug 4059. o Minor bugfixes (usability): - Downgrade log messages about circuit timeout calibration from "notice" to "info": they don't require or suggest any human intervention. Patch from Tom Lowenthal. Fixes bug 4063; bugfix on 0.2.2.14-alpha. o Minor features (diagnostics): - When the system call to create a listener socket fails, log the error message explaining why. This may help diagnose bug 4027. Changes in version 0.2.3.4-alpha - 2011-09-13 Tor 0.2.3.4-alpha includes the fixes from 0.2.2.33, including a slight tweak to Tor's TLS handshake that makes relays and bridges that run this new version reachable from Iran again. It also fixes a few new bugs in 0.2.3.x, and teaches relays to recognize when they're not listed in the network consensus and republish. o Major bugfixes (also part of 0.2.2.33): - Avoid an assertion failure when reloading a configuration with TrackExitHosts changes. Found and fixed by 'laruldan'. Fixes bug 3923; bugfix on 0.2.2.25-alpha. o Minor features (security, also part of 0.2.2.33): - Check for replays of the public-key encrypted portion of an INTRODUCE1 cell, in addition to the current check for replays of the g^x value. This prevents a possible class of active attacks by an attacker who controls both an introduction point and a rendezvous point, and who uses the malleability of AES-CTR to alter the encrypted g^x portion of the INTRODUCE1 cell. We think that these attacks is infeasible (requiring the attacker to send on the order of zettabytes of altered cells in a short interval), but we'd rather block them off in case there are any classes of this attack that we missed. Reported by Willem Pinckaers. o Minor features (also part of 0.2.2.33): - Adjust the expiration time on our SSL session certificates to better match SSL certs seen in the wild. Resolves ticket 4014. - Change the default required uptime for a relay to be accepted as a HSDir (hidden service directory) from 24 hours to 25 hours. Improves on 0.2.0.10-alpha; resolves ticket 2649. - Add a VoteOnHidServDirectoriesV2 config option to allow directory authorities to abstain from voting on assignment of the HSDir consensus flag. Related to bug 2649. - Update to the September 6 2011 Maxmind GeoLite Country database. o Minor bugfixes (also part of 0.2.2.33): - Demote the 'replay detected' log message emitted when a hidden service receives the same Diffie-Hellman public key in two different INTRODUCE2 cells to info level. A normal Tor client can cause that log message during its normal operation. Bugfix on 0.2.1.6-alpha; fixes part of bug 2442. - Demote the 'INTRODUCE2 cell is too {old,new}' log message to info level. There is nothing that a hidden service's operator can do to fix its clients' clocks. Bugfix on 0.2.1.6-alpha; fixes part of bug 2442. - Clarify a log message specifying the characters permitted in HiddenServiceAuthorizeClient client names. Previously, the log message said that "[A-Za-z0-9+-_]" were permitted; that could have given the impression that every ASCII character between "+" and "_" was permitted. Now we say "[A-Za-z0-9+_-]". Bugfix on 0.2.1.5-alpha. o Build fixes (also part of 0.2.2.33): - Clean up some code issues that prevented Tor from building on older BSDs. Fixes bug 3894; reported by "grarpamp". - Search for a platform-specific version of "ar" when cross-compiling. Should fix builds on iOS. Resolves bug 3909, found by Marco Bonetti. o Major bugfixes: - Fix a bug where the SocksPort option (for example) would get ignored and replaced by the default if a SocksListenAddress option was set. Bugfix on 0.2.3.3-alpha; fixes bug 3936. Fix by Fabian Keil. o Major features: - Relays now try regenerating and uploading their descriptor more frequently if they are not listed in the consensus, or if the version of their descriptor listed in the consensus is too old. This fix should prevent situations where a server declines to re-publish itself because it has done so too recently, even though the authorities decided not to list its recent-enough descriptor. Fix for bug 3327. o Minor features: - Relays now include a reason for regenerating their descriptors in an HTTP header when uploading to the authorities. This will make it easier to debug descriptor-upload issues in the future. - When starting as root and then changing our UID via the User control option, and we have a ControlSocket configured, make sure that the ControlSocket is owned by the same account that Tor will run under. Implements ticket 3421; fix by Jérémy Bobbio. o Minor bugfixes: - Abort if tor_vasprintf fails in connection_printf_to_buf (a utility function used in the control-port code). This shouldn't ever happen unless Tor is completely out of memory, but if it did happen and Tor somehow recovered from it, Tor could have sent a log message to a control port in the middle of a reply to a controller command. Fixes part of bug 3428; bugfix on 0.1.2.3-alpha. - Make 'FetchUselessDescriptors' cause all descriptor types and all consensus types (including microdescriptors) to get fetched. Fixes bug 3851; bugfix on 0.2.3.1-alpha. o Code refactoring: - Make a new "entry connection" struct as an internal subtype of "edge connection", to simplify the code and make exit connections smaller. Changes in version 0.2.2.33 - 2011-09-13 Tor 0.2.2.33 fixes several bugs, and includes a slight tweak to Tor's TLS handshake that makes relays and bridges that run this new version reachable from Iran again. o Major bugfixes: - Avoid an assertion failure when reloading a configuration with TrackExitHosts changes. Found and fixed by 'laruldan'. Fixes bug 3923; bugfix on 0.2.2.25-alpha. o Minor features (security): - Check for replays of the public-key encrypted portion of an INTRODUCE1 cell, in addition to the current check for replays of the g^x value. This prevents a possible class of active attacks by an attacker who controls both an introduction point and a rendezvous point, and who uses the malleability of AES-CTR to alter the encrypted g^x portion of the INTRODUCE1 cell. We think that these attacks are infeasible (requiring the attacker to send on the order of zettabytes of altered cells in a short interval), but we'd rather block them off in case there are any classes of this attack that we missed. Reported by Willem Pinckaers. o Minor features: - Adjust the expiration time on our SSL session certificates to better match SSL certs seen in the wild. Resolves ticket 4014. - Change the default required uptime for a relay to be accepted as a HSDir (hidden service directory) from 24 hours to 25 hours. Improves on 0.2.0.10-alpha; resolves ticket 2649. - Add a VoteOnHidServDirectoriesV2 config option to allow directory authorities to abstain from voting on assignment of the HSDir consensus flag. Related to bug 2649. - Update to the September 6 2011 Maxmind GeoLite Country database. o Minor bugfixes (documentation and log messages): - Correct the man page to explain that HashedControlPassword and CookieAuthentication can both be set, in which case either method is sufficient to authenticate to Tor. Bugfix on 0.2.0.7-alpha, when we decided to allow these config options to both be set. Issue raised by bug 3898. - Demote the 'replay detected' log message emitted when a hidden service receives the same Diffie-Hellman public key in two different INTRODUCE2 cells to info level. A normal Tor client can cause that log message during its normal operation. Bugfix on 0.2.1.6-alpha; fixes part of bug 2442. - Demote the 'INTRODUCE2 cell is too {old,new}' log message to info level. There is nothing that a hidden service's operator can do to fix its clients' clocks. Bugfix on 0.2.1.6-alpha; fixes part of bug 2442. - Clarify a log message specifying the characters permitted in HiddenServiceAuthorizeClient client names. Previously, the log message said that "[A-Za-z0-9+-_]" were permitted; that could have given the impression that every ASCII character between "+" and "_" was permitted. Now we say "[A-Za-z0-9+_-]". Bugfix on 0.2.1.5-alpha. o Build fixes: - Provide a substitute implementation of lround() for MSVC, which apparently lacks it. Patch from Gisle Vanem. - Clean up some code issues that prevented Tor from building on older BSDs. Fixes bug 3894; reported by "grarpamp". - Search for a platform-specific version of "ar" when cross-compiling. Should fix builds on iOS. Resolves bug 3909, found by Marco Bonetti. Changes in version 0.2.3.3-alpha - 2011-09-01 Tor 0.2.3.3-alpha adds a new "stream isolation" feature to improve Tor's security, and provides client-side support for the microdescriptor and optimistic data features introduced earlier in the 0.2.3.x series. It also includes numerous critical bugfixes in the (optional) bufferevent-based networking backend. o Major features (stream isolation): - You can now configure Tor so that streams from different applications are isolated on different circuits, to prevent an attacker who sees your streams as they leave an exit node from linking your sessions to one another. To do this, choose some way to distinguish the applications: have them connect to different SocksPorts, or have one of them use SOCKS4 while the other uses SOCKS5, or have them pass different authentication strings to the SOCKS proxy. Then, use the new SocksPort syntax to configure the degree of isolation you need. This implements Proposal 171. - There's a new syntax for specifying multiple client ports (such as SOCKSPort, TransPort, DNSPort, NATDPort): you can now just declare multiple *Port entries with full addr:port syntax on each. The old *ListenAddress format is still supported, but you can't mix it with the new *Port syntax. o Major features (other): - Enable microdescriptor fetching by default for clients. This allows clients to download a much smaller amount of directory information. To disable it (and go back to the old-style consensus and descriptors), set "UseMicrodescriptors 0" in your torrc file. - Tor's firewall-helper feature, introduced in 0.2.3.1-alpha (see the "PortForwarding" config option), now supports Windows. - When using an exit relay running 0.2.3.x, clients can now "optimistically" send data before the exit relay reports that the stream has opened. This saves a round trip when starting connections where the client speaks first (such as web browsing). This behavior is controlled by a consensus parameter (currently disabled). To turn it on or off manually, use the "OptimisticData" torrc option. Implements proposal 181; code by Ian Goldberg. o Major bugfixes (bufferevents, fixes on 0.2.3.1-alpha): - When using IOCP on Windows, we need to enable Libevent windows threading support. - The IOCP backend now works even when the user has not specified the (internal, debugging-only) _UseFilteringSSLBufferevents option. Fixes part of bug 3752. - Correctly record the bytes we've read and written when using bufferevents, so that we can include them in our bandwidth history and advertised bandwidth. Fixes bug 3803. - Apply rate-limiting only at the bottom of a chain of filtering bufferevents. This prevents us from filling up internal read buffers and violating rate-limits when filtering bufferevents are enabled. Fixes part of bug 3804. - Add high-watermarks to the output buffers for filtered bufferevents. This prevents us from filling up internal write buffers and wasting CPU cycles when filtering bufferevents are enabled. Fixes part of bug 3804. - Correctly notice when data has been written from a bufferevent without flushing it completely. Fixes bug 3805. - Fix a bug where server-side tunneled bufferevent-based directory streams would get closed prematurely. Fixes bug 3814. - Fix a use-after-free error with per-connection rate-limiting buckets. Fixes bug 3888. o Major bugfixes (also part of 0.2.2.31-rc): - If we're configured to write our ControlPorts to disk, only write them after switching UID and creating the data directory. This way, we don't fail when starting up with a nonexistent DataDirectory and a ControlPortWriteToFile setting based on that directory. Fixes bug 3747; bugfix on Tor 0.2.2.26-beta. o Minor features: - Added a new CONF_CHANGED event so that controllers can be notified of any configuration changes made by other controllers, or by the user. Implements ticket 1692. - Use evbuffer_copyout() in inspect_evbuffer(). This fixes a memory leak when using bufferevents, and lets Libevent worry about how to best copy data out of a buffer. - Replace files in stats/ rather than appending to them. Now that we include statistics in extra-info descriptors, it makes no sense to keep old statistics forever. Implements ticket 2930. o Minor features (build compatibility): - Limited, experimental support for building with nmake and MSVC. - Provide a substitute implementation of lround() for MSVC, which apparently lacks it. Patch from Gisle Vanem. o Minor features (also part of 0.2.2.31-rc): - Update to the August 2 2011 Maxmind GeoLite Country database. o Minor bugfixes (on 0.2.3.x-alpha): - Fix a spurious warning when parsing SOCKS requests with bufferevents enabled. Fixes bug 3615; bugfix on 0.2.3.2-alpha. - Get rid of a harmless warning that could happen on relays running with bufferevents. The warning was caused by someone doing an http request to a relay's orport. Also don't warn for a few related non-errors. Fixes bug 3700; bugfix on 0.2.3.1-alpha. o Minor bugfixes (on 2.2.x and earlier): - Correct the man page to explain that HashedControlPassword and CookieAuthentication can both be set, in which case either method is sufficient to authenticate to Tor. Bugfix on 0.2.0.7-alpha, when we decided to allow these config options to both be set. Issue raised by bug 3898. - The "--quiet" and "--hush" options now apply not only to Tor's behavior before logs are configured, but also to Tor's behavior in the absense of configured logs. Fixes bug 3550; bugfix on 0.2.0.10-alpha. o Minor bugfixes (also part of 0.2.2.31-rc): - Write several files in text mode, on OSes that distinguish text mode from binary mode (namely, Windows). These files are: 'buffer-stats', 'dirreq-stats', and 'entry-stats' on relays that collect those statistics; 'client_keys' and 'hostname' for hidden services that use authentication; and (in the tor-gencert utility) newly generated identity and signing keys. Previously, we wouldn't specify text mode or binary mode, leading to an assertion failure. Fixes bug 3607. Bugfix on 0.2.1.1-alpha (when the DirRecordUsageByCountry option which would have triggered the assertion failure was added), although this assertion failure would have occurred in tor-gencert on Windows in 0.2.0.1-alpha. - Selectively disable deprecation warnings on OS X because Lion started deprecating the shipped copy of openssl. Fixes bug 3643. - Remove an extra pair of quotation marks around the error message in control-port STATUS_GENERAL BUG events. Bugfix on 0.1.2.6-alpha; fixes bug 3732. - When unable to format an address as a string, report its value as "???" rather than reusing the last formatted address. Bugfix on 0.2.1.5-alpha. o Code simplifications and refactoring: - Rewrite the listener-selection logic so that parsing which ports we want to listen on is now separate from binding to the ports we want. o Build changes: - Building Tor with bufferevent support now requires Libevent 2.0.13-stable or later. Previous versions of Libevent had bugs in SSL-related bufferevents and related issues that would make Tor work badly with bufferevents. Requiring 2.0.13-stable also allows Tor with bufferevents to take advantage of Libevent APIs introduced after 2.0.8-rc. Changes in version 0.2.2.32 - 2011-08-27 The Tor 0.2.2 release series is dedicated to the memory of Andreas Pfitzmann (1958-2010), a pioneer in anonymity and privacy research, a founder of the PETS community, a leader in our field, a mentor, and a friend. He left us with these words: "I had the possibility to contribute to this world that is not as it should be. I hope I could help in some areas to make the world a better place, and that I could also encourage other people to be engaged in improving the world. Please, stay engaged. This world needs you, your love, your initiative -- now I cannot be part of that anymore." Tor 0.2.2.32, the first stable release in the 0.2.2 branch, is finally ready. More than two years in the making, this release features improved client performance and hidden service reliability, better compatibility for Android, correct behavior for bridges that listen on more than one address, more extensible and flexible directory object handling, better reporting of network statistics, improved code security, and many many other features and bugfixes. Changes in version 0.2.2.31-rc - 2011-08-17 Tor 0.2.2.31-rc is the second and hopefully final release candidate for the Tor 0.2.2.x series. o Major bugfixes: - Remove an extra pair of quotation marks around the error message in control-port STATUS_GENERAL BUG events. Bugfix on 0.1.2.6-alpha; fixes bug 3732. - If we're configured to write our ControlPorts to disk, only write them after switching UID and creating the data directory. This way, we don't fail when starting up with a nonexistent DataDirectory and a ControlPortWriteToFile setting based on that directory. Fixes bug 3747; bugfix on Tor 0.2.2.26-beta. o Minor features: - Update to the August 2 2011 Maxmind GeoLite Country database. o Minor bugfixes: - Allow GETINFO fingerprint to return a fingerprint even when we have not yet built a router descriptor. Fixes bug 3577; bugfix on 0.2.0.1-alpha. - Write several files in text mode, on OSes that distinguish text mode from binary mode (namely, Windows). These files are: 'buffer-stats', 'dirreq-stats', and 'entry-stats' on relays that collect those statistics; 'client_keys' and 'hostname' for hidden services that use authentication; and (in the tor-gencert utility) newly generated identity and signing keys. Previously, we wouldn't specify text mode or binary mode, leading to an assertion failure. Fixes bug 3607. Bugfix on 0.2.1.1-alpha (when the DirRecordUsageByCountry option which would have triggered the assertion failure was added), although this assertion failure would have occurred in tor-gencert on Windows in 0.2.0.1-alpha. - Selectively disable deprecation warnings on OS X because Lion started deprecating the shipped copy of openssl. Fixes bug 3643. - When unable to format an address as a string, report its value as "???" rather than reusing the last formatted address. Bugfix on 0.2.1.5-alpha. Changes in version 0.2.3.2-alpha - 2011-07-18 Tor 0.2.3.2-alpha introduces two new experimental features: microdescriptors and pluggable transports. It also continues cleaning up a variety of recently introduced features. o Major features: - Clients can now use microdescriptors instead of regular descriptors to build circuits. Microdescriptors are authority-generated summaries of regular descriptors' contents, designed to change very rarely (see proposal 158 for details). This feature is designed to save bandwidth, especially for clients on slow internet connections. It's off by default for now, since nearly no caches support it, but it will be on-by-default for clients in a future version. You can use the UseMicrodescriptors option to turn it on. - Tor clients using bridges can now be configured to use a separate 'transport' proxy for each bridge. This approach helps to resist censorship by allowing bridges to use protocol obfuscation plugins. It implements part of proposal 180. Implements ticket 2841. - While we're trying to bootstrap, record how many TLS connections fail in each state, and report which states saw the most failures in response to any bootstrap failures. This feature may speed up diagnosis of censorship events. Implements ticket 3116. o Major bugfixes (on 0.2.3.1-alpha): - When configuring a large set of nodes in EntryNodes (as with 'EntryNodes {cc}' or 'EntryNodes 1.1.1.1/16'), choose only a random subset to be guards, and choose them in random order. Fixes bug 2798. - Tor could crash when remembering a consensus in a non-used consensus flavor without having a current consensus set. Fixes bug 3361. - Comparing an unknown address to a microdescriptor's shortened exit policy would always give a "rejected" result. Fixes bug 3599. - Using microdescriptors as a client no longer prevents Tor from uploading and downloading hidden service descriptors. Fixes bug 3601. o Minor features: - Allow nameservers with IPv6 address. Resolves bug 2574. - Accept attempts to include a password authenticator in the handshake, as supported by SOCKS5. This handles SOCKS clients that don't know how to omit a password when authenticating. Resolves bug 1666. - When configuring a large set of nodes in EntryNodes, and there are enough of them listed as Guard so that we don't need to consider the non-guard entries, prefer the ones listed with the Guard flag. - Check for and recover from inconsistency in the microdescriptor cache. This will make it harder for us to accidentally free a microdescriptor without removing it from the appropriate data structures. Fixes issue 3135; issue noted by "wanoskarnet". - Log SSL state transitions at log level DEBUG, log domain HANDSHAKE. This can be useful for debugging censorship events. Implements ticket 3264. - Add port 6523 (Gobby) to LongLivedPorts. Patch by intrigeri; implements ticket 3439. o Minor bugfixes (on 0.2.3.1-alpha): - Do not free all general-purpose regular descriptors just because microdescriptor use is enabled. Fixes bug 3113. - Correctly link libevent_openssl when --enable-static-libevent is passed to configure. Fixes bug 3118. - Bridges should not complain during their heartbeat log messages that they are unlisted in the consensus: that's more or less the point of being a bridge. Fixes bug 3183. - Report a SIGNAL event to controllers when acting on a delayed SIGNAL NEWNYM command. Previously, we would report a SIGNAL event to the controller if we acted on a SIGNAL NEWNYM command immediately, and otherwise not report a SIGNAL event for the command at all. Fixes bug 3349. - Fix a crash when handling the SIGNAL controller command or reporting ERR-level status events with bufferevents enabled. Found by Robert Ransom. Fixes bug 3367. - Always ship the tor-fw-helper manpage in our release tarballs. Fixes bug 3389. Reported by Stephen Walker. - Fix a class of double-mark-for-close bugs when bufferevents are enabled. Fixes bug 3403. - Update tor-fw-helper to support libnatpmp-20110618. Fixes bug 3434. - Add SIGNAL to the list returned by the 'GETINFO events/names' control-port command. Fixes part of bug 3465. - Prevent using negative indices during unit test runs when read_all() fails. Spotted by coverity. - Fix a rare memory leak when checking the nodelist without it being present. Found by coverity. - Only try to download a microdescriptor-flavored consensus from a directory cache that provides them. o Minor bugfixes (on 0.2.2.x and earlier): - Assert that hidden-service-related operations are not performed using single-hop circuits. Previously, Tor would assert that client-side streams are not attached to single-hop circuits, but not that other sensitive operations on the client and service side are not performed using single-hop circuits. Fixes bug 3332; bugfix on 0.0.6. - Don't publish a new relay descriptor when we reload our onion key, unless the onion key has actually changed. Fixes bug 3263 and resolves another cause of bug 1810. Bugfix on 0.1.1.11-alpha. - Allow GETINFO fingerprint to return a fingerprint even when we have not yet built a router descriptor. Fixes bug 3577; bugfix on 0.2.0.1-alpha. - Make 'tor --digests' list hashes of all Tor source files. Bugfix on 0.2.2.4-alpha; fixes bug 3427. o Code simplification and refactoring: - Use tor_sscanf() in place of scanf() in more places through the code. This makes us a little more locale-independent, and should help shut up code-analysis tools that can't tell a safe sscanf string from a dangerous one. - Use tt_assert(), not tor_assert(), for checking for test failures. This makes the unit tests more able to go on in the event that one of them fails. - Split connection_about_to_close() into separate functions for each connection type. o Build changes: - On Windows, we now define the _WIN32_WINNT macros only if they are not already defined. This lets the person building Tor decide, if they want, to require a later version of Windows. Changes in version 0.2.2.30-rc - 2011-07-07 Tor 0.2.2.30-rc is the first release candidate for the Tor 0.2.2.x series. It fixes a few smaller bugs, but generally appears stable. Please test it and let us know whether it is! o Minor bugfixes: - Send a SUCCEEDED stream event to the controller when a reverse resolve succeeded. Fixes bug 3536; bugfix on 0.0.8pre1. Issue discovered by katmagic. - Always NUL-terminate the sun_path field of a sockaddr_un before passing it to the kernel. (Not a security issue: kernels are smart enough to reject bad sockaddr_uns.) Found by Coverity; CID #428. Bugfix on Tor 0.2.0.3-alpha. - Don't stack-allocate the list of supplementary GIDs when we're about to log them. Stack-allocating NGROUPS_MAX gid_t elements could take up to 256K, which is way too much stack. Found by Coverity; CID #450. Bugfix on 0.2.1.7-alpha. - Add BUILDTIMEOUT_SET to the list returned by the 'GETINFO events/names' control-port command. Bugfix on 0.2.2.9-alpha; fixes part of bug 3465. - Fix a memory leak when receiving a descriptor for a hidden service we didn't ask for. Found by Coverity; CID #30. Bugfix on 0.2.2.26-beta. o Minor features: - Update to the July 1 2011 Maxmind GeoLite Country database. Changes in version 0.2.2.29-beta - 2011-06-20 Tor 0.2.2.29-beta reverts an accidental behavior change for users who have bridge lines in their torrc but don't want to use them; gets us closer to having the control socket feature working on Debian; and fixes a variety of smaller bugs. o Major bugfixes: - Revert the UseBridges option to its behavior before 0.2.2.28-beta. When we changed the default behavior to "use bridges if any are listed in the torrc", we surprised users who had bridges in their torrc files but who didn't actually want to use them. Partial resolution for bug 3354. o Privacy fixes: - Don't attach new streams to old rendezvous circuits after SIGNAL NEWNYM. Previously, we would keep using an existing rendezvous circuit if it remained open (i.e. if it were kept open by a long-lived stream, or if a new stream were attached to it before Tor could notice that it was old and no longer in use). Bugfix on 0.1.1.15-rc; fixes bug 3375. o Minor bugfixes: - Fix a bug when using ControlSocketsGroupWritable with User. The directory's group would be checked against the current group, not the configured group. Patch by Jérémy Bobbio. Fixes bug 3393; bugfix on 0.2.2.26-beta. - Make connection_printf_to_buf()'s behaviour sane. Its callers expect it to emit a CRLF iff the format string ends with CRLF; it actually emitted a CRLF iff (a) the format string ended with CRLF or (b) the resulting string was over 1023 characters long or (c) the format string did not end with CRLF *and* the resulting string was 1021 characters long or longer. Bugfix on 0.1.1.9-alpha; fixes part of bug 3407. - Make send_control_event_impl()'s behaviour sane. Its callers expect it to always emit a CRLF at the end of the string; it might have emitted extra control characters as well. Bugfix on 0.1.1.9-alpha; fixes another part of bug 3407. - Make crypto_rand_int() check the value of its input correctly. Previously, it accepted values up to UINT_MAX, but could return a negative number if given a value above INT_MAX+1. Found by George Kadianakis. Fixes bug 3306; bugfix on 0.2.2pre14. - Avoid a segfault when reading a malformed circuit build state with more than INT_MAX entries. Found by wanoskarnet. Bugfix on 0.2.2.4-alpha. - When asked about a DNS record type we don't support via a client DNSPort, reply with NOTIMPL rather than an empty reply. Patch by intrigeri. Fixes bug 3369; bugfix on 2.0.1-alpha. - Fix a rare memory leak during stats writing. Found by coverity. o Minor features: - Update to the June 1 2011 Maxmind GeoLite Country database. o Code simplifications and refactoring: - Remove some dead code as indicated by coverity. - Remove a few dead assignments during router parsing. Found by coverity. - Add some forgotten return value checks during unit tests. Found by coverity. - Don't use 1-bit wide signed bit fields. Found by coverity. Changes in version 0.2.2.28-beta - 2011-06-04 Tor 0.2.2.28-beta makes great progress towards a new stable release: we fixed a big bug in whether relays stay in the consensus consistently, we moved closer to handling bridges and hidden services correctly, and we started the process of better handling the dreaded "my Vidalia died, and now my Tor demands a password when I try to reconnect to it" usability issue. o Major bugfixes: - Don't decide to make a new descriptor when receiving a HUP signal. This bug has caused a lot of 0.2.2.x relays to disappear from the consensus periodically. Fixes the most common case of triggering bug 1810; bugfix on 0.2.2.7-alpha. - Actually allow nameservers with IPv6 addresses. Fixes bug 2574. - Don't try to build descriptors if "ORPort auto" is set and we don't know our actual ORPort yet. Fix for bug 3216; bugfix on 0.2.2.26-beta. - Resolve a crash that occurred when setting BridgeRelay to 1 with accounting enabled. Fixes bug 3228; bugfix on 0.2.2.18-alpha. - Apply circuit timeouts to opened hidden-service-related circuits based on the correct start time. Previously, we would apply the circuit build timeout based on time since the circuit's creation; it was supposed to be applied based on time since the circuit entered its current state. Bugfix on 0.0.6; fixes part of bug 1297. - Use the same circuit timeout for client-side introduction circuits as for other four-hop circuits, rather than the timeout for single-hop directory-fetch circuits; the shorter timeout may have been appropriate with the static circuit build timeout in 0.2.1.x and earlier, but caused many hidden service access attempts to fail with the adaptive CBT introduced in 0.2.2.2-alpha. Bugfix on 0.2.2.2-alpha; fixes another part of bug 1297. - In ticket 2511 we fixed a case where you could use an unconfigured bridge if you had configured it as a bridge the last time you ran Tor. Now fix another edge case: if you had configured it as a bridge but then switched to a different bridge via the controller, you would still be willing to use the old one. Bugfix on 0.2.0.1-alpha; fixes bug 3321. o Major features: - Add an __OwningControllerProcess configuration option and a TAKEOWNERSHIP control-port command. Now a Tor controller can ensure that when it exits, Tor will shut down. Implements feature 3049. - If "UseBridges 1" is set and no bridges are configured, Tor will now refuse to build any circuits until some bridges are set. If "UseBridges auto" is set, Tor will use bridges if they are configured and we are not running as a server, but otherwise will make circuits as usual. The new default is "auto". Patch by anonym, so the Tails LiveCD can stop automatically revealing you as a Tor user on startup. o Minor bugfixes: - Fix warnings from GCC 4.6's "-Wunused-but-set-variable" option. - Remove a trailing asterisk from "exit-policy/default" in the output of the control port command "GETINFO info/names". Bugfix on 0.1.2.5-alpha. - Use a wide type to hold sockets when built for 64-bit Windows builds. Fixes bug 3270. - Warn when the user configures two HiddenServiceDir lines that point to the same directory. Bugfix on 0.0.6 (the version introducing HiddenServiceDir); fixes bug 3289. - Remove dead code from rend_cache_lookup_v2_desc_as_dir. Fixes part of bug 2748; bugfix on 0.2.0.10-alpha. - Log malformed requests for rendezvous descriptors as protocol warnings, not warnings. Also, use a more informative log message in case someone sees it at log level warning without prior info-level messages. Fixes the other part of bug 2748; bugfix on 0.2.0.10-alpha. - Clear the table recording the time of the last request for each hidden service descriptor from each HS directory on SIGNAL NEWNYM. Previously, we would clear our HS descriptor cache on SIGNAL NEWNYM, but if we had previously retrieved a descriptor (or tried to) from every directory responsible for it, we would refuse to fetch it again for up to 15 minutes. Bugfix on 0.2.2.25-alpha; fixes bug 3309. - Fix a log message that said "bits" while displaying a value in bytes. Found by wanoskarnet. Fixes bug 3318; bugfix on 0.2.0.1-alpha. - When checking for 1024-bit keys, check for 1024 bits, not 128 bytes. This allows Tor to correctly discard keys of length 1017 through 1023. Bugfix on 0.0.9pre5. o Minor features: - Relays now log the reason for publishing a new relay descriptor, so we have a better chance of hunting down instances of bug 1810. Resolves ticket 3252. - Revise most log messages that refer to nodes by nickname to instead use the "$key=nickname at address" format. This should be more useful, especially since nicknames are less and less likely to be unique. Resolves ticket 3045. - Log (at info level) when purging pieces of hidden-service-client state because of SIGNAL NEWNYM. o Removed options: - Remove undocumented option "-F" from tor-resolve: it hasn't done anything since 0.2.1.16-rc. Changes in version 0.2.2.27-beta - 2011-05-18 Tor 0.2.2.27-beta fixes a bridge-related stability bug in the previous release, and also adds a few more general bugfixes. o Major bugfixes: - Fix a crash bug when changing bridges in a running Tor process. Fixes bug 3213; bugfix on 0.2.2.26-beta. - When the controller configures a new bridge, don't wait 10 to 60 seconds before trying to fetch its descriptor. Bugfix on 0.2.0.3-alpha; fixes bug 3198 (suggested by 2355). o Minor bugfixes: - Require that onion keys have exponent 65537 in microdescriptors too. Fixes more of bug 3207; bugfix on 0.2.2.26-beta. - Tor used to limit HttpProxyAuthenticator values to 48 characters. Changed the limit to 512 characters by removing base64 newlines. Fixes bug 2752. Fix by Michael Yakubovich. - When a client starts or stops using bridges, never use a circuit that was built before the configuration change. This behavior could put at risk a user who uses bridges to ensure that her traffic only goes to the chosen addresses. Bugfix on 0.2.0.3-alpha; fixes bug 3200. Changes in version 0.2.2.26-beta - 2011-05-17 Tor 0.2.2.26-beta fixes a variety of potential privacy problems. It also introduces a new "socksport auto" approach that should make it easier to run multiple Tors on the same system, and does a lot of cleanup to get us closer to a release candidate. o Security/privacy fixes: - Replace all potentially sensitive memory comparison operations with versions whose runtime does not depend on the data being compared. This will help resist a class of attacks where an adversary can use variations in timing information to learn sensitive data. Fix for one case of bug 3122. (Safe memcmp implementation by Robert Ransom based partially on code by DJB.) - When receiving a hidden service descriptor, check that it is for the hidden service we wanted. Previously, Tor would store any hidden service descriptors that a directory gave it, whether it wanted them or not. This wouldn't have let an attacker impersonate a hidden service, but it did let directories pre-seed a client with descriptors that it didn't want. Bugfix on 0.0.6. - On SIGHUP, do not clear out all TrackHostExits mappings, client DNS cache entries, and virtual address mappings: that's what NEWNYM is for. Fixes bug 1345; bugfix on 0.1.0.1-rc. o Major features: - The options SocksPort, ControlPort, and so on now all accept a value "auto" that opens a socket on an OS-selected port. A new ControlPortWriteToFile option tells Tor to write its actual control port or ports to a chosen file. If the option ControlPortFileGroupReadable is set, the file is created as group-readable. Now users can run two Tor clients on the same system without needing to manually mess with parameters. Resolves part of ticket 3076. - Set SO_REUSEADDR on all sockets, not just listeners. This should help busy exit nodes avoid running out of useable ports just because all the ports have been used in the near past. Resolves issue 2850. o Minor features: - New "GETINFO net/listeners/(type)" controller command to return a list of addresses and ports that are bound for listeners for a given connection type. This is useful when the user has configured "SocksPort auto" and the controller needs to know which port got chosen. Resolves another part of ticket 3076. - Add a new ControlSocketsGroupWritable configuration option: when it is turned on, ControlSockets are group-writeable by the default group of the current user. Patch by Jérémy Bobbio; implements ticket 2972. - Tor now refuses to create a ControlSocket in a directory that is world-readable (or group-readable if ControlSocketsGroupWritable is 0). This is necessary because some operating systems do not enforce permissions on an AF_UNIX sockets. Permissions on the directory holding the socket, however, seems to work everywhere. - Rate-limit a warning about failures to download v2 networkstatus documents. Resolves part of bug 1352. - Backport code from 0.2.3.x that allows directory authorities to clean their microdescriptor caches. Needed to resolve bug 2230. - When an HTTPS proxy reports "403 Forbidden", we now explain what it means rather than calling it an unexpected status code. Closes bug 2503. Patch from Michael Yakubovich. - Update to the May 1 2011 Maxmind GeoLite Country database. o Minor bugfixes: - Authorities now clean their microdesc cache periodically and when reading from disk initially, not only when adding new descriptors. This prevents a bug where we could lose microdescriptors. Bugfix on 0.2.2.6-alpha. Fixes bug 2230. - Do not crash when our configuration file becomes unreadable, for example due to a permissions change, between when we start up and when a controller calls SAVECONF. Fixes bug 3135; bugfix on 0.0.9pre6. - Avoid a bug that would keep us from replacing a microdescriptor cache on Windows. (We would try to replace the file while still holding it open. That's fine on Unix, but Windows doesn't let us do that.) Bugfix on 0.2.2.6-alpha; bug found by wanoskarnet. - Add missing explanations for the authority-related torrc options RephistTrackTime, BridgePassword, and V3AuthUseLegacyKey in the man page. Resolves issue 2379. - As an authority, do not upload our own vote or signature set to ourself. It would tell us nothing new, and as of 0.2.2.24-alpha, it would get flagged as a duplicate. Resolves bug 3026. - Accept hidden service descriptors if we think we might be a hidden service directory, regardless of what our consensus says. This helps robustness, since clients and hidden services can sometimes have a more up-to-date view of the network consensus than we do, and if they think that the directory authorities list us a HSDir, we might actually be one. Related to bug 2732; bugfix on 0.2.0.10-alpha. - When a controller changes TrackHostExits, remove mappings for hosts that should no longer have their exits tracked. Bugfix on 0.1.0.1-rc. - When a controller changes VirtualAddrNetwork, remove any mappings for hosts that were automapped to the old network. Bugfix on 0.1.1.19-rc. - When a controller changes one of the AutomapHosts* options, remove any mappings for hosts that should no longer be automapped. Bugfix on 0.2.0.1-alpha. - Do not reset the bridge descriptor download status every time we re-parse our configuration or get a configuration change. Fixes bug 3019; bugfix on 0.2.0.3-alpha. o Minor bugfixes (code cleanup): - When loading the microdesc journal, remember its current size. In 0.2.2, this helps prevent the microdesc journal from growing without limit on authorities (who are the only ones to use it in 0.2.2). Fixes a part of bug 2230; bugfix on 0.2.2.6-alpha. Fix posted by "cypherpunks." - The microdesc journal is supposed to get rebuilt only if it is at least _half_ the length of the store, not _twice_ the length of the store. Bugfix on 0.2.2.6-alpha; fixes part of bug 2230. - Fix a potential null-pointer dereference while computing a consensus. Bugfix on tor-0.2.0.3-alpha, found with the help of clang's analyzer. - Avoid a possible null-pointer dereference when rebuilding the mdesc cache without actually having any descriptors to cache. Bugfix on 0.2.2.6-alpha. Issue discovered using clang's static analyzer. - If we fail to compute the identity digest of a v3 legacy keypair, warn, and don't use a buffer-full of junk instead. Bugfix on 0.2.1.1-alpha; fixes bug 3106. - Resolve an untriggerable issue in smartlist_string_num_isin(), where if the function had ever in the future been used to check for the presence of a too-large number, it would have given an incorrect result. (Fortunately, we only used it for 16-bit values.) Fixes bug 3175; bugfix on 0.1.0.1-rc. - Require that introduction point keys and onion handshake keys have a public exponent of 65537. Starts to fix bug 3207; bugfix on 0.2.0.10-alpha. o Removed features: - Caches no longer download and serve v2 networkstatus documents unless FetchV2Networkstatus flag is set: these documents haven't haven't been used by clients or relays since 0.2.0.x. Resolves bug 3022. Changes in version 0.2.3.1-alpha - 2011-05-05 Tor 0.2.3.1-alpha adds some new experimental features, including support for an improved network IO backend, IOCP networking on Windows, microdescriptor caching, "fast-start" support for streams, and automatic home router configuration. There are also numerous internal improvements to try to make the code easier for developers to work with. This is the first alpha release in a new series, so expect there to be bugs. Users who would rather test out a more stable branch should stay with 0.2.2.x for now. o Major features: - Tor can now optionally build with the "bufferevents" buffered IO backend provided by Libevent 2. To use this feature, make sure you have the latest possible version of Libevent, and pass the --enable-bufferevents flag to configure when building Tor from source. This feature will make our networking code more flexible, let us stack layers on each other, and let us use more efficient zero-copy transports where available. - As an experimental feature, Tor can use IOCP for networking on Windows. Once this code is tuned and optimized, it promises much better performance than the select-based backend we've used in the past. To try this feature, you must build Tor with Libevent 2, configure Tor with the "bufferevents" buffered IO backend, and add "DisableIOCP 0" to your torrc. There are known bugs here: only try this if you can help debug it as it breaks. - The EntryNodes option can now include country codes like {de} or IP addresses or network masks. Previously we had disallowed these options because we didn't have an efficient way to keep the list up to date. Fixes bug 1982, but see bug 2798 for an unresolved issue here. - Exit nodes now accept and queue data on not-yet-connected streams. Previously, the client wasn't allowed to send data until the stream was connected, which slowed down all connections. This change will enable clients to perform a "fast-start" on streams and send data without having to wait for a confirmation that the stream has opened. (Patch from Ian Goldberg; implements the server side of Proposal 174.) - Tor now has initial support for automatic port mapping on the many home routers that support NAT-PMP or UPnP. (Not yet supported on Windows). To build the support code, you'll need to have libnatpnp library and/or the libminiupnpc library, and you'll need to enable the feature specifically by passing "--enable-upnp" and/or "--enable-natpnp" to configure. To turn it on, use the new PortForwarding option. - Caches now download, cache, and serve multiple "flavors" of the consensus, including a flavor that describes microdescriptors. - Caches now download, cache, and serve microdescriptors -- small summaries of router descriptors that are authenticated by all of the directory authorities. Once enough caches are running this code, clients will be able to save significant amounts of directory bandwidth by downloading microdescriptors instead of router descriptors. o Minor features: - Make logging resolution configurable with a new LogTimeGranularity option, and change the default from 1 millisecond to 1 second. Implements enhancement 1668. - We log which torrc file we're using on startup. Implements ticket 2444. - Ordinarily, Tor does not count traffic from private addresses (like 127.0.0.1 or 10.0.0.1) when calculating rate limits or accounting. There is now a new option, CountPrivateBandwidth, to disable this behavior. Patch from Daniel Cagara. - New --enable-static-tor configure option for building Tor as statically as possible. Idea, general hackery and thoughts from Alexei Czeskis, John Gilmore, Jacob Appelbaum. Implements ticket 2702. - If you set the NumCPUs option to 0, Tor will now try to detect how many CPUs you have. This is the new default behavior. - Turn on directory request statistics by default and include them in extra-info descriptors. Don't break if we have no GeoIP database. - Relays that set "ConnDirectionStatistics 1" write statistics on the bidirectional use of connections to disk every 24 hours. - Add a GeoIP file digest to the extra-info descriptor. Implements enhancement 1883. - The NodeFamily option -- which let you declare that you want to consider nodes to be part of a family whether they list themselves that way or not -- now allows IP address ranges and country codes. - Add a new 'Heartbeat' log message type to periodically log a message describing Tor's status at level Notice. This feature is meant for operators who log at notice, and want to make sure that their Tor server is still working. Implementation by George Kadianakis. o Minor bugfixes (on 0.2.2.25-alpha): - When loading the microdesc journal, remember its current size. In 0.2.2, this helps prevent the microdesc journal from growing without limit on authorities (who are the only ones to use it in 0.2.2). Fixes a part of bug 2230; bugfix on 0.2.2.6-alpha. Fix posted by "cypherpunks." - The microdesc journal is supposed to get rebuilt only if it is at least _half_ the length of the store, not _twice_ the length of the store. Bugfix on 0.2.2.6-alpha; fixes part of bug 2230. - If as an authority we fail to compute the identity digest of a v3 legacy keypair, warn, and don't use a buffer-full of junk instead. Bugfix on 0.2.1.1-alpha; fixes bug 3106. - Authorities now clean their microdesc cache periodically and when reading from disk initially, not only when adding new descriptors. This prevents a bug where we could lose microdescriptors. Bugfix on 0.2.2.6-alpha. o Minor features (controller): - Add a new SIGNAL event to the controller interface so that controllers can be notified when Tor handles a signal. Resolves issue 1955. Patch by John Brooks. - Add a new GETINFO option to get total bytes read and written. Patch from pipe, revised by atagar. Resolves ticket 2345. - Implement some GETINFO controller fields to provide information about the Tor process's pid, euid, username, and resource limits. o Build changes: - Our build system requires automake 1.6 or later to create the Makefile.in files. Previously, you could have used 1.4. This only affects developers and people building Tor from git; people who build Tor from the source distribution without changing the Makefile.am files should be fine. - Our autogen.sh script uses autoreconf to launch autoconf, automake, and so on. This is more robust against some of the failure modes associated with running the autotools pieces on their own. o Minor packaging issues: - On OpenSUSE, create the /var/run/tor directory on startup if it is not already created. Patch from Andreas Stieger. Fixes bug 2573. o Code simplifications and refactoring: - A major revision to our internal node-selecting and listing logic. Tor already had at least two major ways to look at the question of "which Tor servers do we know about": a list of router descriptors, and a list of entries in the current consensus. With microdescriptors, we're adding a third. Having so many systems without an abstraction layer over them was hurting the codebase. Now, we have a new "node_t" abstraction that presents a consistent interface to a client's view of a Tor node, and holds (nearly) all of the mutable state formerly in routerinfo_t and routerstatus_t. - The helper programs tor-gencert, tor-resolve, and tor-checkkey no longer link against Libevent: they never used it, but our library structure used to force them to link it. o Removed features: - Remove some old code to work around even older versions of Tor that used forked processes to handle DNS requests. Such versions of Tor are no longer in use as servers. o Documentation fixes: - Correct a broken faq link in the INSTALL file. Fixes bug 2307. - Add missing documentation for the authority-related torrc options RephistTrackTime, BridgePassword, and V3AuthUseLegacyKey. Resolves issue 2379. Changes in version 0.2.2.25-alpha - 2011-04-29 Tor 0.2.2.25-alpha fixes many bugs: hidden service clients are more robust, routers no longer overreport their bandwidth, Win7 should crash a little less, and NEWNYM (as used by Vidalia's "new identity" button) now prevents hidden service-related activity from being linkable. It provides more information to Vidalia so you can see if your bridge is working. Also, 0.2.2.25-alpha revamps the Entry/Exit/ExcludeNodes and StrictNodes configuration options to make them more reliable, more understandable, and more regularly applied. If you use those options, please see the revised documentation for them in the manual page. o Major bugfixes: - Relays were publishing grossly inflated bandwidth values because they were writing their state files wrong--now they write the correct value. Also, resume reading bandwidth history from the state file correctly. Fixes bug 2704; bugfix on 0.2.2.23-alpha. - Improve hidden service robustness: When we find that we have extended a hidden service's introduction circuit to a relay not listed as an introduction point in the HS descriptor we currently have, retry with an introduction point from the current descriptor. Previously we would just give up. Fixes bugs 1024 and 1930; bugfix on 0.2.0.10-alpha. - Clients now stop trying to use an exit node associated with a given destination by TrackHostExits if they fail to reach that exit node. Fixes bug 2999. Bugfix on 0.2.0.20-rc. - Fix crash bug on platforms where gmtime and localtime can return NULL. Windows 7 users were running into this one. Fixes part of bug 2077. Bugfix on all versions of Tor. Found by boboper. o Security and stability fixes: - Don't double-free a parsable, but invalid, microdescriptor, even if it is followed in the blob we're parsing by an unparsable microdescriptor. Fixes an issue reported in a comment on bug 2954. Bugfix on 0.2.2.6-alpha; fix by "cypherpunks". - If the Nickname configuration option isn't given, Tor would pick a nickname based on the local hostname as the nickname for a relay. Because nicknames are not very important in today's Tor and the "Unnamed" nickname has been implemented, this is now problematic behavior: It leaks information about the hostname without being useful at all. Fixes bug 2979; bugfix on 0.1.2.2-alpha, which introduced the Unnamed nickname. Reported by tagnaq. - Fix an uncommon assertion failure when running with DNSPort under heavy load. Fixes bug 2933; bugfix on 0.2.0.1-alpha. - Avoid linkability based on cached hidden service descriptors: forget all hidden service descriptors cached as a client when processing a SIGNAL NEWNYM command. Fixes bug 3000; bugfix on 0.0.6. o Major features: - Export GeoIP information on bridge usage to controllers even if we have not yet been running for 24 hours. Now Vidalia bridge operators can get more accurate and immediate feedback about their contributions to the network. o Major features and bugfixes (node selection): - Revise and reconcile the meaning of the ExitNodes, EntryNodes, ExcludeEntryNodes, ExcludeExitNodes, ExcludeNodes, and StrictNodes options. Previously, we had been ambiguous in describing what counted as an "exit" node, and what operations exactly "StrictNodes 0" would permit. This created confusion when people saw nodes built through unexpected circuits, and made it hard to tell real bugs from surprises. Now the intended behavior is: . "Exit", in the context of ExitNodes and ExcludeExitNodes, means a node that delivers user traffic outside the Tor network. . "Entry", in the context of EntryNodes, means a node used as the first hop of a multihop circuit. It doesn't include direct connections to directory servers. . "ExcludeNodes" applies to all nodes. . "StrictNodes" changes the behavior of ExcludeNodes only. When StrictNodes is set, Tor should avoid all nodes listed in ExcludeNodes, even when it will make user requests fail. When StrictNodes is *not* set, then Tor should follow ExcludeNodes whenever it can, except when it must use an excluded node to perform self-tests, connect to a hidden service, provide a hidden service, fulfill a .exit request, upload directory information, or fetch directory information. Collectively, the changes to implement the behavior fix bug 1090. - ExcludeNodes now takes precedence over EntryNodes and ExitNodes: if a node is listed in both, it's treated as excluded. - ExcludeNodes now applies to directory nodes -- as a preference if StrictNodes is 0, or an absolute requirement if StrictNodes is 1. Don't exclude all the directory authorities and set StrictNodes to 1 unless you really want your Tor to break. - ExcludeNodes and ExcludeExitNodes now override exit enclaving. - ExcludeExitNodes now overrides .exit requests. - We don't use bridges listed in ExcludeNodes. - When StrictNodes is 1: . We now apply ExcludeNodes to hidden service introduction points and to rendezvous points selected by hidden service users. This can make your hidden service less reliable: use it with caution! . If we have used ExcludeNodes on ourself, do not try relay reachability self-tests. . If we have excluded all the directory authorities, we will not even try to upload our descriptor if we're a relay. . Do not honor .exit requests to an excluded node. - Remove a misfeature that caused us to ignore the Fast/Stable flags when ExitNodes is set. Bugfix on 0.2.2.7-alpha. - When the set of permitted nodes changes, we now remove any mappings introduced via TrackExitHosts to now-excluded nodes. Bugfix on 0.1.0.1-rc. - We never cannibalize a circuit that had excluded nodes on it, even if StrictNodes is 0. Bugfix on 0.1.0.1-rc. - Revert a change where we would be laxer about attaching streams to circuits than when building the circuits. This was meant to prevent a set of bugs where streams were never attachable, but our improved code here should make this unnecessary. Bugfix on 0.2.2.7-alpha. - Keep track of how many times we launch a new circuit to handle a given stream. Too many launches could indicate an inconsistency between our "launch a circuit to handle this stream" logic and our "attach this stream to one of the available circuits" logic. - Improve log messages related to excluded nodes. o Minor bugfixes: - Fix a spurious warning when moving from a short month to a long month on relays with month-based BandwidthAccounting. Bugfix on 0.2.2.17-alpha; fixes bug 3020. - When a client finds that an origin circuit has run out of 16-bit stream IDs, we now mark it as unusable for new streams. Previously, we would try to close the entire circuit. Bugfix on 0.0.6. - Add a forgotten cast that caused a compile warning on OS X 10.6. Bugfix on 0.2.2.24-alpha. - Be more careful about reporting the correct error from a failed connect() system call. Under some circumstances, it was possible to look at an incorrect value for errno when sending the end reason. Bugfix on 0.1.0.1-rc. - Correctly handle an "impossible" overflow cases in connection byte counting, where we write or read more than 4GB on an edge connection in a single second. Bugfix on 0.1.2.8-beta. - Correct the warning displayed when a rendezvous descriptor exceeds the maximum size. Fixes bug 2750; bugfix on 0.2.1.5-alpha. Found by John Brooks. - Clients and hidden services now use HSDir-flagged relays for hidden service descriptor downloads and uploads even if the relays have no DirPort set and the client has disabled TunnelDirConns. This will eventually allow us to give the HSDir flag to relays with no DirPort. Fixes bug 2722; bugfix on 0.2.1.6-alpha. - Downgrade "no current certificates known for authority" message from Notice to Info. Fixes bug 2899; bugfix on 0.2.0.10-alpha. - Make the SIGNAL DUMP control-port command work on FreeBSD. Fixes bug 2917. Bugfix on 0.1.1.1-alpha. - Only limit the lengths of single HS descriptors, even when multiple HS descriptors are published to an HSDir relay in a single POST operation. Fixes bug 2948; bugfix on 0.2.1.5-alpha. Found by hsdir. - Write the current time into the LastWritten line in our state file, rather than the time from the previous write attempt. Also, stop trying to use a time of -1 in our log statements. Fixes bug 3039; bugfix on 0.2.2.14-alpha. - Be more consistent in our treatment of file system paths. "~" should get expanded to the user's home directory in the Log config option. Fixes bug 2971; bugfix on 0.2.0.1-alpha, which introduced the feature for the -f and --DataDirectory options. o Minor features: - Make sure every relay writes a state file at least every 12 hours. Previously, a relay could go for weeks without writing its state file, and on a crash could lose its bandwidth history, capacity estimates, client country statistics, and so on. Addresses bug 3012. - Send END_STREAM_REASON_NOROUTE in response to EHOSTUNREACH errors. Clients before 0.2.1.27 didn't handle NOROUTE correctly, but such clients are already deprecated because of security bugs. - Don't allow v0 hidden service authorities to act as clients. Required by fix for bug 3000. - Ignore SIGNAL NEWNYM commands on relay-only Tor instances. Required by fix for bug 3000. - Ensure that no empty [dirreq-](read|write)-history lines are added to an extrainfo document. Implements ticket 2497. o Code simplification and refactoring: - Remove workaround code to handle directory responses from servers that had bug 539 (they would send HTTP status 503 responses _and_ send a body too). Since only server versions before 0.2.0.16-alpha/0.1.2.19 were affected, there is no longer reason to keep the workaround in place. - Remove the old 'fuzzy time' logic. It was supposed to be used for handling calculations where we have a known amount of clock skew and an allowed amount of unknown skew. But we only used it in three places, and we never adjusted the known/unknown skew values. This is still something we might want to do someday, but if we do, we'll want to do it differently. - Avoid signed/unsigned comparisons by making SIZE_T_CEILING unsigned. None of the cases where we did this before were wrong, but by making this change we avoid warnings. Fixes bug 2475; bugfix on 0.2.1.28. - Use GetTempDir to find the proper temporary directory location on Windows when generating temporary files for the unit tests. Patch by Gisle Vanem. Changes in version 0.2.2.24-alpha - 2011-04-08 Tor 0.2.2.24-alpha fixes a variety of bugs, including a big bug that prevented Tor clients from effectively using "multihomed" bridges, that is, bridges that listen on multiple ports or IP addresses so users can continue to use some of their addresses even if others get blocked. o Major bugfixes: - Fix a bug where bridge users who configure the non-canonical address of a bridge automatically switch to its canonical address. If a bridge listens at more than one address, it should be able to advertise those addresses independently and any non-blocked addresses should continue to work. Bugfix on Tor 0.2.0.x. Fixes bug 2510. - If you configured Tor to use bridge A, and then quit and configured Tor to use bridge B instead, it would happily continue to use bridge A if it's still reachable. While this behavior is a feature if your goal is connectivity, in some scenarios it's a dangerous bug. Bugfix on Tor 0.2.0.1-alpha; fixes bug 2511. - Directory authorities now use data collected from their own uptime observations when choosing whether to assign the HSDir flag to relays, instead of trusting the uptime value the relay reports in its descriptor. This change helps prevent an attack where a small set of nodes with frequently-changing identity keys can blackhole a hidden service. (Only authorities need upgrade; others will be fine once they do.) Bugfix on 0.2.0.10-alpha; fixes bug 2709. o Minor bugfixes: - When we restart our relay, we might get a successful connection from the outside before we've started our reachability tests, triggering a warning: "ORPort found reachable, but I have no routerinfo yet. Failing to inform controller of success." This bug was harmless unless Tor is running under a controller like Vidalia, in which case the controller would never get a REACHABILITY_SUCCEEDED status event. Bugfix on 0.1.2.6-alpha; fixes bug 1172. - Make directory authorities more accurate at recording when relays that have failed several reachability tests became unreachable, so we can provide more accuracy at assigning Stable, Guard, HSDir, etc flags. Bugfix on 0.2.0.6-alpha. Resolves bug 2716. - Fix an issue that prevented static linking of libevent on some platforms (notably Linux). Fixes bug 2698; bugfix on versions 0.2.1.23/0.2.2.8-alpha (the versions introducing the --with-static-libevent configure option). - We now ask the other side of a stream (the client or the exit) for more data on that stream when the amount of queued data on that stream dips low enough. Previously, we wouldn't ask the other side for more data until either it sent us more data (which it wasn't supposed to do if it had exhausted its window!) or we had completely flushed all our queued data. This flow control fix should improve throughput. Fixes bug 2756; bugfix on the earliest released versions of Tor (svn commit r152). - Avoid a double-mark-for-free warning when failing to attach a transparent proxy connection. (We thought we had fixed this in 0.2.2.23-alpha, but it turns out our fix was checking the wrong connection.) Fixes bug 2757; bugfix on 0.1.2.1-alpha (the original bug) and 0.2.2.23-alpha (the incorrect fix). - When warning about missing zlib development packages during compile, give the correct package names. Bugfix on 0.2.0.1-alpha. o Minor features: - Directory authorities now log the source of a rejected POSTed v3 networkstatus vote. - Make compilation with clang possible when using --enable-gcc-warnings by removing two warning options that clang hasn't implemented yet and by fixing a few warnings. Implements ticket 2696. - When expiring circuits, use microsecond timers rather than one-second timers. This can avoid an unpleasant situation where a circuit is launched near the end of one second and expired right near the beginning of the next, and prevent fluctuations in circuit timeout values. - Use computed circuit-build timeouts to decide when to launch parallel introduction circuits for hidden services. (Previously, we would retry after 15 seconds.) - Update to the April 1 2011 Maxmind GeoLite Country database. o Packaging fixes: - Create the /var/run/tor directory on startup on OpenSUSE if it is not already created. Patch from Andreas Stieger. Fixes bug 2573. o Documentation changes: - Modernize the doxygen configuration file slightly. Fixes bug 2707. - Resolve all doxygen warnings except those for missing documentation. Fixes bug 2705. - Add doxygen documentation for more functions, fields, and types. Changes in version 0.2.2.23-alpha - 2011-03-08 Tor 0.2.2.23-alpha lets relays record their bandwidth history so when they restart they don't lose their bandwidth capacity estimate. This release also fixes a diverse set of user-facing bugs, ranging from relays overrunning their rate limiting to clients falsely warning about clock skew to bridge descriptor leaks by our bridge directory authority. o Major bugfixes: - Stop sending a CLOCK_SKEW controller status event whenever we fetch directory information from a relay that has a wrong clock. Instead, only inform the controller when it's a trusted authority that claims our clock is wrong. Bugfix on 0.1.2.6-alpha; fixes the rest of bug 1074. - Fix an assert in parsing router descriptors containing IPv6 addresses. This one took down the directory authorities when somebody tried some experimental code. Bugfix on 0.2.1.3-alpha. - Make the bridge directory authority refuse to answer directory requests for "all" descriptors. It used to include bridge descriptors in its answer, which was a major information leak. Found by "piebeer". Bugfix on 0.2.0.3-alpha. - If relays set RelayBandwidthBurst but not RelayBandwidthRate, Tor would ignore their RelayBandwidthBurst setting, potentially using more bandwidth than expected. Bugfix on 0.2.0.1-alpha. Reported by Paul Wouters. Fixes bug 2470. - Ignore and warn if the user mistakenly sets "PublishServerDescriptor hidserv" in her torrc. The 'hidserv' argument never controlled publication of hidden service descriptors. Bugfix on 0.2.0.1-alpha. o Major features: - Relays now save observed peak bandwidth throughput rates to their state file (along with total usage, which was already saved) so that they can determine their correct estimated bandwidth on restart. Resolves bug 1863, where Tor relays would reset their estimated bandwidth to 0 after restarting. - Directory authorities now take changes in router IP address and ORPort into account when determining router stability. Previously, if a router changed its IP or ORPort, the authorities would not treat it as having any downtime for the purposes of stability calculation, whereas clients would experience downtime since the change could take a while to propagate to them. Resolves issue 1035. - Enable Address Space Layout Randomization (ASLR) and Data Execution Prevention (DEP) by default on Windows to make it harder for attackers to exploit vulnerabilities. Patch from John Brooks. o Minor bugfixes (on 0.2.1.x and earlier): - Fix a rare crash bug that could occur when a client was configured with a large number of bridges. Fixes bug 2629; bugfix on 0.2.1.2-alpha. Bugfix by trac user "shitlei". - Avoid a double mark-for-free warning when failing to attach a transparent proxy connection. Bugfix on 0.1.2.1-alpha. Fixes bug 2279. - Correctly detect failure to allocate an OpenSSL BIO. Fixes bug 2378; found by "cypherpunks". This bug was introduced before the first Tor release, in svn commit r110. - Country codes aren't supported in EntryNodes until 0.2.3.x, so don't mention them in the manpage. Fixes bug 2450; issue spotted by keb and G-Lo. - Fix a bug in bandwidth history state parsing that could have been triggered if a future version of Tor ever changed the timing granularity at which bandwidth history is measured. Bugfix on Tor 0.1.1.11-alpha. - When a relay decides that its DNS is too broken for it to serve as an exit server, it advertised itself as a non-exit, but continued to act as an exit. This could create accidental partitioning opportunities for users. Instead, if a relay is going to advertise reject *:* as its exit policy, it should really act with exit policy "reject *:*". Fixes bug 2366. Bugfix on Tor 0.1.2.5-alpha. Bugfix by user "postman" on trac. - In the special case where you configure a public exit relay as your bridge, Tor would be willing to use that exit relay as the last hop in your circuit as well. Now we fail that circuit instead. Bugfix on 0.2.0.12-alpha. Fixes bug 2403. Reported by "piebeer". - Fix a bug with our locking implementation on Windows that couldn't correctly detect when a file was already locked. Fixes bug 2504, bugfix on 0.2.1.6-alpha. - Fix IPv6-related connect() failures on some platforms (BSD, OS X). Bugfix on 0.2.0.3-alpha; fixes first part of bug 2660. Patch by "piebeer". - Set target port in get_interface_address6() correctly. Bugfix on 0.1.1.4-alpha and 0.2.0.3-alpha; fixes second part of bug 2660. - Directory authorities are now more robust to hops back in time when calculating router stability. Previously, if a run of uptime or downtime appeared to be negative, the calculation could give incorrect results. Bugfix on 0.2.0.6-alpha; noticed when fixing bug 1035. - Fix an assert that got triggered when using the TestingTorNetwork configuration option and then issuing a GETINFO config-text control command. Fixes bug 2250; bugfix on 0.2.1.2-alpha. o Minor bugfixes (on 0.2.2.x): - Clients should not weight BadExit nodes as Exits in their node selection. Similarly, directory authorities should not count BadExit bandwidth as Exit bandwidth when computing bandwidth-weights. Bugfix on 0.2.2.10-alpha; fixes bug 2203. - Correctly clear our dir_read/dir_write history when there is an error parsing any bw history value from the state file. Bugfix on Tor 0.2.2.15-alpha. - Resolve a bug in verifying signatures of directory objects with digests longer than SHA1. Bugfix on 0.2.2.20-alpha. Fixes bug 2409. Found by "piebeer". - Bridge authorities no longer crash on SIGHUP when they try to publish their relay descriptor to themselves. Fixes bug 2572. Bugfix on 0.2.2.22-alpha. o Minor features: - Log less aggressively about circuit timeout changes, and improve some other circuit timeout messages. Resolves bug 2004. - Log a little more clearly about the times at which we're no longer accepting new connections. Resolves bug 2181. - Reject attempts at the client side to open connections to private IP addresses (like 127.0.0.1, 10.0.0.1, and so on) with a randomly chosen exit node. Attempts to do so are always ill-defined, generally prevented by exit policies, and usually in error. This will also help to detect loops in transparent proxy configurations. You can disable this feature by setting "ClientRejectInternalAddresses 0" in your torrc. - Always treat failure to allocate an RSA key as an unrecoverable allocation error. - Update to the March 1 2011 Maxmind GeoLite Country database. o Minor features (log subsystem): - Add documentation for configuring logging at different severities in different log domains. We've had this feature since 0.2.1.1-alpha, but for some reason it never made it into the manpage. Fixes bug 2215. - Make it simpler to specify "All log domains except for A and B". Previously you needed to say "[*,~A,~B]". Now you can just say "[~A,~B]". - Add a "LogMessageDomains 1" option to include the domains of log messages along with the messages. Without this, there's no way to use log domains without reading the source or doing a lot of guessing. o Packaging changes: - Stop shipping the Tor specs files and development proposal documents in the tarball. They are now in a separate git repository at git://git.torproject.org/torspec.git Changes in version 0.2.1.30 - 2011-02-23 Tor 0.2.1.30 fixes a variety of less critical bugs. The main other change is a slight tweak to Tor's TLS handshake that makes relays and bridges that run this new version reachable from Iran again. We don't expect this tweak will win the arms race long-term, but it buys us time until we roll out a better solution. o Major bugfixes: - Stop sending a CLOCK_SKEW controller status event whenever we fetch directory information from a relay that has a wrong clock. Instead, only inform the controller when it's a trusted authority that claims our clock is wrong. Bugfix on 0.1.2.6-alpha; fixes the rest of bug 1074. - Fix a bounds-checking error that could allow an attacker to remotely crash a directory authority. Bugfix on 0.2.1.5-alpha. Found by "piebeer". - If relays set RelayBandwidthBurst but not RelayBandwidthRate, Tor would ignore their RelayBandwidthBurst setting, potentially using more bandwidth than expected. Bugfix on 0.2.0.1-alpha. Reported by Paul Wouters. Fixes bug 2470. - Ignore and warn if the user mistakenly sets "PublishServerDescriptor hidserv" in her torrc. The 'hidserv' argument never controlled publication of hidden service descriptors. Bugfix on 0.2.0.1-alpha. o Minor features: - Adjust our TLS Diffie-Hellman parameters to match those used by Apache's mod_ssl. - Update to the February 1 2011 Maxmind GeoLite Country database. o Minor bugfixes: - Check for and reject overly long directory certificates and directory tokens before they have a chance to hit any assertions. Bugfix on 0.2.1.28. Found by "doorss". - Bring the logic that gathers routerinfos and assesses the acceptability of circuits into line. This prevents a Tor OP from getting locked in a cycle of choosing its local OR as an exit for a path (due to a .exit request) and then rejecting the circuit because its OR is not listed yet. It also prevents Tor clients from using an OR running in the same instance as an exit (due to a .exit request) if the OR does not meet the same requirements expected of an OR running elsewhere. Fixes bug 1859; bugfix on 0.1.0.1-rc. o Packaging changes: - Stop shipping the Tor specs files and development proposal documents in the tarball. They are now in a separate git repository at git://git.torproject.org/torspec.git - Do not include Git version tags as though they are SVN tags when generating a tarball from inside a repository that has switched between branches. Bugfix on 0.2.1.15-rc; fixes bug 2402. Changes in version 0.2.2.22-alpha - 2011-01-25 Tor 0.2.2.22-alpha fixes a few more less-critical security issues. The main other change is a slight tweak to Tor's TLS handshake that makes relays and bridges that run this new version reachable from Iran again. We don't expect this tweak will win the arms race long-term, but it will buy us a bit more time until we roll out a better solution. o Major bugfixes: - Fix a bounds-checking error that could allow an attacker to remotely crash a directory authority. Bugfix on 0.2.1.5-alpha. Found by "piebeer". - Don't assert when changing from bridge to relay or vice versa via the controller. The assert happened because we didn't properly initialize our keys in this case. Bugfix on 0.2.2.18-alpha; fixes bug 2433. Reported by bastik. o Minor features: - Adjust our TLS Diffie-Hellman parameters to match those used by Apache's mod_ssl. - Provide a log message stating which geoip file we're parsing instead of just stating that we're parsing the geoip file. Implements ticket 2432. o Minor bugfixes: - Check for and reject overly long directory certificates and directory tokens before they have a chance to hit any assertions. Bugfix on 0.2.1.28 / 0.2.2.20-alpha. Found by "doorss". Changes in version 0.2.2.21-alpha - 2011-01-15 Tor 0.2.2.21-alpha includes all the patches from Tor 0.2.1.29, which continues our recent code security audit work. The main fix resolves a remote heap overflow vulnerability that can allow remote code execution (CVE-2011-0427). Other fixes address a variety of assert and crash bugs, most of which we think are hard to exploit remotely. o Major bugfixes (security), also included in 0.2.1.29: - Fix a heap overflow bug where an adversary could cause heap corruption. This bug probably allows remote code execution attacks. Reported by "debuger". Fixes CVE-2011-0427. Bugfix on 0.1.2.10-rc. - Prevent a denial-of-service attack by disallowing any zlib-compressed data whose compression factor is implausibly high. Fixes part of bug 2324; reported by "doorss". - Zero out a few more keys in memory before freeing them. Fixes bug 2384 and part of bug 2385. These key instances found by "cypherpunks", based on Andrew Case's report about being able to find sensitive data in Tor's memory space if you have enough permissions. Bugfix on 0.0.2pre9. o Major bugfixes (crashes), also included in 0.2.1.29: - Prevent calls to Libevent from inside Libevent log handlers. This had potential to cause a nasty set of crashes, especially if running Libevent with debug logging enabled, and running Tor with a controller watching for low-severity log messages. Bugfix on 0.1.0.2-rc. Fixes bug 2190. - Add a check for SIZE_T_MAX to tor_realloc() to try to avoid underflow errors there too. Fixes the other part of bug 2324. - Fix a bug where we would assert if we ever had a cached-descriptors.new file (or another file read directly into memory) of exactly SIZE_T_CEILING bytes. Fixes bug 2326; bugfix on 0.2.1.25. Found by doorss. - Fix some potential asserts and parsing issues with grossly malformed router caches. Fixes bug 2352; bugfix on Tor 0.2.1.27. Found by doorss. o Minor bugfixes (other), also included in 0.2.1.29: - Fix a bug with handling misformed replies to reverse DNS lookup requests in DNSPort. Bugfix on Tor 0.2.0.1-alpha. Related to a bug reported by doorss. - Fix compilation on mingw when a pthreads compatibility library has been installed. (We don't want to use it, so we shouldn't be including pthread.h.) Fixes bug 2313; bugfix on 0.1.0.1-rc. - Fix a bug where we would declare that we had run out of virtual addresses when the address space was only half-exhausted. Bugfix on 0.1.2.1-alpha. - Correctly handle the case where AutomapHostsOnResolve is set but no virtual addresses are available. Fixes bug 2328; bugfix on 0.1.2.1-alpha. Bug found by doorss. - Correctly handle wrapping around when we run out of virtual address space. Found by cypherpunks; bugfix on 0.2.0.5-alpha. o Minor features, also included in 0.2.1.29: - Update to the January 1 2011 Maxmind GeoLite Country database. - Introduce output size checks on all of our decryption functions. o Build changes, also included in 0.2.1.29: - Tor does not build packages correctly with Automake 1.6 and earlier; added a check to Makefile.am to make sure that we're building with Automake 1.7 or later. - The 0.2.1.28 tarball was missing src/common/OpenBSD_malloc_Linux.c because we built it with a too-old version of automake. Thus that release broke ./configure --enable-openbsd-malloc, which is popular among really fast exit relays on Linux. o Major bugfixes, new in 0.2.2.21-alpha: - Prevent crash/heap corruption when the cbtnummodes consensus parameter is set to 0 or large values. Fixes bug 2317; bugfix on 0.2.2.14-alpha. o Major features, new in 0.2.2.21-alpha: - Introduce minimum/maximum values that clients will believe from the consensus. Now we'll have a better chance to avoid crashes or worse when a consensus param has a weird value. o Minor features, new in 0.2.2.21-alpha: - Make sure to disable DirPort if running as a bridge. DirPorts aren't used on bridges, and it makes bridge scanning somewhat easier. - If writing the state file to disk fails, wait up to an hour before retrying again, rather than trying again each second. Fixes bug 2346; bugfix on Tor 0.1.1.3-alpha. - Make Libevent log messages get delivered to controllers later, and not from inside the Libevent log handler. This prevents unsafe reentrant Libevent calls while still letting the log messages get through. - Detect platforms that brokenly use a signed size_t, and refuse to build there. Found and analyzed by doorss and rransom. - Fix a bunch of compile warnings revealed by mingw with gcc 4.5. Resolves bug 2314. o Minor bugfixes, new in 0.2.2.21-alpha: - Handle SOCKS messages longer than 128 bytes long correctly, rather than waiting forever for them to finish. Fixes bug 2330; bugfix on 0.2.0.16-alpha. Found by doorss. - Add assertions to check for overflow in arguments to base32_encode() and base32_decode(); fix a signed-unsigned comparison there too. These bugs are not actually reachable in Tor, but it's good to prevent future errors too. Found by doorss. - Correctly detect failures to create DNS requests when using Libevent versions before v2. (Before Libevent 2, we used our own evdns implementation. Its return values for Libevent's evdns_resolve_*() functions are not consistent with those from Libevent.) Fixes bug 2363; bugfix on 0.2.2.6-alpha. Found by "lodger". o Documentation, new in 0.2.2.21-alpha: - Document the default socks host and port (127.0.0.1:9050) for tor-resolve. Changes in version 0.2.1.29 - 2011-01-15 Tor 0.2.1.29 continues our recent code security audit work. The main fix resolves a remote heap overflow vulnerability that can allow remote code execution. Other fixes address a variety of assert and crash bugs, most of which we think are hard to exploit remotely. o Major bugfixes (security): - Fix a heap overflow bug where an adversary could cause heap corruption. This bug probably allows remote code execution attacks. Reported by "debuger". Fixes CVE-2011-0427. Bugfix on 0.1.2.10-rc. - Prevent a denial-of-service attack by disallowing any zlib-compressed data whose compression factor is implausibly high. Fixes part of bug 2324; reported by "doorss". - Zero out a few more keys in memory before freeing them. Fixes bug 2384 and part of bug 2385. These key instances found by "cypherpunks", based on Andrew Case's report about being able to find sensitive data in Tor's memory space if you have enough permissions. Bugfix on 0.0.2pre9. o Major bugfixes (crashes): - Prevent calls to Libevent from inside Libevent log handlers. This had potential to cause a nasty set of crashes, especially if running Libevent with debug logging enabled, and running Tor with a controller watching for low-severity log messages. Bugfix on 0.1.0.2-rc. Fixes bug 2190. - Add a check for SIZE_T_MAX to tor_realloc() to try to avoid underflow errors there too. Fixes the other part of bug 2324. - Fix a bug where we would assert if we ever had a cached-descriptors.new file (or another file read directly into memory) of exactly SIZE_T_CEILING bytes. Fixes bug 2326; bugfix on 0.2.1.25. Found by doorss. - Fix some potential asserts and parsing issues with grossly malformed router caches. Fixes bug 2352; bugfix on Tor 0.2.1.27. Found by doorss. o Minor bugfixes (other): - Fix a bug with handling misformed replies to reverse DNS lookup requests in DNSPort. Bugfix on Tor 0.2.0.1-alpha. Related to a bug reported by doorss. - Fix compilation on mingw when a pthreads compatibility library has been installed. (We don't want to use it, so we shouldn't be including pthread.h.) Fixes bug 2313; bugfix on 0.1.0.1-rc. - Fix a bug where we would declare that we had run out of virtual addresses when the address space was only half-exhausted. Bugfix on 0.1.2.1-alpha. - Correctly handle the case where AutomapHostsOnResolve is set but no virtual addresses are available. Fixes bug 2328; bugfix on 0.1.2.1-alpha. Bug found by doorss. - Correctly handle wrapping around to when we run out of virtual address space. Found by cypherpunks, bugfix on 0.2.0.5-alpha. - The 0.2.1.28 tarball was missing src/common/OpenBSD_malloc_Linux.c because we built it with a too-old version of automake. Thus that release broke ./configure --enable-openbsd-malloc, which is popular among really fast exit relays on Linux. o Minor features: - Update to the January 1 2011 Maxmind GeoLite Country database. - Introduce output size checks on all of our decryption functions. o Build changes: - Tor does not build packages correctly with Automake 1.6 and earlier; added a check to Makefile.am to make sure that we're building with Automake 1.7 or later. Changes in version 0.2.2.20-alpha - 2010-12-17 Tor 0.2.2.20-alpha does some code cleanup to reduce the risk of remotely exploitable bugs. We also fix a variety of other significant bugs, change the IP address for one of our directory authorities, and update the minimum version that Tor relays must run to join the network. o Major bugfixes: - Fix a remotely exploitable bug that could be used to crash instances of Tor remotely by overflowing on the heap. Remote-code execution hasn't been confirmed, but can't be ruled out. Everyone should upgrade. Bugfix on the 0.1.1 series and later. - Fix a bug that could break accounting on 64-bit systems with large time_t values, making them hibernate for impossibly long intervals. Fixes bug 2146. Bugfix on 0.0.9pre6; fix by boboper. - Fix a logic error in directory_fetches_from_authorities() that would cause all _non_-exits refusing single-hop-like circuits to fetch from authorities, when we wanted to have _exits_ fetch from authorities. Fixes more of 2097. Bugfix on 0.2.2.16-alpha; fix by boboper. - Fix a stream fairness bug that would cause newer streams on a given circuit to get preference when reading bytes from the origin or destination. Fixes bug 2210. Fix by Mashael AlSabah. This bug was introduced before the first Tor release, in svn revision r152. o Directory authority changes: - Change IP address and ports for gabelmoo (v3 directory authority). o Minor bugfixes: - Avoid crashes when AccountingMax is set on clients. Fixes bug 2235. Bugfix on 0.2.2.18-alpha. Diagnosed by boboper. - Fix an off-by-one error in calculating some controller command argument lengths. Fortunately, this mistake is harmless since the controller code does redundant NUL termination too. Found by boboper. Bugfix on 0.1.1.1-alpha. - Do not dereference NULL if a bridge fails to build its extra-info descriptor. Found by an anonymous commenter on Trac. Bugfix on 0.2.2.19-alpha. o Minor features: - Update to the December 1 2010 Maxmind GeoLite Country database. - Directory authorities now reject relays running any versions of Tor between 0.2.1.3-alpha and 0.2.1.18 inclusive; they have known bugs that keep RELAY_EARLY cells from working on rendezvous circuits. Followup to fix for bug 2081. - Directory authorities now reject relays running any version of Tor older than 0.2.0.26-rc. That version is the earliest that fetches current directory information correctly. Fixes bug 2156. - Report only the top 10 ports in exit-port stats in order not to exceed the maximum extra-info descriptor length of 50 KB. Implements task 2196. Changes in version 0.2.1.28 - 2010-12-17 Tor 0.2.1.28 does some code cleanup to reduce the risk of remotely exploitable bugs. We also took this opportunity to change the IP address for one of our directory authorities, and to update the geoip database we ship. o Major bugfixes: - Fix a remotely exploitable bug that could be used to crash instances of Tor remotely by overflowing on the heap. Remote-code execution hasn't been confirmed, but can't be ruled out. Everyone should upgrade. Bugfix on the 0.1.1 series and later. o Directory authority changes: - Change IP address and ports for gabelmoo (v3 directory authority). o Minor features: - Update to the December 1 2010 Maxmind GeoLite Country database. Changes in version 0.2.1.27 - 2010-11-23 Yet another OpenSSL security patch broke its compatibility with Tor: Tor 0.2.1.27 makes relays work with openssl 0.9.8p and 1.0.0.b. We also took this opportunity to fix several crash bugs, integrate a new directory authority, and update the bundled GeoIP database. o Major bugfixes: - Resolve an incompatibility with OpenSSL 0.9.8p and OpenSSL 1.0.0b: No longer set the tlsext_host_name extension on server SSL objects; but continue to set it on client SSL objects. Our goal in setting it was to imitate a browser, not a vhosting server. Fixes bug 2204; bugfix on 0.2.1.1-alpha. - Do not log messages to the controller while shrinking buffer freelists. Doing so would sometimes make the controller connection try to allocate a buffer chunk, which would mess up the internals of the freelist and cause an assertion failure. Fixes bug 1125; fixed by Robert Ransom. Bugfix on 0.2.0.16-alpha. - Learn our external IP address when we're a relay or bridge, even if we set PublishServerDescriptor to 0. Bugfix on 0.2.0.3-alpha, where we introduced bridge relays that don't need to publish to be useful. Fixes bug 2050. - Do even more to reject (and not just ignore) annotations on router descriptors received anywhere but from the cache. Previously we would ignore such annotations at first, but cache them to disk anyway. Bugfix on 0.2.0.8-alpha. Found by piebeer. - When you're using bridges and your network goes away and your bridges get marked as down, recover when you attempt a new socks connection (if the network is back), rather than waiting up to an hour to try fetching new descriptors for your bridges. Bugfix on 0.2.0.3-alpha; fixes bug 1981. o Major features: - Move to the November 2010 Maxmind GeoLite country db (rather than the June 2009 ip-to-country GeoIP db) for our statistics that count how many users relays are seeing from each country. Now we'll have more accurate data, especially for many African countries. o New directory authorities: - Set up maatuska (run by Linus Nordberg) as the eighth v3 directory authority. o Minor bugfixes: - Fix an assertion failure that could occur in directory caches or bridge users when using a very short voting interval on a testing network. Diagnosed by Robert Hogan. Fixes bug 1141; bugfix on 0.2.0.8-alpha. - Enforce multiplicity rules when parsing annotations. Bugfix on 0.2.0.8-alpha. Found by piebeer. - Allow handshaking OR connections to take a full KeepalivePeriod seconds to handshake. Previously, we would close them after IDLE_OR_CONN_TIMEOUT (180) seconds, the same timeout as if they were open. Bugfix on 0.2.1.26; fixes bug 1840. Thanks to mingw-san for analysis help. - When building with --enable-gcc-warnings on OpenBSD, disable warnings in system headers. This makes --enable-gcc-warnings pass on OpenBSD 4.8. o Minor features: - Exit nodes didn't recognize EHOSTUNREACH as a plausible error code, and so sent back END_STREAM_REASON_MISC. Clients now recognize a new stream ending reason for this case: END_STREAM_REASON_NOROUTE. Servers can start sending this code when enough clients recognize it. Bugfix on 0.1.0.1-rc; fixes part of bug 1793. - Build correctly on mingw with more recent versions of OpenSSL 0.9.8. Patch from mingw-san. o Removed files: - Remove the old debian/ directory from the main Tor distribution. The official Tor-for-debian git repository lives at the URL https://git.torproject.org/debian/tor.git - Stop shipping the old doc/website/ directory in the tarball. We changed the website format in late 2010, and what we shipped in 0.2.1.26 really wasn't that useful anyway. Changes in version 0.2.2.19-alpha - 2010-11-22 Yet another OpenSSL security patch broke its compatibility with Tor: Tor 0.2.2.19-alpha makes relays work with OpenSSL 0.9.8p and 1.0.0.b. o Major bugfixes: - Resolve an incompatibility with OpenSSL 0.9.8p and OpenSSL 1.0.0b: No longer set the tlsext_host_name extension on server SSL objects; but continue to set it on client SSL objects. Our goal in setting it was to imitate a browser, not a vhosting server. Fixes bug 2204; bugfix on 0.2.1.1-alpha. o Minor bugfixes: - Try harder not to exceed the maximum length of 50 KB when writing statistics to extra-info descriptors. This bug was triggered by very fast relays reporting exit-port, entry, and dirreq statistics. Reported by Olaf Selke. Bugfix on 0.2.2.1-alpha. Fixes bug 2183. - Publish a router descriptor even if generating an extra-info descriptor fails. Previously we would not publish a router descriptor without an extra-info descriptor; this can cause fast exit relays collecting exit-port statistics to drop from the consensus. Bugfix on 0.1.2.9-rc; fixes bug 2195. Changes in version 0.2.2.18-alpha - 2010-11-16 Tor 0.2.2.18-alpha fixes several crash bugs that have been nagging us lately, makes unpublished bridge relays able to detect their IP address, and fixes a wide variety of other bugs to get us much closer to a stable release. o Major bugfixes: - Do even more to reject (and not just ignore) annotations on router descriptors received anywhere but from the cache. Previously we would ignore such annotations at first, but cache them to disk anyway. Bugfix on 0.2.0.8-alpha. Found by piebeer. - Do not log messages to the controller while shrinking buffer freelists. Doing so would sometimes make the controller connection try to allocate a buffer chunk, which would mess up the internals of the freelist and cause an assertion failure. Fixes bug 1125; fixed by Robert Ransom. Bugfix on 0.2.0.16-alpha. - Learn our external IP address when we're a relay or bridge, even if we set PublishServerDescriptor to 0. Bugfix on 0.2.0.3-alpha, where we introduced bridge relays that don't need to publish to be useful. Fixes bug 2050. - Maintain separate TLS contexts and certificates for incoming and outgoing connections in bridge relays. Previously we would use the same TLS contexts and certs for incoming and outgoing connections. Bugfix on 0.2.0.3-alpha; addresses bug 988. - Maintain separate identity keys for incoming and outgoing TLS contexts in bridge relays. Previously we would use the same identity keys for incoming and outgoing TLS contexts. Bugfix on 0.2.0.3-alpha; addresses the other half of bug 988. - Avoid an assertion failure when we as an authority receive a duplicate upload of a router descriptor that we already have, but which we previously considered an obsolete descriptor. Fixes another case of bug 1776. Bugfix on 0.2.2.16-alpha. - Avoid a crash bug triggered by looking at a dangling pointer while setting the network status consensus. Found by Robert Ransom. Bugfix on 0.2.2.17-alpha. Fixes bug 2097. - Fix a logic error where servers that _didn't_ act as exits would try to keep their server lists more aggressively up to date than exits, when it was supposed to be the other way around. Bugfix on 0.2.2.17-alpha. o Minor bugfixes (on Tor 0.2.1.x and earlier): - When we're trying to guess whether we know our IP address as a relay, we would log various ways that we failed to guess our address, but never log that we ended up guessing it successfully. Now add a log line to help confused and anxious relay operators. Bugfix on 0.1.2.1-alpha; fixes bug 1534. - Bring the logic that gathers routerinfos and assesses the acceptability of circuits into line. This prevents a Tor OP from getting locked in a cycle of choosing its local OR as an exit for a path (due to a .exit request) and then rejecting the circuit because its OR is not listed yet. It also prevents Tor clients from using an OR running in the same instance as an exit (due to a .exit request) if the OR does not meet the same requirements expected of an OR running elsewhere. Fixes bug 1859; bugfix on 0.1.0.1-rc. - Correctly describe errors that occur when generating a TLS object. Previously we would attribute them to a failure while generating a TLS context. Patch by Robert Ransom. Bugfix on 0.1.0.4-rc; fixes bug 1994. - Enforce multiplicity rules when parsing annotations. Bugfix on 0.2.0.8-alpha. Found by piebeer. - Fix warnings that newer versions of autoconf produced during ./autogen.sh. These warnings appear to be harmless in our case, but they were extremely verbose. Fixes bug 2020. o Minor bugfixes (on Tor 0.2.2.x): - Enable protection of small arrays whenever we build with gcc hardening features, not only when also building with warnings enabled. Fixes bug 2031; bugfix on 0.2.2.14-alpha. Reported by keb. o Minor features: - Make hidden services work better in private Tor networks by not requiring any uptime to join the hidden service descriptor DHT. Implements ticket 2088. - Rate-limit the "your application is giving Tor only an IP address" warning. Addresses bug 2000; bugfix on 0.0.8pre2. - When AllowSingleHopExits is set, print a warning to explain to the relay operator why most clients are avoiding her relay. - Update to the November 1 2010 Maxmind GeoLite Country database. o Code simplifications and refactoring: - When we fixed bug 1038 we had to put in a restriction not to send RELAY_EARLY cells on rend circuits. This was necessary as long as relays using Tor 0.2.1.3-alpha through 0.2.1.18-alpha were active. Now remove this obsolete check. Resolves bug 2081. - Some options used different conventions for uppercasing of acronyms when comparing manpage and source. Fix those in favor of the manpage, as it makes sense to capitalize acronyms. - Remove the torrc.complete file. It hasn't been kept up to date and users will have better luck checking out the manpage. - Remove the obsolete "NoPublish" option; it has been flagged as obsolete and has produced a warning since 0.1.1.18-rc. - Remove everything related to building the expert bundle for OS X. It has confused many users, doesn't work right on OS X 10.6, and is hard to get rid of once installed. Resolves bug 1274. Changes in version 0.2.2.17-alpha - 2010-09-30 Tor 0.2.2.17-alpha introduces a feature to make it harder for clients to use one-hop circuits (which can put the exit relays at higher risk, plus unbalance the network); fixes a big bug in bandwidth accounting for relays that want to limit their monthly bandwidth use; fixes a big pile of bugs in how clients tolerate temporary network failure; and makes our adaptive circuit build timeout feature (which improves client performance if your network is fast while not breaking things if your network is slow) better handle bad networks. o Major features: - Exit relays now try harder to block exit attempts from unknown relays, to make it harder for people to use them as one-hop proxies a la tortunnel. Controlled by the refuseunknownexits consensus parameter (currently enabled), or you can override it on your relay with the RefuseUnknownExits torrc option. Resolves bug 1751. o Major bugfixes (0.2.1.x and earlier): - Fix a bug in bandwidth accounting that could make us use twice the intended bandwidth when our interval start changes due to daylight saving time. Now we tolerate skew in stored vs computed interval starts: if the start of the period changes by no more than 50% of the period's duration, we remember bytes that we transferred in the old period. Fixes bug 1511; bugfix on 0.0.9pre5. - Always search the Windows system directory for system DLLs, and nowhere else. Bugfix on 0.1.1.23; fixes bug 1954. - When you're using bridges and your network goes away and your bridges get marked as down, recover when you attempt a new socks connection (if the network is back), rather than waiting up to an hour to try fetching new descriptors for your bridges. Bugfix on 0.2.0.3-alpha; fixes bug 1981. o Major bugfixes (on 0.2.2.x): - Fix compilation on Windows. Bugfix on 0.2.2.16-alpha; related to bug 1797. - Fix a segfault that could happen when operating a bridge relay with no GeoIP database set. Fixes bug 1964; bugfix on 0.2.2.15-alpha. - The consensus bandwidth-weights (used by clients to choose fast relays) entered an unexpected edge case in September where Exits were much scarcer than Guards, resulting in bad weight recommendations. Now we compute them using new constraints that should succeed in all cases. Also alter directory authorities to not include the bandwidth-weights line if they fail to produce valid values. Fixes bug 1952; bugfix on 0.2.2.10-alpha. - When weighting bridges during path selection, we used to trust the bandwidths they provided in their descriptor, only capping them at 10MB/s. This turned out to be problematic for two reasons: Bridges could claim to handle a lot more traffic then they actually would, thus making more clients pick them and have a pretty effective DoS attack. The other issue is that new bridges that might not have a good estimate for their bw capacity yet would not get used at all unless no other bridges are available to a client. Fixes bug 1912; bugfix on 0.2.2.7-alpha. o Major bugfixes (on the circuit build timeout feature, 0.2.2.x): - Ignore cannibalized circuits when recording circuit build times. This should provide for a minor performance improvement for hidden service users using 0.2.2.14-alpha, and should remove two spurious notice log messages. Bugfix on 0.2.2.14-alpha; fixes bug 1740. - Simplify the logic that causes us to decide if the network is unavailable for purposes of recording circuit build times. If we receive no cells whatsoever for the entire duration of a circuit's full measured lifetime, the network is probably down. Also ignore one-hop directory fetching circuit timeouts when calculating our circuit build times. These changes should hopefully reduce the cases where we see ridiculous circuit build timeouts for people with spotty wireless connections. Fixes part of bug 1772; bugfix on 0.2.2.2-alpha. - Prevent the circuit build timeout from becoming larger than the maximum build time we have ever seen. Also, prevent the time period for measurement circuits from becoming larger than twice that value. Fixes the other part of bug 1772; bugfix on 0.2.2.2-alpha. o Minor features: - When we run out of directory information such that we can't build circuits, but then get enough that we can build circuits, log when we actually construct a circuit, so the user has a better chance of knowing what's going on. Fixes bug 1362. - Be more generous with how much bandwidth we'd use up (with accounting enabled) before entering "soft hibernation". Previously, we'd refuse new connections and circuits once we'd used up 95% of our allotment. Now, we use up 95% of our allotment, AND make sure that we have no more than 500MB (or 3 hours of expected traffic, whichever is lower) remaining before we enter soft hibernation. - If we've configured EntryNodes and our network goes away and/or all our entrynodes get marked down, optimistically retry them all when a new socks application request appears. Fixes bug 1882. - Add some more defensive programming for architectures that can't handle unaligned integer accesses. We don't know of any actual bugs right now, but that's the best time to fix them. Fixes bug 1943. - Support line continuations in the torrc config file. If a line ends with a single backslash character, the newline is ignored, and the configuration value is treated as continuing on the next line. Resolves bug 1929. o Minor bugfixes (on 0.2.1.x and earlier): - For bandwidth accounting, calculate our expected bandwidth rate based on the time during which we were active and not in soft-hibernation during the last interval. Previously, we were also considering the time spent in soft-hibernation. If this was a long time, we would wind up underestimating our bandwidth by a lot, and skewing our wakeup time towards the start of the accounting interval. Fixes bug 1789. Bugfix on 0.0.9pre5. o Minor bugfixes (on 0.2.2.x): - Resume generating CIRC FAILED REASON=TIMEOUT control port messages, which were disabled by the circuit build timeout changes in 0.2.2.14-alpha. Bugfix on 0.2.2.14-alpha; fixes bug 1739. - Make sure we don't warn about missing bandwidth weights when choosing bridges or other relays not in the consensus. Bugfix on 0.2.2.10-alpha; fixes bug 1805. - In our logs, do not double-report signatures from unrecognized authorities both as "from unknown authority" and "not present". Fixes bug 1956, bugfix on 0.2.2.16-alpha. Changes in version 0.2.2.16-alpha - 2010-09-17 Tor 0.2.2.16-alpha fixes a variety of old stream fairness bugs (most evident at exit relays), and also continues to resolve all the little bugs that have been filling up trac lately. o Major bugfixes (stream-level fairness): - When receiving a circuit-level SENDME for a blocked circuit, try to package cells fairly from all the streams that had previously been blocked on that circuit. Previously, we had started with the oldest stream, and allowed each stream to potentially exhaust the circuit's package window. This gave older streams on any given circuit priority over newer ones. Fixes bug 1937. Detected originally by Camilo Viecco. This bug was introduced before the first Tor release, in svn commit r152: it is the new winner of the longest-lived bug prize. - When the exit relay got a circuit-level sendme cell, it started reading on the exit streams, even if had 500 cells queued in the circuit queue already, so the circuit queue just grew and grew in some cases. We fix this by not re-enabling reading on receipt of a sendme cell when the cell queue is blocked. Fixes bug 1653. Bugfix on 0.2.0.1-alpha. Detected by Mashael AlSabah. Original patch by "yetonetime". - Newly created streams were allowed to read cells onto circuits, even if the circuit's cell queue was blocked and waiting to drain. This created potential unfairness, as older streams would be blocked, but newer streams would gladly fill the queue completely. We add code to detect this situation and prevent any stream from getting more than one free cell. Bugfix on 0.2.0.1-alpha. Partially fixes bug 1298. o Minor features: - Update to the September 1 2010 Maxmind GeoLite Country database. - Warn when CookieAuthFileGroupReadable is set but CookieAuthFile is not. This would lead to a cookie that is still not group readable. Closes bug 1843. Suggested by katmagic. - When logging a rate-limited warning, we now mention how many messages got suppressed since the last warning. - Add new "perconnbwrate" and "perconnbwburst" consensus params to do individual connection-level rate limiting of clients. The torrc config options with the same names trump the consensus params, if both are present. Replaces the old "bwconnrate" and "bwconnburst" consensus params which were broken from 0.2.2.7-alpha through 0.2.2.14-alpha. Closes bug 1947. - When a router changes IP address or port, authorities now launch a new reachability test for it. Implements ticket 1899. - Make the formerly ugly "2 unknown, 7 missing key, 0 good, 0 bad, 2 no signature, 4 required" messages about consensus signatures easier to read, and make sure they get logged at the same severity as the messages explaining which keys are which. Fixes bug 1290. - Don't warn when we have a consensus that we can't verify because of missing certificates, unless those certificates are ones that we have been trying and failing to download. Fixes bug 1145. - If you configure your bridge with a known identity fingerprint, and the bridge authority is unreachable (as it is in at least one country now), fall back to directly requesting the descriptor from the bridge. Finishes the feature started in 0.2.0.10-alpha; closes bug 1138. - When building with --enable-gcc-warnings on OpenBSD, disable warnings in system headers. This makes --enable-gcc-warnings pass on OpenBSD 4.8. o Minor bugfixes (on 0.2.1.x and earlier): - Authorities will now attempt to download consensuses if their own efforts to make a live consensus have failed. This change means authorities that restart will fetch a valid consensus, and it means authorities that didn't agree with the current consensus will still fetch and serve it if it has enough signatures. Bugfix on 0.2.0.9-alpha; fixes bug 1300. - Ensure DNS requests launched by "RESOLVE" commands from the controller respect the __LeaveStreamsUnattached setconf options. The same goes for requests launched via DNSPort or transparent proxying. Bugfix on 0.2.0.1-alpha; fixes bug 1525. - Allow handshaking OR connections to take a full KeepalivePeriod seconds to handshake. Previously, we would close them after IDLE_OR_CONN_TIMEOUT (180) seconds, the same timeout as if they were open. Bugfix on 0.2.1.26; fixes bug 1840. Thanks to mingw-san for analysis help. - Rate-limit "Failed to hand off onionskin" warnings. - Never relay a cell for a circuit we have already destroyed. Between marking a circuit as closeable and finally closing it, it may have been possible for a few queued cells to get relayed, even though they would have been immediately dropped by the next OR in the circuit. Fixes bug 1184; bugfix on 0.2.0.1-alpha. - Never queue a cell for a circuit that's already been marked for close. - Never vote for a server as "Running" if we have a descriptor for it claiming to be hibernating, and that descriptor was published more recently than our last contact with the server. Bugfix on 0.2.0.3-alpha; fixes bug 911. - Squash a compile warning on OpenBSD. Reported by Tas; fixes bug 1848. o Minor bugfixes (on 0.2.2.x): - Fix a regression introduced in 0.2.2.7-alpha that marked relays down if a directory fetch fails and you've configured either bridges or EntryNodes. The intent was to mark the relay as down _unless_ you're using bridges or EntryNodes, since if you are then you could quickly run out of entry points. - Fix the Windows directory-listing code. A bug introduced in 0.2.2.14-alpha could make Windows directory servers forget to load some of their cached v2 networkstatus files. - Really allow clients to use relays as bridges. Fixes bug 1776; bugfix on 0.2.2.15-alpha. - Demote a warn to info that happens when the CellStatistics option was just enabled. Bugfix on 0.2.2.15-alpha; fixes bug 1921. Reported by Moritz Bartl. - On Windows, build correctly either with or without Unicode support. This is necessary so that Tor can support fringe platforms like Windows 98 (which has no Unicode), or Windows CE (which has no non-Unicode). Bugfix on 0.2.2.14-alpha; fixes bug 1797. o Testing - Add a unit test for cross-platform directory-listing code. Changes in version 0.2.2.15-alpha - 2010-08-18 Tor 0.2.2.15-alpha fixes a big bug in hidden service availability, fixes a variety of other bugs that were preventing performance experiments from moving forward, fixes several bothersome memory leaks, and generally closes a lot of smaller bugs that have been filling up trac lately. o Major bugfixes: - Stop assigning the HSDir flag to relays that disable their DirPort (and thus will refuse to answer directory requests). This fix should dramatically improve the reachability of hidden services: hidden services and hidden service clients pick six HSDir relays to store and retrieve the hidden service descriptor, and currently about half of the HSDir relays will refuse to work. Bugfix on 0.2.0.10-alpha; fixes part of bug 1693. - The PerConnBWRate and Burst config options, along with the bwconnrate and bwconnburst consensus params, initialized each conn's token bucket values only when the connection is established. Now we update them if the config options change, and update them every time we get a new consensus. Otherwise we can encounter an ugly edge case where we initialize an OR conn to client-level bandwidth, but then later the relay joins the consensus and we leave it throttled. Bugfix on 0.2.2.7-alpha; fixes bug 1830. - Fix a regression that caused Tor to rebind its ports if it receives SIGHUP while hibernating. Bugfix in 0.1.1.6-alpha; closes bug 919. o Major features: - Lower the maximum weighted-fractional-uptime cutoff to 98%. This should give us approximately 40-50% more Guard-flagged nodes, improving the anonymity the Tor network can provide and also decreasing the dropoff in throughput that relays experience when they first get the Guard flag. - Allow enabling or disabling the *Statistics config options while Tor is running. o Minor features: - Update to the August 1 2010 Maxmind GeoLite Country database. - Have the controller interface give a more useful message than "Internal Error" in response to failed GETINFO requests. - Warn when the same option is provided more than once in a torrc file, on the command line, or in a single SETCONF statement, and the option is one that only accepts a single line. Closes bug 1384. - Build correctly on mingw with more recent versions of OpenSSL 0.9.8. Patch from mingw-san. - Add support for the country code "{??}" in torrc options like ExcludeNodes, to indicate all routers of unknown country. Closes bug 1094. - Relays report the number of bytes spent on answering directory requests in extra-info descriptors similar to {read,write}-history. Implements enhancement 1790. o Minor bugfixes (on 0.2.1.x and earlier): - Complain if PublishServerDescriptor is given multiple arguments that include 0 or 1. This configuration will be rejected in the future. Bugfix on 0.2.0.1-alpha; closes bug 1107. - Disallow BridgeRelay 1 and ORPort 0 at once in the configuration. Bugfix on 0.2.0.13-alpha; closes bug 928. - Change "Application request when we're believed to be offline." notice to "Application request when we haven't used client functionality lately.", to clarify that it's not an error. Bugfix on 0.0.9.3; fixes bug 1222. - Fix a bug in the controller interface where "GETINFO ns/asdaskljkl" would return "551 Internal error" rather than "552 Unrecognized key ns/asdaskljkl". Bugfix on 0.1.2.3-alpha. - Users can't configure a regular relay to be their bridge. It didn't work because when Tor fetched the bridge descriptor, it found that it already had it, and didn't realize that the purpose of the descriptor had changed. Now we replace routers with a purpose other than bridge with bridge descriptors when fetching them. Bugfix on 0.1.1.9-alpha. Bug 1776 not yet fixed because now we immediately refetch the descriptor with router purpose 'general', disabling it as a bridge. - Fix a rare bug in rend_fn unit tests: we would fail a test when a randomly generated port is 0. Diagnosed by Matt Edman. Bugfix on 0.2.0.10-alpha; fixes bug 1808. - Exit nodes didn't recognize EHOSTUNREACH as a plausible error code, and so sent back END_STREAM_REASON_MISC. Clients now recognize a new stream ending reason for this case: END_STREAM_REASON_NOROUTE. Servers can start sending this code when enough clients recognize it. Also update the spec to reflect this new reason. Bugfix on 0.1.0.1-rc; fixes part of bug 1793. - Delay geoip stats collection by bridges for 6 hours, not 2 hours, when we switch from being a public relay to a bridge. Otherwise there will still be clients that see the relay in their consensus, and the stats will end up wrong. Bugfix on 0.2.1.15-rc; fixes bug 932 even more. - Instead of giving an assertion failure on an internal mismatch on estimated freelist size, just log a BUG warning and try later. Mitigates but does not fix bug 1125. - Fix an assertion failure that could occur in caches or bridge users when using a very short voting interval on a testing network. Diagnosed by Robert Hogan. Fixes bug 1141; bugfix on 0.2.0.8-alpha. o Minor bugfixes (on 0.2.2.x): - Alter directory authorities to always consider Exit-flagged nodes as potential Guard nodes in their votes. The actual decision to use Exits as Guards is done in the consensus bandwidth weights. Fixes bug 1294; bugfix on 0.2.2.10-alpha. - When the controller is reporting the purpose of circuits that didn't finish building before the circuit build timeout, it was printing UNKNOWN_13. Now print EXPIRED. Bugfix on 0.2.2.14-alpha. - Our libevent version parsing code couldn't handle versions like 1.4.14b-stable and incorrectly warned the user about using an old and broken version of libevent. Treat 1.4.14b-stable like 1.4.14-stable when parsing the version. Fixes bug 1731; bugfix on 0.2.2.1-alpha. - Don't use substitution references like $(VAR:MOD) when $(asciidoc_files) is empty -- make(1) on NetBSD transforms '$(:x)' to 'x' rather than the empty string. This bites us in doc/ when configured with --disable-asciidoc. Bugfix on 0.2.2.9-alpha; fixes bug 1773. - Remove a spurious hidden service server-side log notice about "Ancient non-dirty circuits". Bugfix on 0.2.2.14-alpha; fixes bug 1741. - Fix compilation with --with-dmalloc set. Bugfix on 0.2.2.6-alpha; fixes bug 1832. - Correctly report written bytes on linked connections. Found while implementing 1790. Bugfix on 0.2.2.4-alpha. - Fix three memory leaks: one in circuit_build_times_parse_state(), one in dirvote_add_signatures_to_pending_consensus(), and one every time we parse a v3 network consensus. Bugfixes on 0.2.2.14-alpha, 0.2.2.6-alpha, and 0.2.2.10-alpha respectively; fixes bug 1831. o Code simplifications and refactoring: - Take a first step towards making or.h smaller by splitting out function definitions for all source files in src/or/. Leave structures and defines in or.h for now. - Remove a bunch of unused function declarations as well as a block of #if 0'd code from the unit tests. Closes bug 1824. - New unit tests for exit-port history statistics; refactored exit statistics code to be more easily tested. - Remove the old debian/ directory from the main Tor distribution. The official Tor-for-debian git repository lives at the URL https://git.torproject.org/debian/tor.git Changes in version 0.2.2.14-alpha - 2010-07-12 Tor 0.2.2.14-alpha greatly improves client-side handling of circuit build timeouts, which are used to estimate speed and improve performance. We also move to a much better GeoIP database, port Tor to Windows CE, introduce new compile flags that improve code security, add an eighth v3 directory authority, and address a lot of more minor issues. o Major bugfixes: - Tor directory authorities no longer crash when started with a cached-microdesc-consensus file in their data directory. Bugfix on 0.2.2.6-alpha; fixes bug 1532. - Treat an unset $HOME like an empty $HOME rather than triggering an assert. Bugfix on 0.0.8pre1; fixes bug 1522. - Ignore negative and large circuit build timeout values that can happen during a suspend or hibernate. These values caused various asserts to fire. Bugfix on 0.2.2.2-alpha; fixes bug 1245. - Alter calculation of Pareto distribution parameter 'Xm' for Circuit Build Timeout learning to use the weighted average of the top N=3 modes (because we have three entry guards). Considering multiple modes should improve the timeout calculation in some cases, and prevent extremely high timeout values. Bugfix on 0.2.2.2-alpha; fixes bug 1335. - Alter calculation of Pareto distribution parameter 'Alpha' to use a right censored distribution model. This approach improves over the synthetic timeout generation approach that was producing insanely high timeout values. Now we calculate build timeouts using truncated times. Bugfix on 0.2.2.2-alpha; fixes bugs 1245 and 1335. - Do not close circuits that are under construction when they reach the circuit build timeout. Instead, leave them building (but do not use them) for up until the time corresponding to the 95th percentile on the Pareto CDF or 60 seconds, whichever is greater. This is done to provide better data for the new Pareto model. This percentile can be controlled by the consensus. o Major features: - Move to the June 2010 Maxmind GeoLite country db (rather than the June 2009 ip-to-country GeoIP db) for our statistics that count how many users relays are seeing from each country. Now we have more accurate data for many African countries. - Port Tor to build and run correctly on Windows CE systems, using the wcecompat library. Contributed by Valerio Lupi. - New "--enable-gcc-hardening" ./configure flag (off by default) to turn on gcc compile time hardening options. It ensures that signed ints have defined behavior (-fwrapv), enables -D_FORTIFY_SOURCE=2 (requiring -O2), adds stack smashing protection with canaries (-fstack-protector-all), turns on ASLR protection if supported by the kernel (-fPIE, -pie), and adds additional security related warnings. Verified to work on Mac OS X and Debian Lenny. - New "--enable-linker-hardening" ./configure flag (off by default) to turn on ELF specific hardening features (relro, now). This does not work with Mac OS X or any other non-ELF binary format. o New directory authorities: - Set up maatuska (run by Linus Nordberg) as the eighth v3 directory authority. o Minor features: - New config option "WarnUnsafeSocks 0" disables the warning that occurs whenever Tor receives a socks handshake using a version of the socks protocol that can only provide an IP address (rather than a hostname). Setups that do DNS locally over Tor are fine, and we shouldn't spam the logs in that case. - Convert the HACKING file to asciidoc, and add a few new sections to it, explaining how we use Git, how we make changelogs, and what should go in a patch. - Add a TIMEOUT_RATE keyword to the BUILDTIMEOUT_SET control port event, to give information on the current rate of circuit timeouts over our stored history. - Add ability to disable circuit build time learning via consensus parameter and via a LearnCircuitBuildTimeout config option. Also automatically disable circuit build time calculation if we are either a AuthoritativeDirectory, or if we fail to write our state file. Fixes bug 1296. - More gracefully handle corrupt state files, removing asserts in favor of saving a backup and resetting state. - Rename the "log.h" header to "torlog.h" so as to conflict with fewer system headers. o Minor bugfixes: - Build correctly on OSX with zlib 1.2.4 and higher with all warnings enabled. - When a2x fails, mention that the user could disable manpages instead of trying to fix their asciidoc installation. - Where available, use Libevent 2.0's periodic timers so that our once-per-second cleanup code gets called even more closely to once per second than it would otherwise. Fixes bug 943. - If you run a bridge that listens on multiple IP addresses, and some user configures a bridge address that uses a different IP address than your bridge writes in its router descriptor, and the user doesn't specify an identity key, their Tor would discard the descriptor because "it isn't one of our configured bridges", and fail to bootstrap. Now believe the descriptor and bootstrap anyway. Bugfix on 0.2.0.3-alpha. - If OpenSSL fails to make a duplicate of a private or public key, log an error message and try to exit cleanly. May help with debugging if bug 1209 ever remanifests. - Save a couple bytes in memory allocation every time we escape certain characters in a string. Patch from Florian Zumbiehl. - Make it explicit that we don't cannibalize one-hop circuits. This happens in the wild, but doesn't turn out to be a problem because we fortunately don't use those circuits. Many thanks to outofwords for the initial analysis and to swissknife who confirmed that two-hop circuits are actually created. - Make directory mirrors report non-zero dirreq-v[23]-shares again. Fixes bug 1564; bugfix on 0.2.2.9-alpha. - Eliminate a case where a circuit build time warning was displayed after network connectivity resumed. Bugfix on 0.2.2.2-alpha. Changes in version 0.2.1.26 - 2010-05-02 Tor 0.2.1.26 addresses the recent connection and memory overload problems we've been seeing on relays, especially relays with their DirPort open. If your relay has been crashing, or you turned it off because it used too many resources, give this release a try. This release also fixes yet another instance of broken OpenSSL libraries that was causing some relays to drop out of the consensus. o Major bugfixes: - Teach relays to defend themselves from connection overload. Relays now close idle circuits early if it looks like they were intended for directory fetches. Relays are also more aggressive about closing TLS connections that have no circuits on them. Such circuits are unlikely to be re-used, and tens of thousands of them were piling up at the fast relays, causing the relays to run out of sockets and memory. Bugfix on 0.2.0.22-rc (where clients started tunneling their directory fetches over TLS). - Fix SSL renegotiation behavior on OpenSSL versions like on Centos that claim to be earlier than 0.9.8m, but which have in reality backported huge swaths of 0.9.8m or 0.9.8n renegotiation behavior. Possible fix for some cases of bug 1346. - Directory mirrors were fetching relay descriptors only from v2 directory authorities, rather than v3 authorities like they should. Only 2 v2 authorities remain (compared to 7 v3 authorities), leading to a serious bottleneck. Bugfix on 0.2.0.9-alpha. Fixes bug 1324. o Minor bugfixes: - Finally get rid of the deprecated and now harmful notion of "clique mode", where directory authorities maintain TLS connections to every other relay. o Testsuite fixes: - In the util/threads test, no longer free the test_mutex before all worker threads have finished. Bugfix on 0.2.1.6-alpha. - The master thread could starve the worker threads quite badly on certain systems, causing them to run only partially in the allowed window. This resulted in test failures. Now the master thread sleeps occasionally for a few microseconds while the two worker-threads compete for the mutex. Bugfix on 0.2.0.1-alpha. Changes in version 0.2.2.13-alpha - 2010-04-24 Tor 0.2.2.13-alpha addresses the recent connection and memory overload problems we've been seeing on relays, especially relays with their DirPort open. If your relay has been crashing, or you turned it off because it used too many resources, give this release a try. o Major bugfixes: - Teach relays to defend themselves from connection overload. Relays now close idle circuits early if it looks like they were intended for directory fetches. Relays are also more aggressive about closing TLS connections that have no circuits on them. Such circuits are unlikely to be re-used, and tens of thousands of them were piling up at the fast relays, causing the relays to run out of sockets and memory. Bugfix on 0.2.0.22-rc (where clients started tunneling their directory fetches over TLS). o Minor features: - Finally get rid of the deprecated and now harmful notion of "clique mode", where directory authorities maintain TLS connections to every other relay. - Directory authorities now do an immediate reachability check as soon as they hear about a new relay. This change should slightly reduce the time between setting up a relay and getting listed as running in the consensus. It should also improve the time between setting up a bridge and seeing use by bridge users. - Directory authorities no longer launch a TLS connection to every relay as they startup. Now that we have 2k+ descriptors cached, the resulting network hiccup is becoming a burden. Besides, authorities already avoid voting about Running for the first half hour of their uptime. Changes in version 0.2.2.12-alpha - 2010-04-20 Tor 0.2.2.12-alpha fixes a critical bug in how directory authorities handle and vote on descriptors. It was causing relays to drop out of the consensus. o Major bugfixes: - Many relays have been falling out of the consensus lately because not enough authorities know about their descriptor for them to get a majority of votes. When we deprecated the v2 directory protocol, we got rid of the only way that v3 authorities can hear from each other about other descriptors. Now authorities examine every v3 vote for new descriptors, and fetch them from that authority. Bugfix on 0.2.1.23. - Fix two typos in tor_vasprintf() that broke the compile on Windows, and a warning in or.h related to bandwidth_weight_rule_t that prevented clean compile on OS X. Fixes bug 1363; bugfix on 0.2.2.11-alpha. - Fix a segfault on relays when DirReqStatistics is enabled and 24 hours pass. Bug found by keb. Fixes bug 1365; bugfix on 0.2.2.11-alpha. o Minor bugfixes: - Demote a confusing TLS warning that relay operators might get when someone tries to talk to their OrPort. It is neither the operator's fault nor can they do anything about it. Fixes bug 1364; bugfix on 0.2.0.14-alpha. Changes in version 0.2.2.11-alpha - 2010-04-15 Tor 0.2.2.11-alpha fixes yet another instance of broken OpenSSL libraries that was causing some relays to drop out of the consensus. o Major bugfixes: - Directory mirrors were fetching relay descriptors only from v2 directory authorities, rather than v3 authorities like they should. Only 2 v2 authorities remain (compared to 7 v3 authorities), leading to a serious bottleneck. Bugfix on 0.2.0.9-alpha. Fixes bug 1324. - Fix a parsing error that made every possible value of CircPriorityHalflifeMsec get treated as "1 msec". Bugfix on 0.2.2.7-alpha. Rename CircPriorityHalflifeMsec to CircuitPriorityHalflifeMsec, so authorities can tell newer relays about the option without breaking older ones. - Fix SSL renegotiation behavior on OpenSSL versions like on Centos that claim to be earlier than 0.9.8m, but which have in reality backported huge swaths of 0.9.8m or 0.9.8n renegotiation behavior. Possible fix for some cases of bug 1346. o Minor features: - Experiment with a more aggressive approach to preventing clients from making one-hop exit streams. Exit relays who want to try it out can set "RefuseUnknownExits 1" in their torrc, and then look for "Attempt by %s to open a stream" log messages. Let us know how it goes! - Add support for statically linking zlib by specifying --enable-static-zlib, to go with our support for statically linking openssl and libevent. Resolves bug 1358. o Minor bugfixes: - Fix a segfault that happens whenever a Tor client that is using libevent2's bufferevents gets a hup signal. Bugfix on 0.2.2.5-alpha; fixes bug 1341. - When we cleaned up the contrib/tor-exit-notice.html file, we left out the first line. Fixes bug 1295. - When building the manpage from a tarball, we required asciidoc, but the asciidoc -> roff/html conversion was already done for the tarball. Make 'make' complain only when we need asciidoc (either because we're compiling directly from git, or because we altered the asciidoc manpage in the tarball). Bugfix on 0.2.2.9-alpha. - When none of the directory authorities vote on any params, Tor segfaulted when trying to make the consensus from the votes. We didn't trigger the bug in practice, because authorities do include params in their votes. Bugfix on 0.2.2.10-alpha; fixes bug 1322. o Testsuite fixes: - In the util/threads test, no longer free the test_mutex before all worker threads have finished. Bugfix on 0.2.1.6-alpha. - The master thread could starve the worker threads quite badly on certain systems, causing them to run only partially in the allowed window. This resulted in test failures. Now the master thread sleeps occasionally for a few microseconds while the two worker-threads compete for the mutex. Bugfix on 0.2.0.1-alpha. Changes in version 0.2.2.10-alpha - 2010-03-07 Tor 0.2.2.10-alpha fixes a regression introduced in 0.2.2.9-alpha that could prevent relays from guessing their IP address correctly. It also starts the groundwork for another client-side performance boost, since currently we're not making efficient use of relays that have both the Guard flag and the Exit flag. o Major bugfixes: - Fix a regression from our patch for bug 1244 that caused relays to guess their IP address incorrectly if they didn't set Address in their torrc and/or their address fails to resolve. Bugfix on 0.2.2.9-alpha; fixes bug 1269. o Major features (performance): - Directory authorities now compute consensus weightings that instruct clients how to weight relays flagged as Guard, Exit, Guard+Exit, and no flag. Clients that use these weightings will distribute network load more evenly across these different relay types. The weightings are in the consensus so we can change them globally in the future. Extra thanks to "outofwords" for finding some nasty security bugs in the first implementation of this feature. o Minor features (performance): - Always perform router selections using weighted relay bandwidth, even if we don't need a high capacity circuit at the time. Non-fast circuits now only differ from fast ones in that they can use relays not marked with the Fast flag. This "feature" could turn out to be a horrible bug; we should investigate more before it goes into a stable release. o Minor features: - Allow disabling building of the manpages. Skipping the manpage speeds up the build considerably. o Minor bugfixes (on 0.2.2.x): - Fix a memleak in the EXTENDCIRCUIT logic. Spotted by coverity. Bugfix on 0.2.2.9-alpha. - Disallow values larger than INT32_MAX for PerConnBWRate|Burst config option. Bugfix on 0.2.2.7-alpha. - Ship the asciidoc-helper file in the tarball, so that people can build from source if they want to, and touching the .1.txt files doesn't break the build. Bugfix on 0.2.2.9-alpha. o Minor bugfixes (on 0.2.1.x or earlier): - Fix a dereference-then-NULL-check sequence when publishing descriptors. Bugfix on 0.2.1.5-alpha. Discovered by ekir; fixes bug 1255. - Fix another dereference-then-NULL-check sequence. Bugfix on 0.2.1.14-rc. Discovered by ekir; fixes bug 1256. - Make sure we treat potentially not NUL-terminated strings correctly. Bugfix on 0.1.1.13-alpha. Discovered by rieo; fixes bug 1257. o Code simplifications and refactoring: - Fix some urls in the exit notice file and make it XHTML1.1 strict compliant. Based on a patch from Christian Kujau. - Don't use sed in asciidoc-helper anymore. - Make the build process fail if asciidoc cannot be found and building with asciidoc isn't disabled. Changes in version 0.2.2.9-alpha - 2010-02-22 Tor 0.2.2.9-alpha makes Tor work again on the latest OS X, updates the location of a directory authority, and cleans up a bunch of small bugs. o Directory authority changes: - Change IP address for dannenberg (v3 directory authority), and remove moria2 (obsolete v1, v2 directory authority and v0 hidden service directory authority) from the list. o Major bugfixes: - Make Tor work again on the latest OS X: when deciding whether to use strange flags to turn TLS renegotiation on, detect the OpenSSL version at run-time, not compile time. We need to do this because Apple doesn't update its dev-tools headers when it updates its libraries in a security patch. - Fix a potential buffer overflow in lookup_last_hid_serv_request() that could happen on 32-bit platforms with 64-bit time_t. Also fix a memory leak when requesting a hidden service descriptor we've requested before. Fixes bug 1242, bugfix on 0.2.0.18-alpha. Found by aakova. - Authorities could be tricked into giving out the Exit flag to relays that didn't allow exiting to any ports. This bug could screw with load balancing and stats. Bugfix on 0.1.1.6-alpha; fixes bug 1238. Bug discovered by Martin Kowalczyk. - When freeing a session key, zero it out completely. We only zeroed the first ptrsize bytes. Bugfix on 0.0.2pre8. Discovered and patched by ekir. Fixes bug 1254. o Minor bugfixes: - Fix static compilation by listing the openssl libraries in the right order. Bugfix on Tor 0.2.2.8-alpha; fixes bug 1237. - Resume handling .exit hostnames in a special way: originally we stripped the .exit part and used the requested exit relay. In 0.2.2.1-alpha we stopped treating them in any special way, meaning if you use a .exit address then Tor will pass it on to the exit relay. Now we reject the .exit stream outright, since that behavior might be more expected by the user. Found and diagnosed by Scott Bennett and Downie on or-talk. - Don't spam the controller with events when we have no file descriptors available. Bugfix on 0.2.1.5-alpha. (Rate-limiting for log messages was already solved from bug 748.) - Avoid a bogus overlapped memcpy in tor_addr_copy(). Reported by "memcpyfail". - Make the DNSPort option work with libevent 2.x. Don't alter the behaviour for libevent 1.x. Fixes bug 1143. Found by SwissTorExit. - Emit a GUARD DROPPED controller event for a case we missed. - Make more fields in the controller protocol case-insensitive, since control-spec.txt said they were. - Refactor resolve_my_address() to not use gethostbyname() anymore. Fixes bug 1244; bugfix on 0.0.2pre25. Reported by Mike Mestnik. - Fix a spec conformance issue: the network-status-version token must be the first token in a v3 consensus or vote. Discovered by parakeep. Bugfix on 0.2.0.3-alpha. o Code simplifications and refactoring: - Generate our manpage and HTML documentation using Asciidoc. This change should make it easier to maintain the documentation, and produce nicer HTML. - Remove the --enable-iphone option. According to reports from Marco Bonetti, Tor builds fine without any special tweaking on recent iPhone SDK versions. - Removed some unnecessary files from the source distribution. The AUTHORS file has now been merged into the people page on the website. The roadmaps and design doc can now be found in the projects directory in svn. - Enabled various circuit build timeout constants to be controlled by consensus parameters. Also set better defaults for these parameters based on experimentation on broadband and simulated high latency links. o Minor features: - The 'EXTENDCIRCUIT' control port command can now be used with a circ id of 0 and no path. This feature will cause Tor to build a new 'fast' general purpose circuit using its own path selection algorithms. - Added a BUILDTIMEOUT_SET controller event to describe changes to the circuit build timeout. - Future-proof the controller protocol a bit by ignoring keyword arguments we do not recognize. - Expand homedirs passed to tor-checkkey. This should silence a coverity complaint about passing a user-supplied string into open() without checking it. Changes in version 0.2.1.25 - 2010-03-16 Tor 0.2.1.25 fixes a regression introduced in 0.2.1.23 that could prevent relays from guessing their IP address correctly. It also fixes several minor potential security bugs. o Major bugfixes: - Fix a regression from our patch for bug 1244 that caused relays to guess their IP address incorrectly if they didn't set Address in their torrc and/or their address fails to resolve. Bugfix on 0.2.1.23; fixes bug 1269. - When freeing a session key, zero it out completely. We only zeroed the first ptrsize bytes. Bugfix on 0.0.2pre8. Discovered and patched by ekir. Fixes bug 1254. o Minor bugfixes: - Fix a dereference-then-NULL-check sequence when publishing descriptors. Bugfix on 0.2.1.5-alpha. Discovered by ekir; fixes bug 1255. - Fix another dereference-then-NULL-check sequence. Bugfix on 0.2.1.14-rc. Discovered by ekir; fixes bug 1256. - Make sure we treat potentially not NUL-terminated strings correctly. Bugfix on 0.1.1.13-alpha. Discovered by rieo; fixes bug 1257. Changes in version 0.2.1.24 - 2010-02-21 Tor 0.2.1.24 makes Tor work again on the latest OS X -- this time for sure! o Minor bugfixes: - Work correctly out-of-the-box with even more vendor-patched versions of OpenSSL. In particular, make it so Debian and OS X don't need customized patches to run/build. Changes in version 0.2.1.23 - 2010-02-13 Tor 0.2.1.23 fixes a huge client-side performance bug, makes Tor work again on the latest OS X, and updates the location of a directory authority. o Major bugfixes (performance): - We were selecting our guards uniformly at random, and then weighting which of our guards we'd use uniformly at random. This imbalance meant that Tor clients were severely limited on throughput (and probably latency too) by the first hop in their circuit. Now we select guards weighted by currently advertised bandwidth. We also automatically discard guards picked using the old algorithm. Fixes bug 1217; bugfix on 0.2.1.3-alpha. Found by Mike Perry. o Major bugfixes: - Make Tor work again on the latest OS X: when deciding whether to use strange flags to turn TLS renegotiation on, detect the OpenSSL version at run-time, not compile time. We need to do this because Apple doesn't update its dev-tools headers when it updates its libraries in a security patch. - Fix a potential buffer overflow in lookup_last_hid_serv_request() that could happen on 32-bit platforms with 64-bit time_t. Also fix a memory leak when requesting a hidden service descriptor we've requested before. Fixes bug 1242, bugfix on 0.2.0.18-alpha. Found by aakova. o Directory authority changes: - Change IP address for dannenberg (v3 directory authority), and remove moria2 (obsolete v1, v2 directory authority and v0 hidden service directory authority) from the list. o Minor bugfixes: - Refactor resolve_my_address() to not use gethostbyname() anymore. Fixes bug 1244; bugfix on 0.0.2pre25. Reported by Mike Mestnik. o Minor features: - Avoid a mad rush at the beginning of each month when each client rotates half of its guards. Instead we spread the rotation out throughout the month, but we still avoid leaving a precise timestamp in the state file about when we first picked the guard. Improves over the behavior introduced in 0.1.2.17. Changes in version 0.2.2.8-alpha - 2010-01-26 Tor 0.2.2.8-alpha fixes a crash bug in 0.2.2.7-alpha that has been causing bridge relays to disappear. If you're running a bridge, please upgrade. o Major bugfixes: - Fix a memory corruption bug on bridges that occured during the inclusion of stats data in extra-info descriptors. Also fix the interface for geoip_get_bridge_stats* to prevent similar bugs in the future. Diagnosis by Tas, patch by Karsten and Sebastian. Fixes bug 1208; bugfix on 0.2.2.7-alpha. o Minor bugfixes: - Ignore OutboundBindAddress when connecting to localhost. Connections to localhost need to come _from_ localhost, or else local servers (like DNS and outgoing HTTP/SOCKS proxies) will often refuse to listen. Changes in version 0.2.2.7-alpha - 2010-01-19 Tor 0.2.2.7-alpha fixes a huge client-side performance bug, as well as laying the groundwork for further relay-side performance fixes. It also starts cleaning up client behavior with respect to the EntryNodes, ExitNodes, and StrictNodes config options. This release also rotates two directory authority keys, due to a security breach of some of the Torproject servers. o Directory authority changes: - Rotate keys (both v3 identity and relay identity) for moria1 and gabelmoo. o Major features (performance): - We were selecting our guards uniformly at random, and then weighting which of our guards we'd use uniformly at random. This imbalance meant that Tor clients were severely limited on throughput (and probably latency too) by the first hop in their circuit. Now we select guards weighted by currently advertised bandwidth. We also automatically discard guards picked using the old algorithm. Fixes bug 1217; bugfix on 0.2.1.3-alpha. Found by Mike Perry. - When choosing which cells to relay first, relays can now favor circuits that have been quiet recently, to provide lower latency for low-volume circuits. By default, relays enable or disable this feature based on a setting in the consensus. You can override this default by using the new "CircuitPriorityHalflife" config option. Design and code by Ian Goldberg, Can Tang, and Chris Alexander. - Add separate per-conn write limiting to go with the per-conn read limiting. We added a global write limit in Tor 0.1.2.5-alpha, but never per-conn write limits. - New consensus params "bwconnrate" and "bwconnburst" to let us rate-limit client connections as they enter the network. It's controlled in the consensus so we can turn it on and off for experiments. It's starting out off. Based on proposal 163. o Major features (relay selection options): - Switch to a StrictNodes config option, rather than the previous "StrictEntryNodes" / "StrictExitNodes" separation that was missing a "StrictExcludeNodes" option. - If EntryNodes, ExitNodes, ExcludeNodes, or ExcludeExitNodes change during a config reload, mark and discard all our origin circuits. This fix should address edge cases where we change the config options and but then choose a circuit that we created before the change. - If EntryNodes or ExitNodes are set, be more willing to use an unsuitable (e.g. slow or unstable) circuit. The user asked for it, they get it. - Make EntryNodes config option much more aggressive even when StrictNodes is not set. Before it would prepend your requested entrynodes to your list of guard nodes, but feel free to use others after that. Now it chooses only from your EntryNodes if any of those are available, and only falls back to others if a) they're all down and b) StrictNodes is not set. - Now we refresh your entry guards from EntryNodes at each consensus fetch -- rather than just at startup and then they slowly rot as the network changes. o Major bugfixes: - Stop bridge directory authorities from answering dbg-stability.txt directory queries, which would let people fetch a list of all bridge identities they track. Bugfix on 0.2.1.6-alpha. o Minor features: - Log a notice when we get a new control connection. Now it's easier for security-conscious users to recognize when a local application is knocking on their controller door. Suggested by bug 1196. - New config option "CircuitStreamTimeout" to override our internal timeout schedule for how many seconds until we detach a stream from a circuit and try a new circuit. If your network is particularly slow, you might want to set this to a number like 60. - New controller command "getinfo config-text". It returns the contents that Tor would write if you send it a SAVECONF command, so the controller can write the file to disk itself. - New options for SafeLogging to allow scrubbing only log messages generated while acting as a relay. - Ship the bridges spec file in the tarball too. - Avoid a mad rush at the beginning of each month when each client rotates half of its guards. Instead we spread the rotation out throughout the month, but we still avoid leaving a precise timestamp in the state file about when we first picked the guard. Improves over the behavior introduced in 0.1.2.17. o Minor bugfixes (compiling): - Fix compilation on OS X 10.3, which has a stub mlockall() but hides it. Bugfix on 0.2.2.6-alpha. - Fix compilation on Solaris by removing support for the DisableAllSwap config option. Solaris doesn't have an rlimit for mlockall, so we cannot use it safely. Fixes bug 1198; bugfix on 0.2.2.6-alpha. o Minor bugfixes (crashes): - Do not segfault when writing buffer stats when we haven't observed a single circuit to report about. Found by Fabian Lanze. Bugfix on 0.2.2.1-alpha. - If we're in the pathological case where there's no exit bandwidth but there is non-exit bandwidth, or no guard bandwidth but there is non-guard bandwidth, don't crash during path selection. Bugfix on 0.2.0.3-alpha. - Fix an impossible-to-actually-trigger buffer overflow in relay descriptor generation. Bugfix on 0.1.0.15. o Minor bugfixes (privacy): - Fix an instance where a Tor directory mirror might accidentally log the IP address of a misbehaving Tor client. Bugfix on 0.1.0.1-rc. - Don't list Windows capabilities in relay descriptors. We never made use of them, and maybe it's a bad idea to publish them. Bugfix on 0.1.1.8-alpha. o Minor bugfixes (other): - Resolve an edge case in path weighting that could make us misweight our relay selection. Fixes bug 1203; bugfix on 0.0.8rc1. - Fix statistics on client numbers by country as seen by bridges that were broken in 0.2.2.1-alpha. Also switch to reporting full 24-hour intervals instead of variable 12-to-48-hour intervals. - After we free an internal connection structure, overwrite it with a different memory value than we use for overwriting a freed internal circuit structure. Should help with debugging. Suggested by bug 1055. - Update our OpenSSL 0.9.8l fix so that it works with OpenSSL 0.9.8m too. o Removed features: - Remove the HSAuthorityRecordStats option that version 0 hidden service authorities could have used to track statistics of overall hidden service usage. Changes in version 0.2.1.22 - 2010-01-19 Tor 0.2.1.22 fixes a critical privacy problem in bridge directory authorities -- it would tell you its whole history of bridge descriptors if you make the right directory request. This stable update also rotates two of the seven v3 directory authority keys and locations. o Directory authority changes: - Rotate keys (both v3 identity and relay identity) for moria1 and gabelmoo. o Major bugfixes: - Stop bridge directory authorities from answering dbg-stability.txt directory queries, which would let people fetch a list of all bridge identities they track. Bugfix on 0.2.1.6-alpha. Changes in version 0.2.1.21 - 2009-12-21 Tor 0.2.1.21 fixes an incompatibility with the most recent OpenSSL library. If you use Tor on Linux / Unix and you're getting SSL renegotiation errors, upgrading should help. We also recommend an upgrade if you're an exit relay. o Major bugfixes: - Work around a security feature in OpenSSL 0.9.8l that prevents our handshake from working unless we explicitly tell OpenSSL that we are using SSL renegotiation safely. We are, of course, but OpenSSL 0.9.8l won't work unless we say we are. - Avoid crashing if the client is trying to upload many bytes and the circuit gets torn down at the same time, or if the flip side happens on the exit relay. Bugfix on 0.2.0.1-alpha; fixes bug 1150. o Minor bugfixes: - Do not refuse to learn about authority certs and v2 networkstatus documents that are older than the latest consensus. This bug might have degraded client bootstrapping. Bugfix on 0.2.0.10-alpha. Spotted and fixed by xmux. - Fix a couple of very-hard-to-trigger memory leaks, and one hard-to- trigger platform-specific option misparsing case found by Coverity Scan. - Fix a compilation warning on Fedora 12 by removing an impossible-to- trigger assert. Fixes bug 1173. Changes in version 0.2.2.6-alpha - 2009-11-19 Tor 0.2.2.6-alpha lays the groundwork for many upcoming features: support for the new lower-footprint "microdescriptor" directory design, future-proofing our consensus format against new hash functions or other changes, and an Android port. It also makes Tor compatible with the upcoming OpenSSL 0.9.8l release, and fixes a variety of bugs. o Major features: - Directory authorities can now create, vote on, and serve multiple parallel formats of directory data as part of their voting process. Partially implements Proposal 162: "Publish the consensus in multiple flavors". - Directory authorities can now agree on and publish small summaries of router information that clients can use in place of regular server descriptors. This transition will eventually allow clients to use far less bandwidth for downloading information about the network. Begins the implementation of Proposal 158: "Clients download consensus + microdescriptors". - The directory voting system is now extensible to use multiple hash algorithms for signatures and resource selection. Newer formats are signed with SHA256, with a possibility for moving to a better hash algorithm in the future. - New DisableAllSwap option. If set to 1, Tor will attempt to lock all current and future memory pages via mlockall(). On supported platforms (modern Linux and probably BSD but not Windows or OS X), this should effectively disable any and all attempts to page out memory. This option requires that you start your Tor as root -- if you use DisableAllSwap, please consider using the User option to properly reduce the privileges of your Tor. - Numerous changes, bugfixes, and workarounds from Nathan Freitas to help Tor build correctly for Android phones. o Major bugfixes: - Work around a security feature in OpenSSL 0.9.8l that prevents our handshake from working unless we explicitly tell OpenSSL that we are using SSL renegotiation safely. We are, but OpenSSL 0.9.8l won't work unless we say we are. o Minor bugfixes: - Fix a crash bug when trying to initialize the evdns module in Libevent 2. Bugfix on 0.2.1.16-rc. - Stop logging at severity 'warn' when some other Tor client tries to establish a circuit with us using weak DH keys. It's a protocol violation, but that doesn't mean ordinary users need to hear about it. Fixes the bug part of bug 1114. Bugfix on 0.1.0.13. - Do not refuse to learn about authority certs and v2 networkstatus documents that are older than the latest consensus. This bug might have degraded client bootstrapping. Bugfix on 0.2.0.10-alpha. Spotted and fixed by xmux. - Fix numerous small code-flaws found by Coverity Scan Rung 3. - If all authorities restart at once right before a consensus vote, nobody will vote about "Running", and clients will get a consensus with no usable relays. Instead, authorities refuse to build a consensus if this happens. Bugfix on 0.2.0.10-alpha; fixes bug 1066. - If your relay can't keep up with the number of incoming create cells, it would log one warning per failure into your logs. Limit warnings to 1 per minute. Bugfix on 0.0.2pre10; fixes bug 1042. - Bridges now use "reject *:*" as their default exit policy. Bugfix on 0.2.0.3-alpha; fixes bug 1113. - Fix a memory leak on directory authorities during voting that was introduced in 0.2.2.1-alpha. Found via valgrind. Changes in version 0.2.1.20 - 2009-10-15 Tor 0.2.1.20 fixes a crash bug when you're accessing many hidden services at once, prepares for more performance improvements, and fixes a bunch of smaller bugs. The Windows and OS X bundles also include a more recent Vidalia, and switch from Privoxy to Polipo. The OS X installers are now drag and drop. It's best to un-install Tor/Vidalia and then install this new bundle, rather than upgrade. If you want to upgrade, you'll need to update the paths for Tor and Polipo in the Vidalia Settings window. o Major bugfixes: - Send circuit or stream sendme cells when our window has decreased by 100 cells, not when it has decreased by 101 cells. Bug uncovered by Karsten when testing the "reduce circuit window" performance patch. Bugfix on the 54th commit on Tor -- from July 2002, before the release of Tor 0.0.0. This is the new winner of the oldest-bug prize. - Fix a remotely triggerable memory leak when a consensus document contains more than one signature from the same voter. Bugfix on 0.2.0.3-alpha. - Avoid segfault in rare cases when finishing an introduction circuit as a client and finding out that we don't have an introduction key for it. Fixes bug 1073. Reported by Aaron Swartz. o Major features: - Tor now reads the "circwindow" parameter out of the consensus, and uses that value for its circuit package window rather than the default of 1000 cells. Begins the implementation of proposal 168. o New directory authorities: - Set up urras (run by Jacob Appelbaum) as the seventh v3 directory authority. - Move moria1 and tonga to alternate IP addresses. o Minor bugfixes: - Fix a signed/unsigned compile warning in 0.2.1.19. - Fix possible segmentation fault on directory authorities. Bugfix on 0.2.1.14-rc. - Fix an extremely rare infinite recursion bug that could occur if we tried to log a message after shutting down the log subsystem. Found by Matt Edman. Bugfix on 0.2.0.16-alpha. - Fix an obscure bug where hidden services on 64-bit big-endian systems might mis-read the timestamp in v3 introduce cells, and refuse to connect back to the client. Discovered by "rotor". Bugfix on 0.2.1.6-alpha. - We were triggering a CLOCK_SKEW controller status event whenever we connect via the v2 connection protocol to any relay that has a wrong clock. Instead, we should only inform the controller when it's a trusted authority that claims our clock is wrong. Bugfix on 0.2.0.20-rc; starts to fix bug 1074. Reported by SwissTorExit. - We were telling the controller about CHECKING_REACHABILITY and REACHABILITY_FAILED status events whenever we launch a testing circuit or notice that one has failed. Instead, only tell the controller when we want to inform the user of overall success or overall failure. Bugfix on 0.1.2.6-alpha. Fixes bug 1075. Reported by SwissTorExit. - Don't warn when we're using a circuit that ends with a node excluded in ExcludeExitNodes, but the circuit is not used to access the outside world. This should help fix bug 1090. Bugfix on 0.2.1.6-alpha. - Work around a small memory leak in some versions of OpenSSL that stopped the memory used by the hostname TLS extension from being freed. o Minor features: - Add a "getinfo status/accepted-server-descriptor" controller command, which is the recommended way for controllers to learn whether our server descriptor has been successfully received by at least on directory authority. Un-recommend good-server-descriptor getinfo and status events until we have a better design for them. Changes in version 0.2.2.5-alpha - 2009-10-11 Tor 0.2.2.5-alpha fixes a few compile problems in 0.2.2.4-alpha. o Major bugfixes: - Make the tarball compile again. Oops. Bugfix on 0.2.2.4-alpha. o Directory authorities: - Temporarily (just for this release) move dizum to an alternate IP address. Changes in version 0.2.2.4-alpha - 2009-10-10 Tor 0.2.2.4-alpha fixes more crash bugs in 0.2.2.2-alpha. It also introduces a new unit test framework, shifts directry authority addresses around to reduce the impact from recent blocking events, and fixes a few smaller bugs. o Major bugfixes: - Fix several more asserts in the circuit_build_times code, for example one that causes Tor to fail to start once we have accumulated 5000 build times in the state file. Bugfixes on 0.2.2.2-alpha; fixes bug 1108. o New directory authorities: - Move moria1 and Tonga to alternate IP addresses. o Minor features: - Log SSL state transitions at debug level during handshake, and include SSL states in error messages. This may help debug future SSL handshake issues. - Add a new "Handshake" log domain for activities that happen during the TLS handshake. - Revert to the "June 3 2009" ip-to-country file. The September one seems to have removed most US IP addresses. - Directory authorities now reject Tor relays with versions less than 0.1.2.14. This step cuts out four relays from the current network, none of which are very big. o Minor bugfixes: - Fix a couple of smaller issues with gathering statistics. Bugfixes on 0.2.2.1-alpha. - Fix two memory leaks in the error case of circuit_build_times_parse_state(). Bugfix on 0.2.2.2-alpha. - Don't count one-hop circuits when we're estimating how long it takes circuits to build on average. Otherwise we'll set our circuit build timeout lower than we should. Bugfix on 0.2.2.2-alpha. - Directory authorities no longer change their opinion of, or vote on, whether a router is Running, unless they have themselves been online long enough to have some idea. Bugfix on 0.2.0.6-alpha. Fixes bug 1023. o Code simplifications and refactoring: - Revise our unit tests to use the "tinytest" framework, so we can run tests in their own processes, have smarter setup/teardown code, and so on. The unit test code has moved to its own subdirectory, and has been split into multiple modules. Changes in version 0.2.2.3-alpha - 2009-09-23 Tor 0.2.2.3-alpha fixes a few crash bugs in 0.2.2.2-alpha. o Major bugfixes: - Fix an overzealous assert in our new circuit build timeout code. Bugfix on 0.2.2.2-alpha; fixes bug 1103. o Minor bugfixes: - If the networkstatus consensus tells us that we should use a negative circuit package window, ignore it. Otherwise we'll believe it and then trigger an assert. Bugfix on 0.2.2.2-alpha. Changes in version 0.2.2.2-alpha - 2009-09-21 Tor 0.2.2.2-alpha introduces our latest performance improvement for clients: Tor tracks the average time it takes to build a circuit, and avoids using circuits that take too long to build. For fast connections, this feature can cut your expected latency in half. For slow or flaky connections, it could ruin your Tor experience. Let us know if it does! o Major features: - Tor now tracks how long it takes to build client-side circuits over time, and adapts its timeout to local network performance. Since a circuit that takes a long time to build will also provide bad performance, we get significant latency improvements by discarding the slowest 20% of circuits. Specifically, Tor creates circuits more aggressively than usual until it has enough data points for a good timeout estimate. Implements proposal 151. We are especially looking for reports (good and bad) from users with both EDGE and broadband connections that can move from broadband to EDGE and find out if the build-time data in the .tor/state gets reset without loss of Tor usability. You should also see a notice log message telling you that Tor has reset its timeout. - Directory authorities can now vote on arbitary integer values as part of the consensus process. This is designed to help set network-wide parameters. Implements proposal 167. - Tor now reads the "circwindow" parameter out of the consensus, and uses that value for its circuit package window rather than the default of 1000 cells. Begins the implementation of proposal 168. o Major bugfixes: - Fix a remotely triggerable memory leak when a consensus document contains more than one signature from the same voter. Bugfix on 0.2.0.3-alpha. o Minor bugfixes: - Fix an extremely rare infinite recursion bug that could occur if we tried to log a message after shutting down the log subsystem. Found by Matt Edman. Bugfix on 0.2.0.16-alpha. - Fix parsing for memory or time units given without a space between the number and the unit. Bugfix on 0.2.2.1-alpha; fixes bug 1076. - A networkstatus vote must contain exactly one signature. Spec conformance issue. Bugfix on 0.2.0.3-alpha. - Fix an obscure bug where hidden services on 64-bit big-endian systems might mis-read the timestamp in v3 introduce cells, and refuse to connect back to the client. Discovered by "rotor". Bugfix on 0.2.1.6-alpha. - We were triggering a CLOCK_SKEW controller status event whenever we connect via the v2 connection protocol to any relay that has a wrong clock. Instead, we should only inform the controller when it's a trusted authority that claims our clock is wrong. Bugfix on 0.2.0.20-rc; starts to fix bug 1074. Reported by SwissTorExit. - We were telling the controller about CHECKING_REACHABILITY and REACHABILITY_FAILED status events whenever we launch a testing circuit or notice that one has failed. Instead, only tell the controller when we want to inform the user of overall success or overall failure. Bugfix on 0.1.2.6-alpha. Fixes bug 1075. Reported by SwissTorExit. - Don't warn when we're using a circuit that ends with a node excluded in ExcludeExitNodes, but the circuit is not used to access the outside world. This should help fix bug 1090, but more problems remain. Bugfix on 0.2.1.6-alpha. - Work around a small memory leak in some versions of OpenSSL that stopped the memory used by the hostname TLS extension from being freed. - Make our 'torify' script more portable; if we have only one of 'torsocks' or 'tsocks' installed, don't complain to the user; and explain our warning about tsocks better. o Minor features: - Add a "getinfo status/accepted-server-descriptor" controller command, which is the recommended way for controllers to learn whether our server descriptor has been successfully received by at least on directory authority. Un-recommend good-server-descriptor getinfo and status events until we have a better design for them. - Update to the "September 4 2009" ip-to-country file. Changes in version 0.2.2.1-alpha - 2009-08-26 Tor 0.2.2.1-alpha disables ".exit" address notation by default, allows Tor clients to bootstrap on networks where only port 80 is reachable, makes it more straightforward to support hardware crypto accelerators, and starts the groundwork for gathering stats safely at relays. o Security fixes: - Start the process of disabling ".exit" address notation, since it can be used for a variety of esoteric application-level attacks on users. To reenable it, set "AllowDotExit 1" in your torrc. Fix on 0.0.9rc5. o New directory authorities: - Set up urras (run by Jacob Appelbaum) as the seventh v3 directory authority. o Major features: - New AccelName and AccelDir options add support for dynamic OpenSSL hardware crypto acceleration engines. - Tor now supports tunneling all of its outgoing connections over a SOCKS proxy, using the SOCKS4Proxy and/or SOCKS5Proxy configuration options. Code by Christopher Davis. o Major bugfixes: - Send circuit or stream sendme cells when our window has decreased by 100 cells, not when it has decreased by 101 cells. Bug uncovered by Karsten when testing the "reduce circuit window" performance patch. Bugfix on the 54th commit on Tor -- from July 2002, before the release of Tor 0.0.0. This is the new winner of the oldest-bug prize. o New options for gathering stats safely: - Directory mirrors that set "DirReqStatistics 1" write statistics about directory requests to disk every 24 hours. As compared to the --enable-geoip-stats flag in 0.2.1.x, there are a few improvements: 1) stats are written to disk exactly every 24 hours; 2) estimated shares of v2 and v3 requests are determined as mean values, not at the end of a measurement period; 3) unresolved requests are listed with country code '??'; 4) directories also measure download times. - Exit nodes that set "ExitPortStatistics 1" write statistics on the number of exit streams and transferred bytes per port to disk every 24 hours. - Relays that set "CellStatistics 1" write statistics on how long cells spend in their circuit queues to disk every 24 hours. - Entry nodes that set "EntryStatistics 1" write statistics on the rough number and origins of connecting clients to disk every 24 hours. - Relays that write any of the above statistics to disk and set "ExtraInfoStatistics 1" include the past 24 hours of statistics in their extra-info documents. o Minor features: - New --digests command-line switch to output the digests of the source files Tor was built with. - The "torify" script now uses torsocks where available. - The memarea code now uses a sentinel value at the end of each area to make sure nothing writes beyond the end of an area. This might help debug some conceivable causes of bug 930. - Time and memory units in the configuration file can now be set to fractional units. For example, "2.5 GB" is now a valid value for AccountingMax. - Certain Tor clients (such as those behind check.torproject.org) may want to fetch the consensus in an extra early manner. To enable this a user may now set FetchDirInfoExtraEarly to 1. This also depends on setting FetchDirInfoEarly to 1. Previous behavior will stay the same as only certain clients who must have this information sooner should set this option. - Instead of adding the svn revision to the Tor version string, report the git commit (when we're building from a git checkout). o Minor bugfixes: - If any of the v3 certs we download are unparseable, we should actually notice the failure so we don't retry indefinitely. Bugfix on 0.2.0.x; reported by "rotator". - If the cached cert file is unparseable, warn but don't exit. - Fix possible segmentation fault on directory authorities. Bugfix on 0.2.1.14-rc. - When Tor fails to parse a descriptor of any kind, dump it to disk. Might help diagnosing bug 1051. o Deprecated and removed features: - The controller no longer accepts the old obsolete "addr-mappings/" or "unregistered-servers-" GETINFO values. - Hidden services no longer publish version 0 descriptors, and clients do not request or use version 0 descriptors. However, the old hidden service authorities still accept and serve version 0 descriptors when contacted by older hidden services/clients. - The EXTENDED_EVENTS and VERBOSE_NAMES controller features are now always on; using them is necessary for correct forward-compatible controllers. - Remove support for .noconnect style addresses. Nobody was using them, and they provided another avenue for detecting Tor users via application-level web tricks. o Packaging changes: - Upgrade Vidalia from 0.1.15 to 0.2.3 in the Windows and OS X installer bundles. See https://trac.vidalia-project.net/browser/vidalia/tags/vidalia-0.2.3/CHANGELOG for details of what's new in Vidalia 0.2.3. - Windows Vidalia Bundle: update Privoxy from 3.0.6 to 3.0.14-beta. - OS X Vidalia Bundle: move to Polipo 1.0.4 with Tor specific configuration file, rather than the old Privoxy. - OS X Vidalia Bundle: Vidalia, Tor, and Polipo are compiled as x86-only for better compatibility with OS X 10.6, aka Snow Leopard. - OS X Tor Expert Bundle: Tor is compiled as x86-only for better compatibility with OS X 10.6, aka Snow Leopard. - OS X Vidalia Bundle: The multi-package installer is now replaced by a simple drag and drop to the /Applications folder. This change occurred with the upgrade to Vidalia 0.2.3. Changes in version 0.2.1.19 - 2009-07-28 Tor 0.2.1.19 fixes a major bug with accessing and providing hidden services on Tor 0.2.1.3-alpha through 0.2.1.18. o Major bugfixes: - Make accessing hidden services on 0.2.1.x work right again. Bugfix on 0.2.1.3-alpha; workaround for bug 1038. Diagnosis and part of patch provided by "optimist". o Minor features: - When a relay/bridge is writing out its identity key fingerprint to the "fingerprint" file and to its logs, write it without spaces. Now it will look like the fingerprints in our bridges documentation, and confuse fewer users. o Minor bugfixes: - Relays no longer publish a new server descriptor if they change their MaxAdvertisedBandwidth config option but it doesn't end up changing their advertised bandwidth numbers. Bugfix on 0.2.0.28-rc; fixes bug 1026. Patch from Sebastian. - Avoid leaking memory every time we get a create cell but we have so many already queued that we refuse it. Bugfix on 0.2.0.19-alpha; fixes bug 1034. Reported by BarkerJr. Changes in version 0.2.1.18 - 2009-07-24 Tor 0.2.1.18 lays the foundations for performance improvements, adds status events to help users diagnose bootstrap problems, adds optional authentication/authorization for hidden services, fixes a variety of potential anonymity problems, and includes a huge pile of other features and bug fixes. o Build fixes: - Add LIBS=-lrt to Makefile.am so the Tor RPMs use a static libevent. Changes in version 0.2.1.17-rc - 2009-07-07 Tor 0.2.1.17-rc marks the fourth -- and hopefully last -- release candidate for the 0.2.1.x series. It lays the groundwork for further client performance improvements, and also fixes a big bug with directory authorities that were causing them to assign Guard and Stable flags poorly. The Windows bundles also finally include the geoip database that we thought we'd been shipping since 0.2.0.x (oops), and the OS X bundles should actually install Torbutton rather than giving you a cryptic failure message (oops). o Major features: - Clients now use the bandwidth values in the consensus, rather than the bandwidth values in each relay descriptor. This approach opens the door to more accurate bandwidth estimates once the directory authorities start doing active measurements. Implements more of proposal 141. o Major bugfixes: - When Tor clients restart after 1-5 days, they discard all their cached descriptors as too old, but they still use the cached consensus document. This approach is good for robustness, but bad for performance: since they don't know any bandwidths, they end up choosing at random rather than weighting their choice by speed. Fixed by the above feature of putting bandwidths in the consensus. Bugfix on 0.2.0.x. - Directory authorities were neglecting to mark relays down in their internal histories if the relays fall off the routerlist without ever being found unreachable. So there were relays in the histories that haven't been seen for eight months, and are listed as being up for eight months. This wreaked havoc on the "median wfu" and "median mtbf" calculations, in turn making Guard and Stable flags very wrong, hurting network performance. Fixes bugs 696 and 969. Bugfix on 0.2.0.6-alpha. o Minor bugfixes: - Serve the DirPortFrontPage page even when we have been approaching our quotas recently. Fixes bug 1013; bugfix on 0.2.1.8-alpha. - The control port would close the connection before flushing long replies, such as the network consensus, if a QUIT command was issued before the reply had completed. Now, the control port flushes all pending replies before closing the connection. Also fixed a spurious warning when a QUIT command is issued after a malformed or rejected AUTHENTICATE command, but before the connection was closed. Patch by Marcus Griep. Bugfix on 0.2.0.x; fixes bugs 1015 and 1016. - When we can't find an intro key for a v2 hidden service descriptor, fall back to the v0 hidden service descriptor and log a bug message. Workaround for bug 1024. - Fix a log message that did not respect the SafeLogging option. Resolves bug 1027. o Minor features: - If we're a relay and we change our IP address, be more verbose about the reason that made us change. Should help track down further bugs for relays on dynamic IP addresses. Changes in version 0.2.0.35 - 2009-06-24 o Security fix: - Avoid crashing in the presence of certain malformed descriptors. Found by lark, and by automated fuzzing. - Fix an edge case where a malicious exit relay could convince a controller that the client's DNS question resolves to an internal IP address. Bug found and fixed by "optimist"; bugfix on 0.1.2.8-beta. o Major bugfixes: - Finally fix the bug where dynamic-IP relays disappear when their IP address changes: directory mirrors were mistakenly telling them their old address if they asked via begin_dir, so they never got an accurate answer about their new address, so they just vanished after a day. For belt-and-suspenders, relays that don't set Address in their config now avoid using begin_dir for all direct connections. Should fix bugs 827, 883, and 900. - Fix a timing-dependent, allocator-dependent, DNS-related crash bug that would occur on some exit nodes when DNS failures and timeouts occurred in certain patterns. Fix for bug 957. o Minor bugfixes: - When starting with a cache over a few days old, do not leak memory for the obsolete router descriptors in it. Bugfix on 0.2.0.33; fixes bug 672. - Hidden service clients didn't use a cached service descriptor that was older than 15 minutes, but wouldn't fetch a new one either, because there was already one in the cache. Now, fetch a v2 descriptor unless the same descriptor was added to the cache within the last 15 minutes. Fixes bug 997; reported by Marcus Griep. Changes in version 0.2.1.16-rc - 2009-06-20 Tor 0.2.1.16-rc speeds up performance for fast exit relays, and fixes a bunch of minor bugs. o Security fixes: - Fix an edge case where a malicious exit relay could convince a controller that the client's DNS question resolves to an internal IP address. Bug found and fixed by "optimist"; bugfix on 0.1.2.8-beta. o Major performance improvements (on 0.2.0.x): - Disable and refactor some debugging checks that forced a linear scan over the whole server-side DNS cache. These accounted for over 50% of CPU time on a relatively busy exit node's gprof profile. Found by Jacob. - Disable some debugging checks that appeared in exit node profile data. o Minor features: - Update to the "June 3 2009" ip-to-country file. - Do not have tor-resolve automatically refuse all .onion addresses; if AutomapHostsOnResolve is set in your torrc, this will work fine. o Minor bugfixes (on 0.2.0.x): - Log correct error messages for DNS-related network errors on Windows. - Fix a race condition that could cause crashes or memory corruption when running as a server with a controller listening for log messages. - Avoid crashing when we have a policy specified in a DirPolicy or SocksPolicy or ReachableAddresses option with ports set on it, and we re-load the policy. May fix bug 996. - Hidden service clients didn't use a cached service descriptor that was older than 15 minutes, but wouldn't fetch a new one either, because there was already one in the cache. Now, fetch a v2 descriptor unless the same descriptor was added to the cache within the last 15 minutes. Fixes bug 997; reported by Marcus Griep. o Minor bugfixes (on 0.2.1.x): - Don't warn users about low port and hibernation mix when they provide a *ListenAddress directive to fix that. Bugfix on 0.2.1.15-rc. - When switching back and forth between bridge mode, do not start gathering GeoIP data until two hours have passed. - Do not complain that the user has requested an excluded node as an exit when the node is not really an exit. This could happen because the circuit was for testing, or an introduction point. Fix for bug 984. Changes in version 0.2.1.15-rc - 2009-05-25 Tor 0.2.1.15-rc marks the second release candidate for the 0.2.1.x series. It fixes a major bug on fast exit relays, as well as a variety of more minor bugs. o Major bugfixes (on 0.2.0.x): - Fix a timing-dependent, allocator-dependent, DNS-related crash bug that would occur on some exit nodes when DNS failures and timeouts occurred in certain patterns. Fix for bug 957. o Minor bugfixes (on 0.2.0.x): - Actually return -1 in the error case for read_bandwidth_usage(). Harmless bug, since we currently don't care about the return value anywhere. Bugfix on 0.2.0.9-alpha. - Provide a more useful log message if bug 977 (related to buffer freelists) ever reappears, and do not crash right away. - Fix an assertion failure on 64-bit platforms when we allocated memory right up to the end of a memarea, then realigned the memory one step beyond the end. Fixes a possible cause of bug 930. - Protect the count of open sockets with a mutex, so we can't corrupt it when two threads are closing or opening sockets at once. Fix for bug 939. Bugfix on 0.2.0.1-alpha. - Don't allow a bridge to publish its router descriptor to a non-bridge directory authority. Fixes part of bug 932. - When we change to or from being a bridge, reset our counts of client usage by country. Fixes bug 932. - Fix a bug that made stream bandwidth get misreported to the controller. - Stop using malloc_usable_size() to use more area than we had actually allocated: it was safe, but made valgrind really unhappy. - Fix a memory leak when v3 directory authorities load their keys and cert from disk. Bugfix on 0.2.0.1-alpha. o Minor bugfixes (on 0.2.1.x): - Fix use of freed memory when deciding to mark a non-addable descriptor as never-downloadable. Bugfix on 0.2.1.9-alpha. Changes in version 0.2.1.14-rc - 2009-04-12 Tor 0.2.1.14-rc marks the first release candidate for the 0.2.1.x series. It begins fixing some major performance problems, and also finally addresses the bug that was causing relays on dynamic IP addresses to fall out of the directory. o Major features: - Clients replace entry guards that were chosen more than a few months ago. This change should significantly improve client performance, especially once more people upgrade, since relays that have been a guard for a long time are currently overloaded. o Major bugfixes (on 0.2.0): - Finally fix the bug where dynamic-IP relays disappear when their IP address changes: directory mirrors were mistakenly telling them their old address if they asked via begin_dir, so they never got an accurate answer about their new address, so they just vanished after a day. For belt-and-suspenders, relays that don't set Address in their config now avoid using begin_dir for all direct connections. Should fix bugs 827, 883, and 900. - Relays were falling out of the networkstatus consensus for part of a day if they changed their local config but the authorities discarded their new descriptor as "not sufficiently different". Now directory authorities accept a descriptor as changed if bandwidthrate or bandwidthburst changed. Partial fix for bug 962; patch by Sebastian. - Avoid crashing in the presence of certain malformed descriptors. Found by lark, and by automated fuzzing. o Minor features: - When generating circuit events with verbose nicknames for controllers, try harder to look up nicknames for routers on a circuit. (Previously, we would look in the router descriptors we had for nicknames, but not in the consensus.) Partial fix for bug 941. - If the bridge config line doesn't specify a port, assume 443. This makes bridge lines a bit smaller and easier for users to understand. - Raise the minimum bandwidth to be a relay from 20000 bytes to 20480 bytes (aka 20KB/s), to match our documentation. Also update directory authorities so they always assign the Fast flag to relays with 20KB/s of capacity. Now people running relays won't suddenly find themselves not seeing any use, if the network gets faster on average. - Update to the "April 3 2009" ip-to-country file. o Minor bugfixes: - Avoid trying to print raw memory to the logs when we decide to give up on downloading a given relay descriptor. Bugfix on 0.2.1.9-alpha. - In tor-resolve, when the Tor client to use is specified by :, actually use the specified port rather than defaulting to 9050. Bugfix on 0.2.1.6-alpha. - Make directory usage recording work again. Bugfix on 0.2.1.6-alpha. - When starting with a cache over a few days old, do not leak memory for the obsolete router descriptors in it. Bugfix on 0.2.0.33. - Avoid double-free on list of successfully uploaded hidden service discriptors. Fix for bug 948. Bugfix on 0.2.1.6-alpha. - Change memarea_strndup() implementation to work even when duplicating a string at the end of a page. This bug was harmless for now, but could have meant crashes later. Fix by lark. Bugfix on 0.2.1.1-alpha. - Limit uploaded directory documents to be 16M rather than 500K. The directory authorities were refusing v3 consensus votes from other authorities, since the votes are now 504K. Fixes bug 959; bugfix on 0.0.2pre17 (where we raised it from 50K to 500K ;). - Directory authorities should never send a 503 "busy" response to requests for votes or keys. Bugfix on 0.2.0.8-alpha; exposed by bug 959. Changes in version 0.2.1.13-alpha - 2009-03-09 Tor 0.2.1.13-alpha includes another big pile of minor bugfixes and cleanups. We're finally getting close to a release candidate. o Major bugfixes: - Correctly update the list of which countries we exclude as exits, when the GeoIP file is loaded or reloaded. Diagnosed by lark. Bugfix on 0.2.1.6-alpha. o Minor bugfixes (on 0.2.0.x and earlier): - Automatically detect MacOSX versions earlier than 10.4.0, and disable kqueue from inside Tor when running with these versions. We previously did this from the startup script, but that was no help to people who didn't use the startup script. Resolves bug 863. - When we had picked an exit node for a connection, but marked it as "optional", and it turned out we had no onion key for the exit, stop wanting that exit and try again. This situation may not be possible now, but will probably become feasible with proposal 158. Spotted by rovv. Fixes another case of bug 752. - Clients no longer cache certificates for authorities they do not recognize. Bugfix on 0.2.0.9-alpha. - When we can't transmit a DNS request due to a network error, retry it after a while, and eventually transmit a failing response to the RESOLVED cell. Bugfix on 0.1.2.5-alpha. - If the controller claimed responsibility for a stream, but that stream never finished making its connection, it would live forever in circuit_wait state. Now we close it after SocksTimeout seconds. Bugfix on 0.1.2.7-alpha; reported by Mike Perry. - Drop begin cells to a hidden service if they come from the middle of a circuit. Patch from lark. - When we erroneously receive two EXTEND cells for the same circuit ID on the same connection, drop the second. Patch from lark. - Fix a crash that occurs on exit nodes when a nameserver request timed out. Bugfix on 0.1.2.1-alpha; our CLEAR debugging code had been suppressing the bug since 0.1.2.10-alpha. Partial fix for bug 929. - Do not assume that a stack-allocated character array will be 64-bit aligned on platforms that demand that uint64_t access is aligned. Possible fix for bug 604. - Parse dates and IPv4 addresses in a locale- and libc-independent manner, to avoid platform-dependent behavior on malformed input. - Build correctly when configured to build outside the main source path. Patch from Michael Gold. - We were already rejecting relay begin cells with destination port of 0. Now also reject extend cells with destination port or address of 0. Suggested by lark. o Minor bugfixes (on 0.2.1.x): - Don't re-extend introduction circuits if we ran out of RELAY_EARLY cells. Bugfix on 0.2.1.3-alpha. Fixes more of bug 878. - If we're an exit node, scrub the IP address to which we are exiting in the logs. Bugfix on 0.2.1.8-alpha. o Minor features: - On Linux, use the prctl call to re-enable core dumps when the user is option is set. - New controller event NEWCONSENSUS that lists the networkstatus lines for every recommended relay. Now controllers like Torflow can keep up-to-date on which relays they should be using. - Update to the "February 26 2009" ip-to-country file. Changes in version 0.2.0.34 - 2009-02-08 Tor 0.2.0.34 features several more security-related fixes. You should upgrade, especially if you run an exit relay (remote crash) or a directory authority (remote infinite loop), or you're on an older (pre-XP) or not-recently-patched Windows (remote exploit). This release marks end-of-life for Tor 0.1.2.x. Those Tor versions have many known flaws, and nobody should be using them. You should upgrade. If you're using a Linux or BSD and its packages are obsolete, stop using those packages and upgrade anyway. o Security fixes: - Fix an infinite-loop bug on handling corrupt votes under certain circumstances. Bugfix on 0.2.0.8-alpha. - Fix a temporary DoS vulnerability that could be performed by a directory mirror. Bugfix on 0.2.0.9-alpha; reported by lark. - Avoid a potential crash on exit nodes when processing malformed input. Remote DoS opportunity. Bugfix on 0.2.0.33. - Do not accept incomplete ipv4 addresses (like 192.168.0) as valid. Spec conformance issue. Bugfix on Tor 0.0.2pre27. o Minor bugfixes: - Fix compilation on systems where time_t is a 64-bit integer. Patch from Matthias Drochner. - Don't consider expiring already-closed client connections. Fixes bug 893. Bugfix on 0.0.2pre20. Changes in version 0.2.1.12-alpha - 2009-02-08 Tor 0.2.1.12-alpha features several more security-related fixes. You should upgrade, especially if you run an exit relay (remote crash) or a directory authority (remote infinite loop), or you're on an older (pre-XP) or not-recently-patched Windows (remote exploit). It also includes a big pile of minor bugfixes and cleanups. o Security fixes: - Fix an infinite-loop bug on handling corrupt votes under certain circumstances. Bugfix on 0.2.0.8-alpha. - Fix a temporary DoS vulnerability that could be performed by a directory mirror. Bugfix on 0.2.0.9-alpha; reported by lark. - Avoid a potential crash on exit nodes when processing malformed input. Remote DoS opportunity. Bugfix on 0.2.1.7-alpha. o Minor bugfixes: - Let controllers actually ask for the "clients_seen" event for getting usage summaries on bridge relays. Bugfix on 0.2.1.10-alpha; reported by Matt Edman. - Fix a compile warning on OSX Panther. Fixes bug 913; bugfix against 0.2.1.11-alpha. - Fix a bug in address parsing that was preventing bridges or hidden service targets from being at IPv6 addresses. - Solve a bug that kept hardware crypto acceleration from getting enabled when accounting was turned on. Fixes bug 907. Bugfix on 0.0.9pre6. - Remove a bash-ism from configure.in to build properly on non-Linux platforms. Bugfix on 0.2.1.1-alpha. - Fix code so authorities _actually_ send back X-Descriptor-Not-New headers. Bugfix on 0.2.0.10-alpha. - Don't consider expiring already-closed client connections. Fixes bug 893. Bugfix on 0.0.2pre20. - Fix another interesting corner-case of bug 891 spotted by rovv: Previously, if two hosts had different amounts of clock drift, and one of them created a new connection with just the wrong timing, the other might decide to deprecate the new connection erroneously. Bugfix on 0.1.1.13-alpha. - Resolve a very rare crash bug that could occur when the user forced a nameserver reconfiguration during the middle of a nameserver probe. Fixes bug 526. Bugfix on 0.1.2.1-alpha. - Support changing value of ServerDNSRandomizeCase during SIGHUP. Bugfix on 0.2.1.7-alpha. - If we're using bridges and our network goes away, be more willing to forgive our bridges and try again when we get an application request. Bugfix on 0.2.0.x. o Minor features: - Support platforms where time_t is 64 bits long. (Congratulations, NetBSD!) Patch from Matthias Drochner. - Add a 'getinfo status/clients-seen' controller command, in case controllers want to hear clients_seen events but connect late. o Build changes: - Disable GCC's strict alias optimization by default, to avoid the likelihood of its introducing subtle bugs whenever our code violates the letter of C99's alias rules. Changes in version 0.2.0.33 - 2009-01-21 Tor 0.2.0.33 fixes a variety of bugs that were making relays less useful to users. It also finally fixes a bug where a relay or client that's been off for many days would take a long time to bootstrap. This update also fixes an important security-related bug reported by Ilja van Sprundel. You should upgrade. (We'll send out more details about the bug once people have had some time to upgrade.) o Security fixes: - Fix a heap-corruption bug that may be remotely triggerable on some platforms. Reported by Ilja van Sprundel. o Major bugfixes: - When a stream at an exit relay is in state "resolving" or "connecting" and it receives an "end" relay cell, the exit relay would silently ignore the end cell and not close the stream. If the client never closes the circuit, then the exit relay never closes the TCP connection. Bug introduced in Tor 0.1.2.1-alpha; reported by "wood". - When sending CREATED cells back for a given circuit, use a 64-bit connection ID to find the right connection, rather than an addr:port combination. Now that we can have multiple OR connections between the same ORs, it is no longer possible to use addr:port to uniquely identify a connection. - Bridge relays that had DirPort set to 0 would stop fetching descriptors shortly after startup, and then briefly resume after a new bandwidth test and/or after publishing a new bridge descriptor. Bridge users that try to bootstrap from them would get a recent networkstatus but would get descriptors from up to 18 hours earlier, meaning most of the descriptors were obsolete already. Reported by Tas; bugfix on 0.2.0.13-alpha. - Prevent bridge relays from serving their 'extrainfo' document to anybody who asks, now that extrainfo docs include potentially sensitive aggregated client geoip summaries. Bugfix on 0.2.0.13-alpha. - If the cached networkstatus consensus is more than five days old, discard it rather than trying to use it. In theory it could be useful because it lists alternate directory mirrors, but in practice it just means we spend many minutes trying directory mirrors that are long gone from the network. Also discard router descriptors as we load them if they are more than five days old, since the onion key is probably wrong by now. Bugfix on 0.2.0.x. Fixes bug 887. o Minor bugfixes: - Do not mark smartlist_bsearch_idx() function as ATTR_PURE. This bug could make gcc generate non-functional binary search code. Bugfix on 0.2.0.10-alpha. - Build correctly on platforms without socklen_t. - Compile without warnings on solaris. - Avoid potential crash on internal error during signature collection. Fixes bug 864. Patch from rovv. - Correct handling of possible malformed authority signing key certificates with internal signature types. Fixes bug 880. Bugfix on 0.2.0.3-alpha. - Fix a hard-to-trigger resource leak when logging credential status. CID 349. - When we can't initialize DNS because the network is down, do not automatically stop Tor from starting. Instead, we retry failed dns_init() every 10 minutes, and change the exit policy to reject *:* until one succeeds. Fixes bug 691. - Use 64 bits instead of 32 bits for connection identifiers used with the controller protocol, to greatly reduce risk of identifier reuse. - When we're choosing an exit node for a circuit, and we have no pending streams, choose a good general exit rather than one that supports "all the pending streams". Bugfix on 0.1.1.x. Fix by rovv. - Fix another case of assuming, when a specific exit is requested, that we know more than the user about what hosts it allows. Fixes one case of bug 752. Patch from rovv. - Clip the MaxCircuitDirtiness config option to a minimum of 10 seconds. Warn the user if lower values are given in the configuration. Bugfix on 0.1.0.1-rc. Patch by Sebastian. - Clip the CircuitBuildTimeout to a minimum of 30 seconds. Warn the user if lower values are given in the configuration. Bugfix on 0.1.1.17-rc. Patch by Sebastian. - Fix a memory leak when we decline to add a v2 rendezvous descriptor to the cache because we already had a v0 descriptor with the same ID. Bugfix on 0.2.0.18-alpha. - Fix a race condition when freeing keys shared between main thread and CPU workers that could result in a memory leak. Bugfix on 0.1.0.1-rc. Fixes bug 889. - Send a valid END cell back when a client tries to connect to a nonexistent hidden service port. Bugfix on 0.1.2.15. Fixes bug 840. Patch from rovv. - Check which hops rendezvous stream cells are associated with to prevent possible guess-the-streamid injection attacks from intermediate hops. Fixes another case of bug 446. Based on patch from rovv. - If a broken client asks a non-exit router to connect somewhere, do not even do the DNS lookup before rejecting the connection. Fixes another case of bug 619. Patch from rovv. - When a relay gets a create cell it can't decrypt (e.g. because it's using the wrong onion key), we were dropping it and letting the client time out. Now actually answer with a destroy cell. Fixes bug 904. Bugfix on 0.0.2pre8. o Minor bugfixes (hidden services): - Do not throw away existing introduction points on SIGHUP. Bugfix on 0.0.6pre1. Patch by Karsten. Fixes bug 874. o Minor features: - Report the case where all signatures in a detached set are rejected differently than the case where there is an error handling the detached set. - When we realize that another process has modified our cached descriptors, print out a more useful error message rather than triggering an assertion. Fixes bug 885. Patch from Karsten. - Implement the 0x20 hack to better resist DNS poisoning: set the case on outgoing DNS requests randomly, and reject responses that do not match the case correctly. This logic can be disabled with the ServerDNSRamdomizeCase setting, if you are using one of the 0.3% of servers that do not reliably preserve case in replies. See "Increased DNS Forgery Resistance through 0x20-Bit Encoding" for more info. - Check DNS replies for more matching fields to better resist DNS poisoning. - Never use OpenSSL compression: it wastes RAM and CPU trying to compress cells, which are basically all encrypted, compressed, or both. Changes in version 0.2.1.11-alpha - 2009-01-20 Tor 0.2.1.11-alpha finishes fixing the "if your Tor is off for a week it will take a long time to bootstrap again" bug. It also fixes an important security-related bug reported by Ilja van Sprundel. You should upgrade. (We'll send out more details about the bug once people have had some time to upgrade.) o Security fixes: - Fix a heap-corruption bug that may be remotely triggerable on some platforms. Reported by Ilja van Sprundel. o Major bugfixes: - Discard router descriptors as we load them if they are more than five days old. Otherwise if Tor is off for a long time and then starts with cached descriptors, it will try to use the onion keys in those obsolete descriptors when building circuits. Bugfix on 0.2.0.x. Fixes bug 887. o Minor features: - Try to make sure that the version of Libevent we're running with is binary-compatible with the one we built with. May address bug 897 and others. - Make setting ServerDNSRandomizeCase to 0 actually work. Bugfix for bug 905. Bugfix on 0.2.1.7-alpha. - Add a new --enable-local-appdata configuration switch to change the default location of the datadir on win32 from APPDATA to LOCAL_APPDATA. In the future, we should migrate to LOCAL_APPDATA entirely. Patch from coderman. o Minor bugfixes: - Make outbound DNS packets respect the OutboundBindAddress setting. Fixes the bug part of bug 798. Bugfix on 0.1.2.2-alpha. - When our circuit fails at the first hop (e.g. we get a destroy cell back), avoid using that OR connection anymore, and also tell all the one-hop directory requests waiting for it that they should fail. Bugfix on 0.2.1.3-alpha. - In the torify(1) manpage, mention that tsocks will leak your DNS requests. Changes in version 0.2.1.10-alpha - 2009-01-06 Tor 0.2.1.10-alpha fixes two major bugs in bridge relays (one that would make the bridge relay not so useful if it had DirPort set to 0, and one that could let an attacker learn a little bit of information about the bridge's users), and a bug that would cause your Tor relay to ignore a circuit create request it can't decrypt (rather than reply with an error). It also fixes a wide variety of other bugs. o Major bugfixes: - If the cached networkstatus consensus is more than five days old, discard it rather than trying to use it. In theory it could be useful because it lists alternate directory mirrors, but in practice it just means we spend many minutes trying directory mirrors that are long gone from the network. Helps bug 887 a bit; bugfix on 0.2.0.x. - Bridge relays that had DirPort set to 0 would stop fetching descriptors shortly after startup, and then briefly resume after a new bandwidth test and/or after publishing a new bridge descriptor. Bridge users that try to bootstrap from them would get a recent networkstatus but would get descriptors from up to 18 hours earlier, meaning most of the descriptors were obsolete already. Reported by Tas; bugfix on 0.2.0.13-alpha. - Prevent bridge relays from serving their 'extrainfo' document to anybody who asks, now that extrainfo docs include potentially sensitive aggregated client geoip summaries. Bugfix on 0.2.0.13-alpha. o Minor features: - New controller event "clients_seen" to report a geoip-based summary of which countries we've seen clients from recently. Now controllers like Vidalia can show bridge operators that they're actually making a difference. - Build correctly against versions of OpenSSL 0.9.8 or later built without support for deprecated functions. - Update to the "December 19 2008" ip-to-country file. o Minor bugfixes (on 0.2.0.x): - Authorities now vote for the Stable flag for any router whose weighted MTBF is at least 5 days, regardless of the mean MTBF. - Do not remove routers as too old if we do not have any consensus document. Bugfix on 0.2.0.7-alpha. - Do not accept incomplete ipv4 addresses (like 192.168.0) as valid. Spec conformance issue. Bugfix on Tor 0.0.2pre27. - When an exit relay resolves a stream address to a local IP address, do not just keep retrying that same exit relay over and over. Instead, just close the stream. Addresses bug 872. Bugfix on 0.2.0.32. Patch from rovv. - If a hidden service sends us an END cell, do not consider retrying the connection; just close it. Patch from rovv. - When we made bridge authorities stop serving bridge descriptors over unencrypted links, we also broke DirPort reachability testing for bridges. So bridges with a non-zero DirPort were printing spurious warns to their logs. Bugfix on 0.2.0.16-alpha. Fixes bug 709. - When a relay gets a create cell it can't decrypt (e.g. because it's using the wrong onion key), we were dropping it and letting the client time out. Now actually answer with a destroy cell. Fixes bug 904. Bugfix on 0.0.2pre8. - Squeeze 2-5% out of client performance (according to oprofile) by improving the implementation of some policy-manipulation functions. o Minor bugfixes (on 0.2.1.x): - Make get_interface_address() function work properly again; stop guessing the wrong parts of our address as our address. - Do not cannibalize a circuit if we're out of RELAY_EARLY cells to send on that circuit. Otherwise we might violate the proposal-110 limit. Bugfix on 0.2.1.3-alpha. Partial fix for bug 878. Diagnosis thanks to Karsten. - When we're sending non-EXTEND cells to the first hop in a circuit, for example to use an encrypted directory connection, we don't need to use RELAY_EARLY cells: the first hop knows what kind of cell it is, and nobody else can even see the cell type. Conserving RELAY_EARLY cells makes it easier to cannibalize circuits like this later. - Stop logging nameserver addresses in reverse order. - If we are retrying a directory download slowly over and over, do not automatically give up after the 254th failure. Bugfix on 0.2.1.9-alpha. - Resume reporting accurate "stream end" reasons to the local control port. They were lost in the changes for Proposal 148. Bugfix on 0.2.1.9-alpha. o Deprecated and removed features: - The old "tor --version --version" command, which would print out the subversion "Id" of most of the source files, is now removed. It turned out to be less useful than we'd expected, and harder to maintain. o Code simplifications and refactoring: - Change our header file guard macros to be less likely to conflict with system headers. Adam Langley noticed that we were conflicting with log.h on Android. - Tool-assisted documentation cleanup. Nearly every function or static variable in Tor should have its own documentation now. Changes in version 0.2.1.9-alpha - 2008-12-25 Tor 0.2.1.9-alpha fixes many more bugs, some of them security-related. o New directory authorities: - gabelmoo (the authority run by Karsten Loesing) now has a new IP address. o Security fixes: - Never use a connection with a mismatched address to extend a circuit, unless that connection is canonical. A canonical connection is one whose address is authenticated by the router's identity key, either in a NETINFO cell or in a router descriptor. - Avoid a possible memory corruption bug when receiving hidden service descriptors. Bugfix on 0.2.1.6-alpha. o Major bugfixes: - Fix a logic error that would automatically reject all but the first configured DNS server. Bugfix on 0.2.1.5-alpha. Possible fix for part of bug 813/868. Bug spotted by coderman. - When a stream at an exit relay is in state "resolving" or "connecting" and it receives an "end" relay cell, the exit relay would silently ignore the end cell and not close the stream. If the client never closes the circuit, then the exit relay never closes the TCP connection. Bug introduced in 0.1.2.1-alpha; reported by "wood". - When we can't initialize DNS because the network is down, do not automatically stop Tor from starting. Instead, retry failed dns_init() every 10 minutes, and change the exit policy to reject *:* until one succeeds. Fixes bug 691. o Minor features: - Give a better error message when an overzealous init script says "sudo -u username tor --user username". Makes Bug 882 easier for users to diagnose. - When a directory authority gives us a new guess for our IP address, log which authority we used. Hopefully this will help us debug the recent complaints about bad IP address guesses. - Detect svn revision properly when we're using git-svn. - Try not to open more than one descriptor-downloading connection to an authority at once. This should reduce load on directory authorities. Fixes bug 366. - Add cross-certification to newly generated certificates, so that a signing key is enough information to look up a certificate. Partial implementation of proposal 157. - Start serving certificates by pairs. Partial implementation of proposal 157. - Clients now never report any stream end reason except 'MISC'. Implements proposal 148. - On platforms with a maximum syslog string length, truncate syslog messages to that length ourselves, rather than relying on the system to do it for us. - Optimize out calls to time(NULL) that occur for every IO operation, or for every cell. On systems where time() is a slow syscall, this fix will be slightly helpful. - Exit servers can now answer resolve requests for ip6.arpa addresses. - When we download a descriptor that we then immediately (as a directory authority) reject, do not retry downloading it right away. Should save some bandwidth on authorities. Fix for bug 888. Patch by Sebastian Hahn. - When a download gets us zero good descriptors, do not notify Tor that new directory information has arrived. - Avoid some nasty corner cases in the logic for marking connections as too old or obsolete or noncanonical for circuits. Partial bugfix on bug 891. o Minor features (controller): - New CONSENSUS_ARRIVED event to note when a new consensus has been fetched and validated. - When we realize that another process has modified our cached descriptors file, print out a more useful error message rather than triggering an assertion. Fixes bug 885. Patch from Karsten. - Add an internal-use-only __ReloadTorrcOnSIGHUP option for controllers to prevent SIGHUP from reloading the configuration. Fixes bug 856. o Minor bugfixes: - Resume using the correct "REASON=" stream when telling the controller why we closed a stream. Bugfix in 0.2.1.1-alpha. - When a canonical connection appears later in our internal list than a noncanonical one for a given OR ID, always use the canonical one. Bugfix on 0.2.0.12-alpha. Fixes bug 805. Spotted by rovv. - Clip the MaxCircuitDirtiness config option to a minimum of 10 seconds. Warn the user if lower values are given in the configuration. Bugfix on 0.1.0.1-rc. Patch by Sebastian. - Clip the CircuitBuildTimeout to a minimum of 30 seconds. Warn the user if lower values are given in the configuration. Bugfix on 0.1.1.17-rc. Patch by Sebastian. - Fix a race condition when freeing keys shared between main thread and CPU workers that could result in a memory leak. Bugfix on 0.1.0.1-rc. Fixes bug 889. o Minor bugfixes (hidden services): - Do not throw away existing introduction points on SIGHUP (bugfix on 0.0.6pre1); also, do not stall hidden services because we're throwing away introduction points; bugfix on 0.2.1.7-alpha. Spotted by John Brooks. Patch by Karsten. Fixes bug 874. - Fix a memory leak when we decline to add a v2 rendezvous descriptor to the cache because we already had a v0 descriptor with the same ID. Bugfix on 0.2.0.18-alpha. o Deprecated and removed features: - RedirectExits has been removed. It was deprecated since 0.2.0.3-alpha. - Finally remove deprecated "EXTENDED_FORMAT" controller feature. It has been called EXTENDED_EVENTS since 0.1.2.4-alpha. - Cell pools are now always enabled; --disable-cell-pools is ignored. o Code simplifications and refactoring: - Rename the confusing or_is_obsolete field to the more appropriate is_bad_for_new_circs, and move it to or_connection_t where it belongs. - Move edge-only flags from connection_t to edge_connection_t: not only is this better coding, but on machines of plausible alignment, it should save 4-8 bytes per connection_t. "Every little bit helps." - Rename ServerDNSAllowBrokenResolvConf to ServerDNSAllowBrokenConfig for consistency; keep old option working for backward compatibility. - Simplify the code for finding connections to use for a circuit. Changes in version 0.2.1.8-alpha - 2008-12-08 Tor 0.2.1.8-alpha fixes some crash bugs in earlier alpha releases, builds better on unusual platforms like Solaris and old OS X, and fixes a variety of other issues. o Major features: - New DirPortFrontPage option that takes an html file and publishes it as "/" on the DirPort. Now relay operators can provide a disclaimer without needing to set up a separate webserver. There's a sample disclaimer in contrib/tor-exit-notice.html. o Security fixes: - When the client is choosing entry guards, now it selects at most one guard from a given relay family. Otherwise we could end up with all of our entry points into the network run by the same operator. Suggested by Camilo Viecco. Fix on 0.1.1.11-alpha. o Major bugfixes: - Fix a DOS opportunity during the voting signature collection process at directory authorities. Spotted by rovv. Bugfix on 0.2.0.x. - Fix a possible segfault when establishing an exit connection. Bugfix on 0.2.1.5-alpha. o Minor bugfixes: - Get file locking working on win32. Bugfix on 0.2.1.6-alpha. Fixes bug 859. - Made Tor a little less aggressive about deleting expired certificates. Partial fix for bug 854. - Stop doing unaligned memory access that generated bus errors on sparc64. Bugfix on 0.2.0.10-alpha. Fix for bug 862. - Fix a crash bug when changing EntryNodes from the controller. Bugfix on 0.2.1.6-alpha. Fix for bug 867. Patched by Sebastian. - Make USR2 log-level switch take effect immediately. Bugfix on 0.1.2.8-beta. - If one win32 nameserver fails to get added, continue adding the rest, and don't automatically fail. - Use fcntl() for locking when flock() is not available. Should fix compilation on Solaris. Should fix Bug 873. Bugfix on 0.2.1.6-alpha. - Do not mark smartlist_bsearch_idx() function as ATTR_PURE. This bug could make gcc generate non-functional binary search code. Bugfix on 0.2.0.10-alpha. - Build correctly on platforms without socklen_t. - Avoid potential crash on internal error during signature collection. Fixes bug 864. Patch from rovv. - Do not use C's stdio library for writing to log files. This will improve logging performance by a minute amount, and will stop leaking fds when our disk is full. Fixes bug 861. - Stop erroneous use of O_APPEND in cases where we did not in fact want to re-seek to the end of a file before every last write(). - Correct handling of possible malformed authority signing key certificates with internal signature types. Fixes bug 880. Bugfix on 0.2.0.3-alpha. - Fix a hard-to-trigger resource leak when logging credential status. CID 349. o Minor features: - Directory mirrors no longer fetch the v1 directory or running-routers files. They are obsolete, and nobody asks for them anymore. This is the first step to making v1 authorities obsolete. o Minor features (controller): - Return circuit purposes in response to GETINFO circuit-status. Fixes bug 858. Changes in version 0.2.0.32 - 2008-11-20 Tor 0.2.0.32 fixes a major security problem in Debian and Ubuntu packages (and maybe other packages) noticed by Theo de Raadt, fixes a smaller security flaw that might allow an attacker to access local services, further improves hidden service performance, and fixes a variety of other issues. o Security fixes: - The "User" and "Group" config options did not clear the supplementary group entries for the Tor process. The "User" option is now more robust, and we now set the groups to the specified user's primary group. The "Group" option is now ignored. For more detailed logging on credential switching, set CREDENTIAL_LOG_LEVEL in common/compat.c to LOG_NOTICE or higher. Patch by Jacob Appelbaum and Steven Murdoch. Bugfix on 0.0.2pre14. Fixes bug 848 and 857. - The "ClientDNSRejectInternalAddresses" config option wasn't being consistently obeyed: if an exit relay refuses a stream because its exit policy doesn't allow it, we would remember what IP address the relay said the destination address resolves to, even if it's an internal IP address. Bugfix on 0.2.0.7-alpha; patch by rovv. o Major bugfixes: - Fix a DOS opportunity during the voting signature collection process at directory authorities. Spotted by rovv. Bugfix on 0.2.0.x. o Major bugfixes (hidden services): - When fetching v0 and v2 rendezvous service descriptors in parallel, we were failing the whole hidden service request when the v0 descriptor fetch fails, even if the v2 fetch is still pending and might succeed. Similarly, if the last v2 fetch fails, we were failing the whole hidden service request even if a v0 fetch is still pending. Fixes bug 814. Bugfix on 0.2.0.10-alpha. - When extending a circuit to a hidden service directory to upload a rendezvous descriptor using a BEGIN_DIR cell, almost 1/6 of all requests failed, because the router descriptor has not been downloaded yet. In these cases, do not attempt to upload the rendezvous descriptor, but wait until the router descriptor is downloaded and retry. Likewise, do not attempt to fetch a rendezvous descriptor from a hidden service directory for which the router descriptor has not yet been downloaded. Fixes bug 767. Bugfix on 0.2.0.10-alpha. o Minor bugfixes: - Fix several infrequent memory leaks spotted by Coverity. - When testing for libevent functions, set the LDFLAGS variable correctly. Found by Riastradh. - Avoid a bug where the FastFirstHopPK 0 option would keep Tor from bootstrapping with tunneled directory connections. Bugfix on 0.1.2.5-alpha. Fixes bug 797. Found by Erwin Lam. - When asked to connect to A.B.exit:80, if we don't know the IP for A and we know that server B rejects most-but-not all connections to port 80, we would previously reject the connection. Now, we assume the user knows what they were asking for. Fixes bug 752. Bugfix on 0.0.9rc5. Diagnosed by BarkerJr. - If we overrun our per-second write limits a little, count this as having used up our write allocation for the second, and choke outgoing directory writes. Previously, we had only counted this when we had met our limits precisely. Fixes bug 824. Patch from by rovv. Bugfix on 0.2.0.x (??). - Remove the old v2 directory authority 'lefkada' from the default list. It has been gone for many months. - Stop doing unaligned memory access that generated bus errors on sparc64. Bugfix on 0.2.0.10-alpha. Fixes bug 862. - Make USR2 log-level switch take effect immediately. Bugfix on 0.1.2.8-beta. o Minor bugfixes (controller): - Make DNS resolved events into "CLOSED", not "FAILED". Bugfix on 0.1.2.5-alpha. Fix by Robert Hogan. Resolves bug 807. Changes in version 0.2.1.7-alpha - 2008-11-08 Tor 0.2.1.7-alpha fixes a major security problem in Debian and Ubuntu packages (and maybe other packages) noticed by Theo de Raadt, fixes a smaller security flaw that might allow an attacker to access local services, adds better defense against DNS poisoning attacks on exit relays, further improves hidden service performance, and fixes a variety of other issues. o Security fixes: - The "ClientDNSRejectInternalAddresses" config option wasn't being consistently obeyed: if an exit relay refuses a stream because its exit policy doesn't allow it, we would remember what IP address the relay said the destination address resolves to, even if it's an internal IP address. Bugfix on 0.2.0.7-alpha; patch by rovv. - The "User" and "Group" config options did not clear the supplementary group entries for the Tor process. The "User" option is now more robust, and we now set the groups to the specified user's primary group. The "Group" option is now ignored. For more detailed logging on credential switching, set CREDENTIAL_LOG_LEVEL in common/compat.c to LOG_NOTICE or higher. Patch by Jacob Appelbaum and Steven Murdoch. Bugfix on 0.0.2pre14. Fixes bug 848. - Do not use or believe expired v3 authority certificates. Patch from Karsten. Bugfix in 0.2.0.x. Fixes bug 851. o Minor features: - Now NodeFamily and MyFamily config options allow spaces in identity fingerprints, so it's easier to paste them in. Suggested by Lucky Green. - Implement the 0x20 hack to better resist DNS poisoning: set the case on outgoing DNS requests randomly, and reject responses that do not match the case correctly. This logic can be disabled with the ServerDNSRandomizeCase setting, if you are using one of the 0.3% of servers that do not reliably preserve case in replies. See "Increased DNS Forgery Resistance through 0x20-Bit Encoding" for more info. - Preserve case in replies to DNSPort requests in order to support the 0x20 hack for resisting DNS poisoning attacks. o Hidden service performance improvements: - When the client launches an introduction circuit, retry with a new circuit after 30 seconds rather than 60 seconds. - Launch a second client-side introduction circuit in parallel after a delay of 15 seconds (based on work by Christian Wilms). - Hidden services start out building five intro circuits rather than three, and when the first three finish they publish a service descriptor using those. Now we publish our service descriptor much faster after restart. o Minor bugfixes: - Minor fix in the warning messages when you're having problems bootstrapping; also, be more forgiving of bootstrap problems when we're still making incremental progress on a given bootstrap phase. - When we're choosing an exit node for a circuit, and we have no pending streams, choose a good general exit rather than one that supports "all the pending streams". Bugfix on 0.1.1.x. Fix by rovv. - Send a valid END cell back when a client tries to connect to a nonexistent hidden service port. Bugfix on 0.1.2.15. Fixes bug 840. Patch from rovv. - If a broken client asks a non-exit router to connect somewhere, do not even do the DNS lookup before rejecting the connection. Fixes another case of bug 619. Patch from rovv. - Fix another case of assuming, when a specific exit is requested, that we know more than the user about what hosts it allows. Fixes another case of bug 752. Patch from rovv. - Check which hops rendezvous stream cells are associated with to prevent possible guess-the-streamid injection attacks from intermediate hops. Fixes another case of bug 446. Based on patch from rovv. - Avoid using a negative right-shift when comparing 32-bit addresses. Possible fix for bug 845 and bug 811. - Make the assert_circuit_ok() function work correctly on circuits that have already been marked for close. - Fix read-off-the-end-of-string error in unit tests when decoding introduction points. - Fix uninitialized size field for memory area allocation: may improve memory performance during directory parsing. - Treat duplicate certificate fetches as failures, so that we do not try to re-fetch an expired certificate over and over and over. - Do not say we're fetching a certificate when we'll in fact skip it because of a pending download. Changes in version 0.2.1.6-alpha - 2008-09-30 Tor 0.2.1.6-alpha further improves performance and robustness of hidden services, starts work on supporting per-country relay selection, and fixes a variety of smaller issues. o Major features: - Implement proposal 121: make it possible to build hidden services that only certain clients are allowed to connect to. This is enforced at several points, so that unauthorized clients are unable to send INTRODUCE cells to the service, or even (depending on the type of authentication) to learn introduction points. This feature raises the bar for certain kinds of active attacks against hidden services. Code by Karsten Loesing. - Relays now store and serve v2 hidden service descriptors by default, i.e., the new default value for HidServDirectoryV2 is 1. This is the last step in proposal 114, which aims to make hidden service lookups more reliable. - Start work to allow node restrictions to include country codes. The syntax to exclude nodes in a country with country code XX is "ExcludeNodes {XX}". Patch from Robert Hogan. It still needs some refinement to decide what config options should take priority if you ask to both use a particular node and exclude it. - Allow ExitNodes list to include IP ranges and country codes, just like the Exclude*Nodes lists. Patch from Robert Hogan. o Major bugfixes: - Fix a bug when parsing ports in tor_addr_port_parse() that caused Tor to fail to start if you had it configured to use a bridge relay. Fixes bug 809. Bugfix on 0.2.1.5-alpha. - When extending a circuit to a hidden service directory to upload a rendezvous descriptor using a BEGIN_DIR cell, almost 1/6 of all requests failed, because the router descriptor had not been downloaded yet. In these cases, we now wait until the router descriptor is downloaded, and then retry. Likewise, clients now skip over a hidden service directory if they don't yet have its router descriptor, rather than futilely requesting it and putting mysterious complaints in the logs. Fixes bug 767. Bugfix on 0.2.0.10-alpha. - When fetching v0 and v2 rendezvous service descriptors in parallel, we were failing the whole hidden service request when the v0 descriptor fetch fails, even if the v2 fetch is still pending and might succeed. Similarly, if the last v2 fetch fails, we were failing the whole hidden service request even if a v0 fetch is still pending. Fixes bug 814. Bugfix on 0.2.0.10-alpha. - DNS replies need to have names matching their requests, but these names should be in the questions section, not necessarily in the answers section. Fixes bug 823. Bugfix on 0.2.1.5-alpha. o Minor features: - Update to the "September 1 2008" ip-to-country file. - Allow ports 465 and 587 in the default exit policy again. We had rejected them in 0.1.0.15, because back in 2005 they were commonly misconfigured and ended up as spam targets. We hear they are better locked down these days. - Use a lockfile to make sure that two Tor processes are not simultaneously running with the same datadir. - Serve the latest v3 networkstatus consensus via the control port. Use "getinfo dir/status-vote/current/consensus" to fetch it. - Better logging about stability/reliability calculations on directory servers. - Drop the requirement to have an open dir port for storing and serving v2 hidden service descriptors. - Directory authorities now serve a /tor/dbg-stability.txt URL to help debug WFU and MTBF calculations. - Implement most of Proposal 152: allow specialized servers to permit single-hop circuits, and clients to use those servers to build single-hop circuits when using a specialized controller. Patch from Josh Albrecht. Resolves feature request 768. - Add a -p option to tor-resolve for specifying the SOCKS port: some people find host:port too confusing. - Make TrackHostExit mappings expire a while after their last use, not after their creation. Patch from Robert Hogan. - Provide circuit purposes along with circuit events to the controller. o Minor bugfixes: - Fix compile on OpenBSD 4.4-current. Bugfix on 0.2.1.5-alpha. Reported by Tas. - Fixed some memory leaks -- some quite frequent, some almost impossible to trigger -- based on results from Coverity. - When testing for libevent functions, set the LDFLAGS variable correctly. Found by Riastradh. - Fix an assertion bug in parsing policy-related options; possible fix for bug 811. - Catch and report a few more bootstrapping failure cases when Tor fails to establish a TCP connection. Cleanup on 0.2.1.x. - Avoid a bug where the FastFirstHopPK 0 option would keep Tor from bootstrapping with tunneled directory connections. Bugfix on 0.1.2.5-alpha. Fixes bug 797. Found by Erwin Lam. - When asked to connect to A.B.exit:80, if we don't know the IP for A and we know that server B rejects most-but-not all connections to port 80, we would previously reject the connection. Now, we assume the user knows what they were asking for. Fixes bug 752. Bugfix on 0.0.9rc5. Diagnosed by BarkerJr. - If we are not using BEGIN_DIR cells, don't attempt to contact hidden service directories if they have no advertised dir port. Bugfix on 0.2.0.10-alpha. - If we overrun our per-second write limits a little, count this as having used up our write allocation for the second, and choke outgoing directory writes. Previously, we had only counted this when we had met our limits precisely. Fixes bug 824. Patch by rovv. Bugfix on 0.2.0.x (??). - Avoid a "0 divided by 0" calculation when calculating router uptime at directory authorities. Bugfix on 0.2.0.8-alpha. - Make DNS resolved controller events into "CLOSED", not "FAILED". Bugfix on 0.1.2.5-alpha. Fix by Robert Hogan. Resolves bug 807. - Fix a bug where an unreachable relay would establish enough reachability testing circuits to do a bandwidth test -- if we already have a connection to the middle hop of the testing circuit, then it could establish the last hop by using the existing connection. Bugfix on 0.1.2.2-alpha, exposed when we made testing circuits no longer use entry guards in 0.2.1.3-alpha. - If we have correct permissions on $datadir, we complain to stdout and fail to start. But dangerous permissions on $datadir/cached-status/ would cause us to open a log and complain there. Now complain to stdout and fail to start in both cases. Fixes bug 820, reported by seeess. - Remove the old v2 directory authority 'lefkada' from the default list. It has been gone for many months. o Code simplifications and refactoring: - Revise the connection_new functions so that a more typesafe variant exists. This will work better with Coverity, and let us find any actual mistakes we're making here. - Refactor unit testing logic so that dmalloc can be used sensibly with unit tests to check for memory leaks. - Move all hidden-service related fields from connection and circuit structure to substructures: this way they won't eat so much memory. Changes in version 0.2.0.31 - 2008-09-03 Tor 0.2.0.31 addresses two potential anonymity issues, starts to fix a big bug we're seeing where in rare cases traffic from one Tor stream gets mixed into another stream, and fixes a variety of smaller issues. o Major bugfixes: - Make sure that two circuits can never exist on the same connection with the same circuit ID, even if one is marked for close. This is conceivably a bugfix for bug 779. Bugfix on 0.1.0.4-rc. - Relays now reject risky extend cells: if the extend cell includes a digest of all zeroes, or asks to extend back to the relay that sent the extend cell, tear down the circuit. Ideas suggested by rovv. - If not enough of our entry guards are available so we add a new one, we might use the new one even if it overlapped with the current circuit's exit relay (or its family). Anonymity bugfix pointed out by rovv. o Minor bugfixes: - Recover 3-7 bytes that were wasted per memory chunk. Fixes bug 794; bug spotted by rovv. Bugfix on 0.2.0.1-alpha. - Correctly detect the presence of the linux/netfilter_ipv4.h header when building against recent kernels. Bugfix on 0.1.2.1-alpha. - Pick size of default geoip filename string correctly on windows. Fixes bug 806. Bugfix on 0.2.0.30. - Make the autoconf script accept the obsolete --with-ssl-dir option as an alias for the actually-working --with-openssl-dir option. Fix the help documentation to recommend --with-openssl-dir. Based on a patch by "Dave". Bugfix on 0.2.0.1-alpha. - When using the TransPort option on OpenBSD, and using the User option to change UID and drop privileges, make sure to open /dev/pf before dropping privileges. Fixes bug 782. Patch from Christopher Davis. Bugfix on 0.1.2.1-alpha. - Try to attach connections immediately upon receiving a RENDEZVOUS2 or RENDEZVOUS_ESTABLISHED cell. This can save a second or two on the client side when connecting to a hidden service. Bugfix on 0.0.6pre1. Found and fixed by Christian Wilms; resolves bug 743. - When closing an application-side connection because its circuit is getting torn down, generate the stream event correctly. Bugfix on 0.1.2.x. Anonymous patch. Changes in version 0.2.1.5-alpha - 2008-08-31 Tor 0.2.1.5-alpha moves us closer to handling IPv6 destinations, puts in a lot of the infrastructure for adding authorization to hidden services, lays the groundwork for having clients read their load balancing information out of the networkstatus consensus rather than the individual router descriptors, addresses two potential anonymity issues, and fixes a variety of smaller issues. o Major features: - Convert many internal address representations to optionally hold IPv6 addresses. - Generate and accept IPv6 addresses in many protocol elements. - Make resolver code handle nameservers located at ipv6 addresses. - Begin implementation of proposal 121 ("Client authorization for hidden services"): configure hidden services with client authorization, publish descriptors for them, and configure authorization data for hidden services at clients. The next step is to actually access hidden services that perform client authorization. - More progress toward proposal 141: Network status consensus documents and votes now contain bandwidth information for each router and a summary of that router's exit policy. Eventually this will be used by clients so that they do not have to download every known descriptor before building circuits. o Major bugfixes (on 0.2.0.x and before): - When sending CREATED cells back for a given circuit, use a 64-bit connection ID to find the right connection, rather than an addr:port combination. Now that we can have multiple OR connections between the same ORs, it is no longer possible to use addr:port to uniquely identify a connection. - Relays now reject risky extend cells: if the extend cell includes a digest of all zeroes, or asks to extend back to the relay that sent the extend cell, tear down the circuit. Ideas suggested by rovv. - If not enough of our entry guards are available so we add a new one, we might use the new one even if it overlapped with the current circuit's exit relay (or its family). Anonymity bugfix pointed out by rovv. o Minor bugfixes: - Recover 3-7 bytes that were wasted per memory chunk. Fixes bug 794; bug spotted by rovv. Bugfix on 0.2.0.1-alpha. - When using the TransPort option on OpenBSD, and using the User option to change UID and drop privileges, make sure to open /dev/pf before dropping privileges. Fixes bug 782. Patch from Christopher Davis. Bugfix on 0.1.2.1-alpha. - Correctly detect the presence of the linux/netfilter_ipv4.h header when building against recent kernels. Bugfix on 0.1.2.1-alpha. - Add a missing safe_str() call for a debug log message. - Use 64 bits instead of 32 bits for connection identifiers used with the controller protocol, to greatly reduce risk of identifier reuse. - Make the autoconf script accept the obsolete --with-ssl-dir option as an alias for the actually-working --with-openssl-dir option. Fix the help documentation to recommend --with-openssl-dir. Based on a patch by "Dave". Bugfix on 0.2.0.1-alpha. o Minor features: - Rate-limit too-many-sockets messages: when they happen, they happen a lot. Resolves bug 748. - Resist DNS poisoning a little better by making sure that names in answer sections match. - Print the SOCKS5 error message string as well as the error code when a tor-resolve request fails. Patch from Jacob. Changes in version 0.2.1.4-alpha - 2008-08-04 Tor 0.2.1.4-alpha fixes a pair of crash bugs in 0.2.1.3-alpha. o Major bugfixes: - The address part of exit policies was not correctly written to router descriptors. This generated router descriptors that failed their self-checks. Noticed by phobos, fixed by Karsten. Bugfix on 0.2.1.3-alpha. - Tor triggered a false assert when extending a circuit to a relay but we already have a connection open to that relay. Noticed by phobos, fixed by Karsten. Bugfix on 0.2.1.3-alpha. o Minor bugfixes: - Fix a hidden service logging bug: in some edge cases, the router descriptor of a previously picked introduction point becomes obsolete and we need to give up on it rather than continually complaining that it has become obsolete. Observed by xiando. Bugfix on 0.2.1.3-alpha. o Removed features: - Take out the TestVia config option, since it was a workaround for a bug that was fixed in Tor 0.1.1.21. Changes in version 0.2.1.3-alpha - 2008-08-03 Tor 0.2.1.3-alpha implements most of the pieces to prevent infinite-length circuit attacks (see proposal 110); fixes a bug that might cause exit relays to corrupt streams they send back; allows address patterns (e.g. 255.128.0.0/16) to appear in ExcludeNodes and ExcludeExitNodes config options; and fixes a big pile of bugs. o Bootstrapping bugfixes (on 0.2.1.x-alpha): - Send a bootstrap problem "warn" event on the first problem if the reason is NO_ROUTE (that is, our network is down). o Major features: - Implement most of proposal 110: The first K cells to be sent along a circuit are marked as special "early" cells; only K "early" cells will be allowed. Once this code is universal, we can block certain kinds of DOS attack by requiring that EXTEND commands must be sent using an "early" cell. o Major bugfixes: - Try to attach connections immediately upon receiving a RENDEZVOUS2 or RENDEZVOUS_ESTABLISHED cell. This can save a second or two on the client side when connecting to a hidden service. Bugfix on 0.0.6pre1. Found and fixed by Christian Wilms; resolves bug 743. - Ensure that two circuits can never exist on the same connection with the same circuit ID, even if one is marked for close. This is conceivably a bugfix for bug 779; fixes a bug on 0.1.0.4-rc. o Minor features: - When relays do their initial bandwidth measurement, don't limit to just our entry guards for the test circuits. Otherwise we tend to have multiple test circuits going through a single entry guard, which makes our bandwidth test less accurate. Fixes part of bug 654; patch contributed by Josh Albrecht. - Add an ExcludeExitNodes option so users can list a set of nodes that should be be excluded from the exit node position, but allowed elsewhere. Implements proposal 151. - Allow address patterns (e.g., 255.128.0.0/16) to appear in ExcludeNodes and ExcludeExitNodes lists. - Change the implementation of ExcludeNodes and ExcludeExitNodes to be more efficient. Formerly it was quadratic in the number of servers; now it should be linear. Fixes bug 509. - Save 16-22 bytes per open circuit by moving the n_addr, n_port, and n_conn_id_digest fields into a separate structure that's only needed when the circuit has not yet attached to an n_conn. o Minor bugfixes: - Change the contrib/tor.logrotate script so it makes the new logs as "_tor:_tor" rather than the default, which is generally "root:wheel". Fixes bug 676, reported by Serge Koksharov. - Stop using __attribute__((nonnull)) with GCC: it can give us useful warnings (occasionally), but it can also cause the compiler to eliminate error-checking code. Suggested by Peter Gutmann. - When a hidden service is giving up on an introduction point candidate that was not included in the last published rendezvous descriptor, don't reschedule publication of the next descriptor. Fixes bug 763. Bugfix on 0.0.9.3. - Mark RendNodes, RendExcludeNodes, HiddenServiceNodes, and HiddenServiceExcludeNodes as obsolete: they never worked properly, and nobody claims to be using them. Fixes bug 754. Bugfix on 0.1.0.1-rc. Patch from Christian Wilms. - Fix a small alignment and memory-wasting bug on buffer chunks. Spotted by rovv. o Minor bugfixes (controller): - When closing an application-side connection because its circuit is getting torn down, generate the stream event correctly. Bugfix on 0.1.2.x. Anonymous patch. o Removed features: - Remove all backward-compatibility code to support relays running versions of Tor so old that they no longer work at all on the Tor network. Changes in version 0.2.0.30 - 2008-07-15 o Minor bugfixes: - Stop using __attribute__((nonnull)) with GCC: it can give us useful warnings (occasionally), but it can also cause the compiler to eliminate error-checking code. Suggested by Peter Gutmann. Changes in version 0.2.0.29-rc - 2008-07-08 Tor 0.2.0.29-rc fixes two big bugs with using bridges, fixes more hidden-service performance bugs, and fixes a bunch of smaller bugs. o Major bugfixes: - If you have more than one bridge but don't know their keys, you would only launch a request for the descriptor of the first one on your list. (Tor considered launching requests for the others, but found that it already had a connection on the way for $0000...0000 so it didn't open another.) Bugfix on 0.2.0.x. - If you have more than one bridge but don't know their keys, and the connection to one of the bridges failed, you would cancel all pending bridge connections. (After all, they all have the same digest.) Bugfix on 0.2.0.x. - When a hidden service was trying to establish an introduction point, and Tor had built circuits preemptively for such purposes, we were ignoring all the preemptive circuits and launching a new one instead. Bugfix on 0.2.0.14-alpha. - When a hidden service was trying to establish an introduction point, and Tor *did* manage to reuse one of the preemptively built circuits, it didn't correctly remember which one it used, so it asked for another one soon after, until there were no more preemptive circuits, at which point it launched one from scratch. Bugfix on 0.0.9.x. - Make directory servers include the X-Your-Address-Is: http header in their responses even for begin_dir conns. Now clients who only ever use begin_dir connections still have a way to learn their IP address. Fixes bug 737; bugfix on 0.2.0.22-rc. Reported by goldy. o Minor bugfixes: - Fix a macro/CPP interaction that was confusing some compilers: some GCCs don't like #if/#endif pairs inside macro arguments. Fixes bug 707. - Fix macro collision between OpenSSL 0.9.8h and Windows headers. Fixes bug 704; fix from Steven Murdoch. - When opening /dev/null in finish_daemonize(), do not pass the O_CREAT flag. Fortify was complaining, and correctly so. Fixes bug 742; fix from Michael Scherer. Bugfix on 0.0.2pre19. - Correctly detect transparent proxy support on Linux hosts that require in.h to be included before netfilter_ipv4.h. Patch from coderman. - Disallow session resumption attempts during the renegotiation stage of the v2 handshake protocol. Clients should never be trying session resumption at this point, but apparently some did, in ways that caused the handshake to fail. Bugfix on 0.2.0.20-rc. Bug found by Geoff Goodell. Changes in version 0.2.1.2-alpha - 2008-06-20 Tor 0.2.1.2-alpha includes a new "TestingTorNetwork" config option to make it easier to set up your own private Tor network; fixes several big bugs with using more than one bridge relay; fixes a big bug with offering hidden services quickly after Tor starts; and uses a better API for reporting potential bootstrapping problems to the controller. o Major features: - New TestingTorNetwork config option to allow adjustment of previously constant values that, while reasonable, could slow bootstrapping. Implements proposal 135. Patch from Karsten. o Major bugfixes: - If you have more than one bridge but don't know their digests, you would only learn a request for the descriptor of the first one on your list. (Tor considered launching requests for the others, but found that it already had a connection on the way for $0000...0000 so it didn't open another.) Bugfix on 0.2.0.x. - If you have more than one bridge but don't know their digests, and the connection to one of the bridges failed, you would cancel all pending bridge connections. (After all, they all have the same digest.) Bugfix on 0.2.0.x. - When establishing a hidden service, introduction points that originate from cannibalized circuits are completely ignored and not included in rendezvous service descriptors. This might be another reason for delay in making a hidden service available. Bugfix from long ago (0.0.9.x?) o Minor features: - Allow OpenSSL to use dynamic locks if it wants. - When building a consensus, do not include routers that are down. This will cut down 30% to 40% on consensus size. Implements proposal 138. - In directory authorities' approved-routers files, allow fingerprints with or without space. - Add a "GETINFO /status/bootstrap-phase" controller option, so the controller can query our current bootstrap state in case it attaches partway through and wants to catch up. - Send an initial "Starting" bootstrap status event, so we have a state to start out in. o Minor bugfixes: - Asking for a conditional consensus at .../consensus/ would crash a dirserver if it did not already have a consensus. Bugfix on 0.2.1.1-alpha. - Clean up some macro/CPP interactions: some GCC versions don't like #if/#endif pairs inside macro arguments. Fixes bug 707. Bugfix on 0.2.0.x. o Bootstrapping bugfixes (on 0.2.1.1-alpha): - Directory authorities shouldn't complain about bootstrapping problems just because they do a lot of reachability testing and some of the connection attempts fail. - Start sending "count" and "recommendation" key/value pairs in bootstrap problem status events, so the controller can hear about problems even before Tor decides they're worth reporting for sure. - If you're using bridges, generate "bootstrap problem" warnings as soon as you run out of working bridges, rather than waiting for ten failures -- which will never happen if you have less than ten bridges. - If we close our OR connection because there's been a circuit pending on it for too long, we were telling our bootstrap status events "REASON=NONE". Now tell them "REASON=TIMEOUT". Changes in version 0.2.1.1-alpha - 2008-06-13 Tor 0.2.1.1-alpha fixes a lot of memory fragmentation problems that were making the Tor process bloat especially on Linux; makes our TLS handshake blend in better; sends "bootstrap phase" status events to the controller, so it can keep the user informed of progress (and problems) fetching directory information and establishing circuits; and adds a variety of smaller features. o Major features: - More work on making our TLS handshake blend in: modify the list of ciphers advertised by OpenSSL in client mode to even more closely resemble a common web browser. We cheat a little so that we can advertise ciphers that the locally installed OpenSSL doesn't know about. - Start sending "bootstrap phase" status events to the controller, so it can keep the user informed of progress fetching directory information and establishing circuits. Also inform the controller if we think we're stuck at a particular bootstrap phase. Implements proposal 137. - Resume using OpenSSL's RAND_poll() for better (and more portable) cross-platform entropy collection again. We used to use it, then stopped using it because of a bug that could crash systems that called RAND_poll when they had a lot of fds open. It looks like the bug got fixed in late 2006. Our new behavior is to call RAND_poll() at startup, and to call RAND_poll() when we reseed later only if we have a non-buggy OpenSSL version. o Major bugfixes: - When we choose to abandon a new entry guard because we think our older ones might be better, close any circuits pending on that new entry guard connection. This fix should make us recover much faster when our network is down and then comes back. Bugfix on 0.1.2.8-beta; found by lodger. o Memory fixes and improvements: - Add a malloc_good_size implementation to OpenBSD_malloc_linux.c, to avoid unused RAM in buffer chunks and memory pools. - Speed up parsing and cut down on memory fragmentation by using stack-style allocations for parsing directory objects. Previously, this accounted for over 40% of allocations from within Tor's code on a typical directory cache. - Use a Bloom filter rather than a digest-based set to track which descriptors we need to keep around when we're cleaning out old router descriptors. This speeds up the computation significantly, and may reduce fragmentation. - Reduce the default smartlist size from 32 to 16; it turns out that most smartlists hold around 8-12 elements tops. - Make dumpstats() log the fullness and size of openssl-internal buffers. - If the user has applied the experimental SSL_MODE_RELEASE_BUFFERS patch to their OpenSSL, turn it on to save memory on servers. This patch will (with any luck) get included in a mainline distribution before too long. - Never use OpenSSL compression: it wastes RAM and CPU trying to compress cells, which are basically all encrypted, compressed, or both. o Minor bugfixes: - Stop reloading the router list from disk for no reason when we run out of reachable directory mirrors. Once upon a time reloading it would set the 'is_running' flag back to 1 for them. It hasn't done that for a long time. - In very rare situations new hidden service descriptors were published earlier than 30 seconds after the last change to the service. (We currently think that a hidden service descriptor that's been stable for 30 seconds is worth publishing.) o Minor features: - Allow separate log levels to be configured for different logging domains. For example, this allows one to log all notices, warnings, or errors, plus all memory management messages of level debug or higher, with: Log [MM] debug-err [*] notice-err file /var/log/tor. - Add a couple of extra warnings to --enable-gcc-warnings for GCC 4.3, and stop using a warning that had become unfixably verbose under GCC 4.3. - New --hush command-line option similar to --quiet. While --quiet disables all logging to the console on startup, --hush limits the output to messages of warning and error severity. - Servers support a new URL scheme for consensus downloads that allows the client to specify which authorities are trusted. The server then only sends the consensus if the client will trust it. Otherwise a 404 error is sent back. Clients use this new scheme when the server supports it (meaning it's running 0.2.1.1-alpha or later). Implements proposal 134. - New configure/torrc options (--enable-geoip-stats, DirRecordUsageByCountry) to record how many IPs we've served directory info to in each country code, how many status documents total we've sent to each country code, and what share of the total directory requests we should expect to see. - Use the TLS1 hostname extension to more closely resemble browser behavior. - Lots of new unit tests. - Add a macro to implement the common pattern of iterating through two parallel lists in lockstep. Changes in version 0.2.0.28-rc - 2008-06-13 Tor 0.2.0.28-rc fixes an anonymity-related bug, fixes a hidden-service performance bug, and fixes a bunch of smaller bugs. o Anonymity fixes: - Fix a bug where, when we were choosing the 'end stream reason' to put in our relay end cell that we send to the exit relay, Tor clients on Windows were sometimes sending the wrong 'reason'. The anonymity problem is that exit relays may be able to guess whether the client is running Windows, thus helping partition the anonymity set. Down the road we should stop sending reasons to exit relays, or otherwise prevent future versions of this bug. o Major bugfixes: - While setting up a hidden service, some valid introduction circuits were overlooked and abandoned. This might be the reason for the long delay in making a hidden service available. Bugfix on 0.2.0.14-alpha. o Minor features: - Update to the "June 9 2008" ip-to-country file. - Run 'make test' as part of 'make dist', so we stop releasing so many development snapshots that fail their unit tests. o Minor bugfixes: - When we're checking if we have enough dir info for each relay to begin establishing circuits, make sure that we actually have the descriptor listed in the consensus, not just any descriptor. Bugfix on 0.1.2.x. - Bridge relays no longer print "xx=0" in their extrainfo document for every single country code in the geoip db. Bugfix on 0.2.0.27-rc. - Only warn when we fail to load the geoip file if we were planning to include geoip stats in our extrainfo document. Bugfix on 0.2.0.27-rc. - If we change our MaxAdvertisedBandwidth and then reload torrc, Tor won't realize it should publish a new relay descriptor. Fixes bug 688, reported by mfr. Bugfix on 0.1.2.x. - When we haven't had any application requests lately, don't bother logging that we have expired a bunch of descriptors. Bugfix on 0.1.2.x. - Make relay cells written on a connection count as non-padding when tracking how long a connection has been in use. Bugfix on 0.2.0.1-alpha. Spotted by lodger. - Fix unit tests in 0.2.0.27-rc. - Fix compile on Windows. Changes in version 0.2.0.27-rc - 2008-06-03 Tor 0.2.0.27-rc adds a few features we left out of the earlier release candidates. In particular, we now include an IP-to-country GeoIP database, so controllers can easily look up what country a given relay is in, and so bridge relays can give us some sanitized summaries about which countries are making use of bridges. (See proposal 126-geoip-fetching.txt for details.) o Major features: - Include an IP-to-country GeoIP file in the tarball, so bridge relays can report sanitized summaries of the usage they're seeing. o Minor features: - Add a "PURPOSE=" argument to "STREAM NEW" events, as suggested by Robert Hogan. Fixes the first part of bug 681. - Make bridge authorities never serve extrainfo docs. - Add support to detect Libevent versions in the 1.4.x series on mingw. - Fix build on gcc 4.3 with --enable-gcc-warnings set. - Include a new contrib/tor-exit-notice.html file that exit relay operators can put on their website to help reduce abuse queries. o Minor bugfixes: - When tunneling an encrypted directory connection, and its first circuit fails, do not leave it unattached and ask the controller to deal. Fixes the second part of bug 681. - Make bridge authorities correctly expire old extrainfo documents from time to time. Changes in version 0.2.0.26-rc - 2008-05-13 Tor 0.2.0.26-rc fixes a major security vulnerability caused by a bug in Debian's OpenSSL packages. All users running any 0.2.0.x version should upgrade, whether they're running Debian or not. o Major security fixes: - Use new V3 directory authority keys on the tor26, gabelmoo, and moria1 V3 directory authorities. The old keys were generated with a vulnerable version of Debian's OpenSSL package, and must be considered compromised. Other authorities' keys were not generated with an affected version of OpenSSL. o Major bugfixes: - List authority signatures as "unrecognized" based on DirServer lines, not on cert cache. Bugfix on 0.2.0.x. o Minor features: - Add a new V3AuthUseLegacyKey option to make it easier for authorities to change their identity keys if they have to. Changes in version 0.2.0.25-rc - 2008-04-23 Tor 0.2.0.25-rc makes Tor work again on OS X and certain BSDs. o Major bugfixes: - Remember to initialize threading before initializing logging. Otherwise, many BSD-family implementations will crash hard on startup. Fixes bug 671. Bugfix on 0.2.0.24-rc. o Minor bugfixes: - Authorities correctly free policies on bad servers on exit. Fixes bug 672. Bugfix on 0.2.0.x. Changes in version 0.2.0.24-rc - 2008-04-22 Tor 0.2.0.24-rc adds dizum (run by Alex de Joode) as the new sixth v3 directory authority, makes relays with dynamic IP addresses and no DirPort notice more quickly when their IP address changes, fixes a few rare crashes and memory leaks, and fixes a few other miscellaneous bugs. o New directory authorities: - Take lefkada out of the list of v3 directory authorities, since it has been down for months. - Set up dizum (run by Alex de Joode) as the new sixth v3 directory authority. o Major bugfixes: - Detect address changes more quickly on non-directory mirror relays. Bugfix on 0.2.0.18-alpha; fixes bug 652. o Minor features (security): - Reject requests for reverse-dns lookup of names that are in a private address space. Patch from lodger. - Non-exit relays no longer allow DNS requests. Fixes bug 619. Patch from lodger. o Minor bugfixes (crashes): - Avoid a rare assert that can trigger when Tor doesn't have much directory information yet and it tries to fetch a v2 hidden service descriptor. Fixes bug 651, reported by nwf. - Initialize log mutex before initializing dmalloc. Otherwise, running with dmalloc would crash. Bugfix on 0.2.0.x-alpha. - Use recursive pthread mutexes in order to avoid deadlock when logging debug-level messages to a controller. Bug spotted by nwf, bugfix on 0.2.0.16-alpha. o Minor bugfixes (resource management): - Keep address policies from leaking memory: start their refcount at 1, not 2. Bugfix on 0.2.0.16-alpha. - Free authority certificates on exit, so they don't look like memory leaks. Bugfix on 0.2.0.19-alpha. - Free static hashtables for policy maps and for TLS connections on shutdown, so they don't look like memory leaks. Bugfix on 0.2.0.x. - Avoid allocating extra space when computing consensuses on 64-bit platforms. Bug spotted by aakova. o Minor bugfixes (misc): - Do not read the configuration file when we've only been told to generate a password hash. Fixes bug 643. Bugfix on 0.0.9pre5. Fix based on patch from Sebastian Hahn. - Exit relays that are used as a client can now reach themselves using the .exit notation, rather than just launching an infinite pile of circuits. Fixes bug 641. Reported by Sebastian Hahn. - When attempting to open a logfile fails, tell us why. - Fix a dumb bug that was preventing us from knowing that we should preemptively build circuits to handle expected directory requests. Fixes bug 660. Bugfix on 0.1.2.x. - Warn less verbosely about clock skew from netinfo cells from untrusted sources. Fixes bug 663. - Make controller stream events for DNS requests more consistent, by adding "new stream" events for DNS requests, and removing spurious "stream closed" events" for cached reverse resolves. Patch from mwenge. Fixes bug 646. - Correctly notify one-hop connections when a circuit build has failed. Possible fix for bug 669. Found by lodger. Changes in version 0.2.0.23-rc - 2008-03-24 Tor 0.2.0.23-rc is the fourth release candidate for the 0.2.0 series. It makes bootstrapping faster if the first directory mirror you contact is down. The bundles also include the new Vidalia 0.1.2 release. o Major bugfixes: - When a tunneled directory request is made to a directory server that's down, notice after 30 seconds rather than 120 seconds. Also, fail any begindir streams that are pending on it, so they can retry elsewhere. This was causing multi-minute delays on bootstrap. Changes in version 0.2.0.22-rc - 2008-03-18 Tor 0.2.0.22-rc is the third release candidate for the 0.2.0 series. It enables encrypted directory connections by default for non-relays, fixes some broken TLS behavior we added in 0.2.0.20-rc, and resolves many other bugs. The bundles also include Vidalia 0.1.1 and Torbutton 1.1.17. o Major features: - Enable encrypted directory connections by default for non-relays, so censor tools that block Tor directory connections based on their plaintext patterns will no longer work. This means Tor works in certain censored countries by default again. o Major bugfixes: - Make sure servers always request certificates from clients during TLS renegotiation. Reported by lodger; bugfix on 0.2.0.20-rc. - Do not enter a CPU-eating loop when a connection is closed in the middle of client-side TLS renegotiation. Fixes bug 622. Bug diagnosed by lodger; bugfix on 0.2.0.20-rc. - Fix assertion failure that could occur when a blocked circuit became unblocked, and it had pending client DNS requests. Bugfix on 0.2.0.1-alpha. Fixes bug 632. o Minor bugfixes (on 0.1.2.x): - Generate "STATUS_SERVER" events rather than misspelled "STATUS_SEVER" events. Caught by mwenge. - When counting the number of bytes written on a TLS connection, look at the BIO actually used for writing to the network, not at the BIO used (sometimes) to buffer data for the network. Looking at different BIOs could result in write counts on the order of ULONG_MAX. Fixes bug 614. - On Windows, correctly detect errors when listing the contents of a directory. Fix from lodger. o Minor bugfixes (on 0.2.0.x): - Downgrade "sslv3 alert handshake failure" message to INFO. - If we set RelayBandwidthRate and RelayBandwidthBurst very high but left BandwidthRate and BandwidthBurst at the default, we would be silently limited by those defaults. Now raise them to match the RelayBandwidth* values. - Fix the SVK version detection logic to work correctly on a branch. - Make --enable-openbsd-malloc work correctly on Linux with alpha CPUs. Fixes bug 625. - Logging functions now check that the passed severity is sane. - Use proper log levels in the testsuite call of get_interface_address6(). - When using a nonstandard malloc, do not use the platform values for HAVE_MALLOC_GOOD_SIZE or HAVE_MALLOC_USABLE_SIZE. - Make the openbsd malloc code use 8k pages on alpha CPUs and 16k pages on ia64. - Detect mismatched page sizes when using --enable-openbsd-malloc. - Avoid double-marked-for-close warning when certain kinds of invalid .in-addr.arpa addresses are passed to the DNSPort. Part of a fix for bug 617. Bugfix on 0.2.0.1-alpha. - Make sure that the "NULL-means-reject *:*" convention is followed by all the policy manipulation functions, avoiding some possible crash bugs. Bug found by lodger. Bugfix on 0.2.0.16-alpha. - Fix the implementation of ClientDNSRejectInternalAddresses so that it actually works, and doesn't warn about every single reverse lookup. Fixes the other part of bug 617. Bugfix on 0.2.0.1-alpha. o Minor features: - Only log guard node status when guard node status has changed. - Downgrade the 3 most common "INFO" messages to "DEBUG". This will make "INFO" 75% less verbose. Changes in version 0.2.0.21-rc - 2008-03-02 Tor 0.2.0.21-rc is the second release candidate for the 0.2.0 series. It makes Tor work well with Vidalia again, fixes a rare assert bug, and fixes a pair of more minor bugs. The bundles also include Vidalia 0.1.0 and Torbutton 1.1.16. o Major bugfixes: - The control port should declare that it requires password auth when HashedControlSessionPassword is set too. Patch from Matt Edman; bugfix on 0.2.0.20-rc. Fixes bug 615. - Downgrade assert in connection_buckets_decrement() to a log message. This may help us solve bug 614, and in any case will make its symptoms less severe. Bugfix on 0.2.0.20-rc. Reported by fredzupy. - We were sometimes miscounting the number of bytes read from the network, causing our rate limiting to not be followed exactly. Bugfix on 0.2.0.16-alpha. Reported by lodger. o Minor bugfixes: - Fix compilation with OpenSSL 0.9.8 and 0.9.8a. All other supported OpenSSL versions should have been working fine. Diagnosis and patch from lodger, Karsten Loesing, and Sebastian Hahn. Fixes bug 616. Bugfix on 0.2.0.20-rc. Changes in version 0.2.0.20-rc - 2008-02-24 Tor 0.2.0.20-rc is the first release candidate for the 0.2.0 series. It makes more progress towards normalizing Tor's TLS handshake, makes hidden services work better again, helps relays bootstrap if they don't know their IP address, adds optional support for linking in openbsd's allocator or tcmalloc, allows really fast relays to scale past 15000 sockets, and fixes a bunch of minor bugs reported by Veracode. o Major features: - Enable the revised TLS handshake based on the one designed by Steven Murdoch in proposal 124, as revised in proposal 130. It includes version negotiation for OR connections as described in proposal 105. The new handshake is meant to be harder for censors to fingerprint, and it adds the ability to detect certain kinds of man-in-the-middle traffic analysis attacks. The version negotiation feature will allow us to improve Tor's link protocol more safely in the future. - Choose which bridge to use proportional to its advertised bandwidth, rather than uniformly at random. This should speed up Tor for bridge users. Also do this for people who set StrictEntryNodes. - When a TrackHostExits-chosen exit fails too many times in a row, stop using it. Bugfix on 0.1.2.x; fixes bug 437. o Major bugfixes: - Resolved problems with (re-)fetching hidden service descriptors. Patch from Karsten Loesing; fixes problems with 0.2.0.18-alpha and 0.2.0.19-alpha. - If we only ever used Tor for hidden service lookups or posts, we would stop building circuits and start refusing connections after 24 hours, since we falsely believed that Tor was dormant. Reported by nwf; bugfix on 0.1.2.x. - Servers that don't know their own IP address should go to the authorities for their first directory fetch, even if their DirPort is off or if they don't know they're reachable yet. This will help them bootstrap better. Bugfix on 0.2.0.18-alpha; fixes bug 609. - When counting the number of open sockets, count not only the number of sockets we have received from the socket() call, but also the number we've gotten from accept() and socketpair(). This bug made us fail to count all sockets that we were using for incoming connections. Bugfix on 0.2.0.x. - Fix code used to find strings within buffers, when those strings are not in the first chunk of the buffer. Bugfix on 0.2.0.x. - Fix potential segfault when parsing HTTP headers. Bugfix on 0.2.0.x. - Add a new __HashedControlSessionPassword option for controllers to use for one-off session password hashes that shouldn't get saved to disk by SAVECONF --- Vidalia users were accumulating a pile of HashedControlPassword lines in their torrc files, one for each time they had restarted Tor and then clicked Save. Make Tor automatically convert "HashedControlPassword" to this new option but only when it's given on the command line. Partial fix for bug 586. o Minor features (performance): - Tune parameters for cell pool allocation to minimize amount of RAM overhead used. - Add OpenBSD malloc code from phk as an optional malloc replacement on Linux: some glibc libraries do very poorly with Tor's memory allocation patterns. Pass --enable-openbsd-malloc to get the replacement malloc code. - Add a --with-tcmalloc option to the configure script to link against tcmalloc (if present). Does not yet search for non-system include paths. - Stop imposing an arbitrary maximum on the number of file descriptors used for busy servers. Bug reported by Olaf Selke; patch from Sebastian Hahn. o Minor features (other): - When SafeLogging is disabled, log addresses along with all TLS errors. - When building with --enable-gcc-warnings, check for whether Apple's warning "-Wshorten-64-to-32" is available. - Add a --passphrase-fd argument to the tor-gencert command for scriptability. o Minor bugfixes (memory leaks and code problems): - We were leaking a file descriptor if Tor started with a zero-length cached-descriptors file. Patch by freddy77; bugfix on 0.1.2. - Detect size overflow in zlib code. Reported by Justin Ferguson and Dan Kaminsky. - We were comparing the raw BridgePassword entry with a base64'ed version of it, when handling a "/tor/networkstatus-bridges" directory request. Now compare correctly. Noticed by Veracode. - Recover from bad tracked-since value in MTBF-history file. Should fix bug 537. - Alter the code that tries to recover from unhandled write errors, to not try to flush onto a socket that's given us unhandled errors. Bugfix on 0.1.2.x. - Make Unix controlsockets work correctly on OpenBSD. Patch from tup. Bugfix on 0.2.0.3-alpha. o Minor bugfixes (other): - If we have an extra-info document for our server, always make it available on the control port, even if we haven't gotten a copy of it from an authority yet. Patch from mwenge. - Log the correct memory chunk sizes for empty RAM chunks in mempool.c. - Directory mirrors no longer include a guess at the client's IP address if the connection appears to be coming from the same /24 network; it was producing too many wrong guesses. - Make the new hidden service code respect the SafeLogging setting. Bugfix on 0.2.0.x. Patch from Karsten. - When starting as an authority, do not overwrite all certificates cached from other authorities. Bugfix on 0.2.0.x. Fixes bug 606. - If we're trying to flush the last bytes on a connection (for example, when answering a directory request), reset the time-to-give-up timeout every time we manage to write something on the socket. Bugfix on 0.1.2.x. - Change the behavior of "getinfo status/good-server-descriptor" so it doesn't return failure when any authority disappears. - Even though the man page said that "TrackHostExits ." should work, nobody had ever implemented it. Bugfix on 0.1.0.x. - Report TLS "zero return" case as a "clean close" and "IO error" as a "close". Stop calling closes "unexpected closes": existing Tors don't use SSL_close(), so having a connection close without the TLS shutdown handshake is hardly unexpected. - Send NAMESERVER_STATUS messages for a single failed nameserver correctly. o Code simplifications and refactoring: - Remove the tor_strpartition function: its logic was confused, and it was only used for one thing that could be implemented far more easily. Changes in version 0.2.0.19-alpha - 2008-02-09 Tor 0.2.0.19-alpha makes more progress towards normalizing Tor's TLS handshake, makes path selection for relays more secure and IP address guessing more robust, and generally fixes a lot of bugs in preparation for calling the 0.2.0 branch stable. o Major features: - Do not include recognizeable strings in the commonname part of Tor's x509 certificates. o Major bugfixes: - If we're a relay, avoid picking ourselves as an introduction point, a rendezvous point, or as the final hop for internal circuits. Bug reported by taranis and lodger. Bugfix on 0.1.2.x. - Patch from "Andrew S. Lists" to catch when we contact a directory mirror at IP address X and he says we look like we're coming from IP address X. Bugfix on 0.1.2.x. o Minor features (security): - Be more paranoid about overwriting sensitive memory on free(), as a defensive programming tactic to ensure forward secrecy. o Minor features (directory authority): - Actually validate the options passed to AuthDirReject, AuthDirInvalid, AuthDirBadDir, and AuthDirBadExit. - Reject router descriptors with out-of-range bandwidthcapacity or bandwidthburst values. o Minor features (controller): - Reject controller commands over 1MB in length. This keeps rogue processes from running us out of memory. o Minor features (misc): - Give more descriptive well-formedness errors for out-of-range hidden service descriptor/protocol versions. - Make memory debugging information describe more about history of cell allocation, so we can help reduce our memory use. o Deprecated features (controller): - The status/version/num-versioning and status/version/num-concurring GETINFO options are no longer useful in the v3 directory protocol: treat them as deprecated, and warn when they're used. o Minor bugfixes: - When our consensus networkstatus has been expired for a while, stop being willing to build circuits using it. Fixes bug 401. Bugfix on 0.1.2.x. - Directory caches now fetch certificates from all authorities listed in a networkstatus consensus, even when they do not recognize them. Fixes bug 571. Bugfix on 0.2.0.x. - When connecting to a bridge without specifying its key, insert the connection into the identity-to-connection map as soon as a key is learned. Fixes bug 574. Bugfix on 0.2.0.x. - Detect versions of OS X where malloc_good_size() is present in the library but never actually declared. Resolves bug 587. Bugfix on 0.2.0.x. - Stop incorrectly truncating zlib responses to directory authority signature download requests. Fixes bug 593. Bugfix on 0.2.0.x. - Stop recommending that every server operator send mail to tor-ops. Resolves bug 597. Bugfix on 0.1.2.x. - Don't trigger an assert if we start a directory authority with a private IP address (like 127.0.0.1). - Avoid possible failures when generating a directory with routers with over-long versions strings, or too many flags set. Bugfix on 0.1.2.x. - If an attempt to launch a DNS resolve request over the control port fails because we have overrun the limit on the number of connections, tell the controller that the request has failed. - Avoid using too little bandwidth when our clock skips a few seconds. Bugfix on 0.1.2.x. - Fix shell error when warning about missing packages in configure script, on Fedora or Red Hat machines. Bugfix on 0.2.0.x. - Do not become confused when receiving a spurious VERSIONS-like cell from a confused v1 client. Bugfix on 0.2.0.x. - Re-fetch v2 (as well as v0) rendezvous descriptors when all introduction points for a hidden service have failed. Patch from Karsten Loesing. Bugfix on 0.2.0.x. o Code simplifications and refactoring: - Remove some needless generality from cpuworker code, for improved type-safety. - Stop overloading the circuit_t.onionskin field for both "onionskin from a CREATE cell that we are waiting for a cpuworker to be assigned" and "onionskin from an EXTEND cell that we are going to send to an OR as soon as we are connected". Might help with bug 600. - Add an in-place version of aes_crypt() so that we can avoid doing a needless memcpy() call on each cell payload. Changes in version 0.2.0.18-alpha - 2008-01-25 Tor 0.2.0.18-alpha adds a sixth v3 directory authority run by CCC, fixes a big memory leak in 0.2.0.17-alpha, and adds new config options that can warn or reject connections to ports generally associated with vulnerable-plaintext protocols. o New directory authorities: - Set up dannenberg (run by CCC) as the sixth v3 directory authority. o Major bugfixes: - Fix a major memory leak when attempting to use the v2 TLS handshake code. Bugfix on 0.2.0.x; fixes bug 589. - We accidentally enabled the under-development v2 TLS handshake code, which was causing log entries like "TLS error while renegotiating handshake". Disable it again. Resolves bug 590. - We were computing the wrong Content-Length: header for directory responses that need to be compressed on the fly, causing clients asking for those items to always fail. Bugfix on 0.2.0.x; partially fixes bug 593. o Major features: - Avoid going directly to the directory authorities even if you're a relay, if you haven't found yourself reachable yet or if you've decided not to advertise your dirport yet. Addresses bug 556. - If we've gone 12 hours since our last bandwidth check, and we estimate we have less than 50KB bandwidth capacity but we could handle more, do another bandwidth test. - New config options WarnPlaintextPorts and RejectPlaintextPorts so Tor can warn and/or refuse connections to ports commonly used with vulnerable-plaintext protocols. Currently we warn on ports 23, 109, 110, and 143, but we don't reject any. o Minor bugfixes: - When we setconf ClientOnly to 1, close any current OR and Dir listeners. Reported by mwenge. - When we get a consensus that's been signed by more people than we expect, don't log about it; it's not a big deal. Reported by Kyle Williams. o Minor features: - Don't answer "/tor/networkstatus-bridges" directory requests if the request isn't encrypted. - Make "ClientOnly 1" config option disable directory ports too. - Patches from Karsten Loesing to make v2 hidden services more robust: work even when there aren't enough HSDir relays available; retry when a v2 rend desc fetch fails; but don't retry if we already have a usable v0 rend desc. Changes in version 0.2.0.17-alpha - 2008-01-17 Tor 0.2.0.17-alpha makes the tarball build cleanly again (whoops). o Compile fixes: - Make the tor-gencert man page get included correctly in the tarball. Changes in version 0.2.0.16-alpha - 2008-01-17 Tor 0.2.0.16-alpha adds a fifth v3 directory authority run by Karsten Loesing, and generally cleans up a lot of features and minor bugs. o New directory authorities: - Set up gabelmoo (run by Karsten Loesing) as the fifth v3 directory authority. o Major performance improvements: - Switch our old ring buffer implementation for one more like that used by free Unix kernels. The wasted space in a buffer with 1mb of data will now be more like 8k than 1mb. The new implementation also avoids realloc();realloc(); patterns that can contribute to memory fragmentation. o Minor features: - Configuration files now accept C-style strings as values. This helps encode characters not allowed in the current configuration file format, such as newline or #. Addresses bug 557. - Although we fixed bug 539 (where servers would send HTTP status 503 responses _and_ send a body too), there are still servers out there that haven't upgraded. Therefore, make clients parse such bodies when they receive them. - When we're not serving v2 directory information, there is no reason to actually keep any around. Remove the obsolete files and directory on startup if they are very old and we aren't going to serve them. o Minor performance improvements: - Reference-count and share copies of address policy entries; only 5% of them were actually distinct. - Never walk through the list of logs if we know that no log is interested in a given message. o Minor bugfixes: - When an authority has not signed a consensus, do not try to download a nonexistent "certificate with key 00000000". Bugfix on 0.2.0.x. Fixes bug 569. - Fix a rare assert error when we're closing one of our threads: use a mutex to protect the list of logs, so we never write to the list as it's being freed. Bugfix on 0.1.2.x. Fixes the very rare bug 575, which is kind of the revenge of bug 222. - Patch from Karsten Loesing to complain less at both the client and the relay when a relay used to have the HSDir flag but doesn't anymore, and we try to upload a hidden service descriptor. - Stop leaking one cert per TLS context. Fixes bug 582. Bugfix on 0.2.0.15-alpha. - Do not try to download missing certificates until we have tried to check our fallback consensus. Fixes bug 583. - Make bridges round reported GeoIP stats info up to the nearest estimate, not down. Now we can distinguish between "0 people from this country" and "1 person from this country". - Avoid a spurious free on base64 failure. Bugfix on 0.1.2. - Avoid possible segfault if key generation fails in crypto_pk_hybrid_encrypt. Bugfix on 0.2.0. - Avoid segfault in the case where a badly behaved v2 versioning directory sends a signed networkstatus with missing client-versions. Bugfix on 0.1.2. - Avoid segfaults on certain complex invocations of router_get_by_hexdigest(). Bugfix on 0.1.2. - Correct bad index on array access in parse_http_time(). Bugfix on 0.2.0. - Fix possible bug in vote generation when server versions are present but client versions are not. - Fix rare bug on REDIRECTSTREAM control command when called with no port set: it could erroneously report an error when none had happened. - Avoid bogus crash-prone, leak-prone tor_realloc when we're compressing large objects and find ourselves with more than 4k left over. Bugfix on 0.2.0. - Fix a small memory leak when setting up a hidden service. - Fix a few memory leaks that could in theory happen under bizarre error conditions. - Fix an assert if we post a general-purpose descriptor via the control port but that descriptor isn't mentioned in our current network consensus. Bug reported by Jon McLachlan; bugfix on 0.2.0.9-alpha. o Minor features (controller): - Get NS events working again. Patch from tup. - The GETCONF command now escapes and quotes configuration values that don't otherwise fit into the torrc file. - The SETCONF command now handles quoted values correctly. o Minor features (directory authorities): - New configuration options to override default maximum number of servers allowed on a single IP address. This is important for running a test network on a single host. - Actually implement the -s option to tor-gencert. - Add a manual page for tor-gencert. o Minor features (bridges): - Bridge authorities no longer serve bridge descriptors over unencrypted connections. o Minor features (other): - Add hidden services and DNSPorts to the list of things that make Tor accept that it has running ports. Change starting Tor with no ports from a fatal error to a warning; we might change it back if this turns out to confuse anybody. Fixes bug 579. Changes in version 0.1.2.19 - 2008-01-17 Tor 0.1.2.19 fixes a huge memory leak on exit relays, makes the default exit policy a little bit more conservative so it's safer to run an exit relay on a home system, and fixes a variety of smaller issues. o Security fixes: - Exit policies now reject connections that are addressed to a relay's public (external) IP address too, unless ExitPolicyRejectPrivate is turned off. We do this because too many relays are running nearby to services that trust them based on network address. o Major bugfixes: - When the clock jumps forward a lot, do not allow the bandwidth buckets to become negative. Fixes bug 544. - Fix a memory leak on exit relays; we were leaking a cached_resolve_t on every successful resolve. Reported by Mike Perry. - Purge old entries from the "rephist" database and the hidden service descriptor database even when DirPort is zero. - Stop thinking that 0.1.2.x directory servers can handle "begin_dir" requests. Should ease bugs 406 and 419 where 0.1.2.x relays are crashing or mis-answering these requests. - When we decide to send a 503 response to a request for servers, do not then also send the server descriptors: this defeats the whole purpose. Fixes bug 539. o Minor bugfixes: - Changing the ExitPolicyRejectPrivate setting should cause us to rebuild our server descriptor. - Fix handling of hex nicknames when answering controller requests for networkstatus by name, or when deciding whether to warn about unknown routers in a config option. (Patch from mwenge.) - Fix a couple of hard-to-trigger autoconf problems that could result in really weird results on platforms whose sys/types.h files define nonstandard integer types. - Don't try to create the datadir when running --verify-config or --hash-password. Resolves bug 540. - If we were having problems getting a particular descriptor from the directory caches, and then we learned about a new descriptor for that router, we weren't resetting our failure count. Reported by lodger. - Although we fixed bug 539 (where servers would send HTTP status 503 responses _and_ send a body too), there are still servers out there that haven't upgraded. Therefore, make clients parse such bodies when they receive them. - Run correctly on systems where rlim_t is larger than unsigned long. This includes some 64-bit systems. - Run correctly on platforms (like some versions of OS X 10.5) where the real limit for number of open files is OPEN_FILES, not rlim_max from getrlimit(RLIMIT_NOFILES). - Avoid a spurious free on base64 failure. - Avoid segfaults on certain complex invocations of router_get_by_hexdigest(). - Fix rare bug on REDIRECTSTREAM control command when called with no port set: it could erroneously report an error when none had happened. Changes in version 0.2.0.15-alpha - 2007-12-25 Tor 0.2.0.14-alpha and 0.2.0.15-alpha fix a bunch of bugs with the features added in 0.2.0.13-alpha. o Major bugfixes: - Fix several remotely triggerable asserts based on DirPort requests for a v2 or v3 networkstatus object before we were prepared. This was particularly bad for 0.2.0.13 and later bridge relays, who would never have a v2 networkstatus and would thus always crash when used. Bugfixes on 0.2.0.x. - Estimate the v3 networkstatus size more accurately, rather than estimating it at zero bytes and giving it artificially high priority compared to other directory requests. Bugfix on 0.2.0.x. o Minor bugfixes: - Fix configure.in logic for cross-compilation. - When we load a bridge descriptor from the cache, and it was previously unreachable, mark it as retriable so we won't just ignore it. Also, try fetching a new copy immediately. Bugfixes on 0.2.0.13-alpha. - The bridge GeoIP stats were counting other relays, for example self-reachability and authority-reachability tests. o Minor features: - Support compilation to target iPhone; patch from cjacker huang. To build for iPhone, pass the --enable-iphone option to configure. Changes in version 0.2.0.14-alpha - 2007-12-23 o Major bugfixes: - Fix a crash on startup if you install Tor 0.2.0.13-alpha fresh without a datadirectory from a previous Tor install. Reported by Zax. - Fix a crash when we fetch a descriptor that turns out to be unexpected (it used to be in our networkstatus when we started fetching it, but it isn't in our current networkstatus), and we aren't using bridges. Bugfix on 0.2.0.x. - Fix a crash when accessing hidden services: it would work the first time you use a given introduction point for your service, but on subsequent requests we'd be using garbage memory. Fixed by Karsten Loesing. Bugfix on 0.2.0.13-alpha. - Fix a crash when we load a bridge descriptor from disk but we don't currently have a Bridge line for it in our torrc. Bugfix on 0.2.0.13-alpha. o Major features: - If bridge authorities set BridgePassword, they will serve a snapshot of known bridge routerstatuses from their DirPort to anybody who knows that password. Unset by default. o Minor bugfixes: - Make the unit tests build again. - Make "GETINFO/desc-annotations/id/" actually work. - Make PublishServerDescriptor default to 1, so the default doesn't have to change as we invent new directory protocol versions. - Fix test for rlim_t on OSX 10.3: sys/resource.h doesn't want to be included unless sys/time.h is already included. Fixes bug 553. Bugfix on 0.2.0.x. - If we receive a general-purpose descriptor and then receive an identical bridge-purpose descriptor soon after, don't discard the next one as a duplicate. o Minor features: - If BridgeRelay is set to 1, then the default for PublishServerDescriptor is now "bridge" rather than "v2,v3". - If the user sets RelayBandwidthRate but doesn't set RelayBandwidthBurst, then make them equal rather than erroring out. Changes in version 0.2.0.13-alpha - 2007-12-21 Tor 0.2.0.13-alpha adds a fourth v3 directory authority run by Geoff Goodell, fixes many more bugs, and adds a lot of infrastructure for upcoming features. o New directory authorities: - Set up lefkada (run by Geoff Goodell) as the fourth v3 directory authority. o Major bugfixes: - Only update guard status (usable / not usable) once we have enough directory information. This was causing us to always pick two new guards on startup (bugfix on 0.2.0.9-alpha), and it was causing us to discard all our guards on startup if we hadn't been running for a few weeks (bugfix on 0.1.2.x). Fixes bug 448. - Purge old entries from the "rephist" database and the hidden service descriptor databases even when DirPort is zero. Bugfix on 0.1.2.x. - We were ignoring our RelayBandwidthRate for the first 30 seconds after opening a circuit -- even a relayed circuit. Bugfix on 0.2.0.3-alpha. - Stop thinking that 0.1.2.x directory servers can handle "begin_dir" requests. Should ease bugs 406 and 419 where 0.1.2.x relays are crashing or mis-answering these types of requests. - Relays were publishing their server descriptor to v1 and v2 directory authorities, but they didn't try publishing to v3-only authorities. Fix this; and also stop publishing to v1 authorities. Bugfix on 0.2.0.x. - When we were reading router descriptors from cache, we were ignoring the annotations -- so for example we were reading in bridge-purpose descriptors as general-purpose descriptors. Bugfix on 0.2.0.8-alpha. - When we decided to send a 503 response to a request for servers, we were then also sending the server descriptors: this defeats the whole purpose. Fixes bug 539; bugfix on 0.1.2.x. o Major features: - Bridge relays now behave like clients with respect to time intervals for downloading new consensus documents -- otherwise they stand out. Bridge users now wait until the end of the interval, so their bridge relay will be sure to have a new consensus document. - Three new config options (AlternateDirAuthority, AlternateBridgeAuthority, and AlternateHSAuthority) that let the user selectively replace the default directory authorities by type, rather than the all-or-nothing replacement that DirServer offers. - Tor can now be configured to read a GeoIP file from disk in one of two formats. This can be used by controllers to map IP addresses to countries. Eventually, it may support exit-by-country. - When possible, bridge relays remember which countries users are coming from, and report aggregate information in their extra-info documents, so that the bridge authorities can learn where Tor is blocked. - Bridge directory authorities now do reachability testing on the bridges they know. They provide router status summaries to the controller via "getinfo ns/purpose/bridge", and also dump summaries to a file periodically. - Stop fetching directory info so aggressively if your DirPort is on but your ORPort is off; stop fetching v2 dir info entirely. You can override these choices with the new FetchDirInfoEarly config option. o Minor bugfixes: - The fix in 0.2.0.12-alpha cleared the "hsdir" flag in v3 network consensus documents when there are too many relays at a single IP address. Now clear it in v2 network status documents too, and also clear it in routerinfo_t when the relay is no longer listed in the relevant networkstatus document. - Don't crash if we get an unexpected value for the PublishServerDescriptor config option. Reported by Matt Edman; bugfix on 0.2.0.9-alpha. - Our new v2 hidden service descriptor format allows descriptors that have no introduction points. But Tor crashed when we tried to build a descriptor with no intro points (and it would have crashed if we had tried to parse one). Bugfix on 0.2.0.x; patch by Karsten Loesing. - Fix building with dmalloc 5.5.2 with glibc. - Reject uploaded descriptors and extrainfo documents if they're huge. Otherwise we'll cache them all over the network and it'll clog everything up. Reported by Aljosha Judmayer. - Check for presence of s6_addr16 and s6_addr32 fields in in6_addr via autoconf. Should fix compile on solaris. Bugfix on 0.2.0.x. - When the DANGEROUS_VERSION controller status event told us we're running an obsolete version, it used the string "OLD" to describe it. Yet the "getinfo" interface used the string "OBSOLETE". Now use "OBSOLETE" in both cases. Bugfix on 0.1.2.x. - If we can't expand our list of entry guards (e.g. because we're using bridges or we have StrictEntryNodes set), don't mark relays down when they fail a directory request. Otherwise we're too quick to mark all our entry points down. Bugfix on 0.1.2.x. - Fix handling of hex nicknames when answering controller requests for networkstatus by name, or when deciding whether to warn about unknown routers in a config option. Bugfix on 0.1.2.x. (Patch from mwenge.) - Fix a couple of hard-to-trigger autoconf problems that could result in really weird results on platforms whose sys/types.h files define nonstandard integer types. Bugfix on 0.1.2.x. - Fix compilation with --disable-threads set. Bugfix on 0.2.0.x. - Don't crash on name lookup when we have no current consensus. Fixes bug 538; bugfix on 0.2.0.x. - Only Tors that want to mirror the v2 directory info should create the "cached-status" directory in their datadir. (All Tors used to create it.) Bugfix on 0.2.0.9-alpha. - Directory authorities should only automatically download Extra Info documents if they're v1, v2, or v3 authorities. Bugfix on 0.1.2.x. o Minor features: - On the USR1 signal, when dmalloc is in use, log the top 10 memory consumers. (We already do this on HUP.) - Authorities and caches fetch the v2 networkstatus documents less often, now that v3 is encouraged. - Add a new config option BridgeRelay that specifies you want to be a bridge relay. Right now the only difference is that it makes you answer begin_dir requests, and it makes you cache dir info, even if your DirPort isn't on. - Add "GETINFO/desc-annotations/id/" so controllers can ask about source, timestamp of arrival, purpose, etc. We need something like this to help Vidalia not do GeoIP lookups on bridge addresses. - Allow multiple HashedControlPassword config lines, to support multiple controller passwords. - Authorities now decide whether they're authoritative for a given router based on the router's purpose. - New config options AuthDirBadDir and AuthDirListBadDirs for authorities to mark certain relays as "bad directories" in the networkstatus documents. Also supports the "!baddir" directive in the approved-routers file. Changes in version 0.2.0.12-alpha - 2007-11-16 This twelfth development snapshot fixes some more build problems as well as a few minor bugs. o Compile fixes: - Make it build on OpenBSD again. Patch from tup. - Substitute BINDIR and LOCALSTATEDIR in scripts. Fixes package-building for Red Hat, OS X, etc. o Minor bugfixes (on 0.1.2.x): - Changing the ExitPolicyRejectPrivate setting should cause us to rebuild our server descriptor. o Minor bugfixes (on 0.2.0.x): - When we're lacking a consensus, don't try to perform rendezvous operations. Reported by Karsten Loesing. - Fix a small memory leak whenever we decide against using a newly picked entry guard. Reported by Mike Perry. - When authorities detected more than two relays running on the same IP address, they were clearing all the status flags but forgetting to clear the "hsdir" flag. So clients were being told that a given relay was the right choice for a v2 hsdir lookup, yet they never had its descriptor because it was marked as 'not running' in the consensus. - If we're trying to fetch a bridge descriptor and there's no way the bridge authority could help us (for example, we don't know a digest, or there is no bridge authority), don't be so eager to fall back to asking the bridge authority. - If we're using bridges or have strictentrynodes set, and our chosen exit is in the same family as all our bridges/entry guards, then be flexible about families. o Minor features: - When we negotiate a v2 link-layer connection (not yet implemented), accept RELAY_EARLY cells and turn them into RELAY cells if we've negotiated a v1 connection for their next step. Initial code for proposal 110. Changes in version 0.2.0.11-alpha - 2007-11-12 This eleventh development snapshot fixes some build problems with the previous snapshot. It also includes a more secure-by-default exit policy for relays, fixes an enormous memory leak for exit relays, and fixes another bug where servers were falling out of the directory list. o Security fixes: - Exit policies now reject connections that are addressed to a relay's public (external) IP address too, unless ExitPolicyRejectPrivate is turned off. We do this because too many relays are running nearby to services that trust them based on network address. Bugfix on 0.1.2.x. o Major bugfixes: - Fix a memory leak on exit relays; we were leaking a cached_resolve_t on every successful resolve. Reported by Mike Perry; bugfix on 0.1.2.x. - On authorities, never downgrade to old router descriptors simply because they're listed in the consensus. This created a catch-22 where we wouldn't list a new descriptor because there was an old one in the consensus, and we couldn't get the new one in the consensus because we wouldn't list it. Possible fix for bug 548. Also, this might cause bug 543 to appear on authorities; if so, we'll need a band-aid for that. Bugfix on 0.2.0.9-alpha. o Packaging fixes on 0.2.0.10-alpha: - We were including instructions about what to do with the src/config/fallback-consensus file, but we weren't actually including it in the tarball. Disable all of that for now. o Minor features: - Allow people to say PreferTunnelledDirConns rather than PreferTunneledDirConns, for those alternate-spellers out there. o Minor bugfixes: - Don't reevaluate all the information from our consensus document just because we've downloaded a v2 networkstatus that we intend to cache. Fixes bug 545; bugfix on 0.2.0.x. Changes in version 0.2.0.10-alpha - 2007-11-10 This tenth development snapshot adds a third v3 directory authority run by Mike Perry, adds most of Karsten Loesing's new hidden service descriptor format, fixes a bad crash bug and new bridge bugs introduced in 0.2.0.9-alpha, fixes many bugs with the v3 directory implementation, fixes some minor memory leaks in previous 0.2.0.x snapshots, and addresses many more minor issues. o New directory authorities: - Set up ides (run by Mike Perry) as the third v3 directory authority. o Major features: - Allow tunnelled directory connections to ask for an encrypted "begin_dir" connection or an anonymized "uses a full Tor circuit" connection independently. Now we can make anonymized begin_dir connections for (e.g.) more secure hidden service posting and fetching. - More progress on proposal 114: code from Karsten Loesing to implement new hidden service descriptor format. - Raise the default BandwidthRate/BandwidthBurst to 5MB/10MB, to accommodate the growing number of servers that use the default and are reaching it. - Directory authorities use a new formula for selecting which nodes to advertise as Guards: they must be in the top 7/8 in terms of how long we have known about them, and above the median of those nodes in terms of weighted fractional uptime. - Make "not enough dir info yet" warnings describe *why* Tor feels it doesn't have enough directory info yet. o Major bugfixes: - Stop servers from crashing if they set a Family option (or maybe in other situations too). Bugfix on 0.2.0.9-alpha; reported by Fabian Keil. - Make bridge users work again -- the move to v3 directories in 0.2.0.9-alpha had introduced a number of bugs that made bridges no longer work for clients. - When the clock jumps forward a lot, do not allow the bandwidth buckets to become negative. Bugfix on 0.1.2.x; fixes bug 544. o Major bugfixes (v3 dir, bugfixes on 0.2.0.9-alpha): - When the consensus lists a router descriptor that we previously were mirroring, but that we considered non-canonical, reload the descriptor as canonical. This fixes bug 543 where Tor servers would start complaining after a few days that they don't have enough directory information to build a circuit. - Consider replacing the current consensus when certificates arrive that make the pending consensus valid. Previously, we were only considering replacement when the new certs _didn't_ help. - Fix an assert error on startup if we didn't already have the consensus and certs cached in our datadirectory: we were caching the consensus in consensus_waiting_for_certs but then free'ing it right after. - Avoid sending a request for "keys/fp" (for which we'll get a 400 Bad Request) if we need more v3 certs but we've already got pending requests for all of them. - Correctly back off from failing certificate downloads. Fixes bug 546. - Authorities don't vote on the Running flag if they have been running for less than 30 minutes themselves. Fixes bug 547, where a newly started authority would vote that everyone was down. o New requirements: - Drop support for OpenSSL version 0.9.6. Just about nobody was using it, it had no AES, and it hasn't seen any security patches since 2004. o Minor features: - Clients now hold circuitless TLS connections open for 1.5 times MaxCircuitDirtiness (15 minutes), since it is likely that they'll rebuild a new circuit over them within that timeframe. Previously, they held them open only for KeepalivePeriod (5 minutes). - Use "If-Modified-Since" to avoid retrieving consensus networkstatuses that we already have. - When we have no consensus, check FallbackNetworkstatusFile (defaults to $PREFIX/share/tor/fallback-consensus) for a consensus. This way we start knowing some directory caches. - When we receive a consensus from the future, warn about skew. - Improve skew reporting: try to give the user a better log message about how skewed they are, and how much this matters. - When we have a certificate for an authority, believe that certificate's claims about the authority's IP address. - New --quiet command-line option to suppress the default console log. Good in combination with --hash-password. - Authorities send back an X-Descriptor-Not-New header in response to an accepted-but-discarded descriptor upload. Partially implements fix for bug 535. - Make the log message for "tls error. breaking." more useful. - Better log messages about certificate downloads, to attempt to track down the second incarnation of bug 546. o Minor features (bridges): - If bridge users set UpdateBridgesFromAuthority, but the digest they ask for is a 404 from the bridge authority, they now fall back to trying the bridge directly. - Bridges now use begin_dir to publish their server descriptor to the bridge authority, even when they haven't set TunnelDirConns. o Minor features (controller): - When reporting clock skew, and we know that the clock is _at least as skewed_ as some value, but we don't know the actual value, report the value as a "minimum skew." o Utilities: - Update linux-tor-prio.sh script to allow QoS based on the uid of the Tor process. Patch from Marco Bonetti with tweaks from Mike Perry. o Minor bugfixes: - Refuse to start if both ORPort and UseBridges are set. Bugfix on 0.2.0.x, suggested by Matt Edman. - Don't stop fetching descriptors when FetchUselessDescriptors is set, even if we stop asking for circuits. Bugfix on 0.1.2.x; reported by tup and ioerror. - Better log message on vote from unknown authority. - Don't log "Launching 0 request for 0 router" message. o Minor bugfixes (memory leaks): - Stop leaking memory every time we parse a v3 certificate. Bugfix on 0.2.0.1-alpha. - Stop leaking memory every time we load a v3 certificate. Bugfix on 0.2.0.1-alpha. Fixes bug 536. - Stop leaking a cached networkstatus on exit. Bugfix on 0.2.0.3-alpha. - Stop leaking voter information every time we free a consensus. Bugfix on 0.2.0.3-alpha. - Stop leaking signed data every time we check a voter signature. Bugfix on 0.2.0.3-alpha. - Stop leaking a signature every time we fail to parse a consensus or a vote. Bugfix on 0.2.0.3-alpha. - Stop leaking v2_download_status_map on shutdown. Bugfix on 0.2.0.9-alpha. - Stop leaking conn->nickname every time we make a connection to a Tor relay without knowing its expected identity digest (e.g. when using bridges). Bugfix on 0.2.0.3-alpha. - Minor bugfixes (portability): - Run correctly on platforms where rlim_t is larger than unsigned long, and/or where the real limit for number of open files is OPEN_FILES, not rlim_max from getrlimit(RLIMIT_NOFILES). In particular, these may be needed for OS X 10.5. Changes in version 0.1.2.18 - 2007-10-28 Tor 0.1.2.18 fixes many problems including crash bugs, problems with hidden service introduction that were causing huge delays, and a big bug that was causing some servers to disappear from the network status lists for a few hours each day. o Major bugfixes (crashes): - If a connection is shut down abruptly because of something that happened inside connection_flushed_some(), do not call connection_finished_flushing(). Should fix bug 451: "connection_stop_writing: Assertion conn->write_event failed" Bugfix on 0.1.2.7-alpha. - Fix possible segfaults in functions called from rend_process_relay_cell(). o Major bugfixes (hidden services): - Hidden services were choosing introduction points uniquely by hexdigest, but when constructing the hidden service descriptor they merely wrote the (potentially ambiguous) nickname. - Clients now use the v2 intro format for hidden service connections: they specify their chosen rendezvous point by identity digest rather than by (potentially ambiguous) nickname. These changes could speed up hidden service connections dramatically. o Major bugfixes (other): - Stop publishing a new server descriptor just because we get a HUP signal. This led (in a roundabout way) to some servers getting dropped from the networkstatus lists for a few hours each day. - When looking for a circuit to cannibalize, consider family as well as identity. Fixes bug 438. Bugfix on 0.1.0.x (which introduced circuit cannibalization). - When a router wasn't listed in a new networkstatus, we were leaving the flags for that router alone -- meaning it remained Named, Running, etc -- even though absence from the networkstatus means that it shouldn't be considered to exist at all anymore. Now we clear all the flags for routers that fall out of the networkstatus consensus. Fixes bug 529. o Minor bugfixes: - Don't try to access (or alter) the state file when running --list-fingerprint or --verify-config or --hash-password. Resolves bug 499. - When generating information telling us how to extend to a given router, do not try to include the nickname if it is absent. Resolves bug 467. - Fix a user-triggerable segfault in expand_filename(). (There isn't a way to trigger this remotely.) - When sending a status event to the controller telling it that an OR address is reachable, set the port correctly. (Previously we were reporting the dir port.) - Fix a minor memory leak whenever a controller sends the PROTOCOLINFO command. Bugfix on 0.1.2.17. - When loading bandwidth history, do not believe any information in the future. Fixes bug 434. - When loading entry guard information, do not believe any information in the future. - When we have our clock set far in the future and generate an onion key, then re-set our clock to be correct, we should not stop the onion key from getting rotated. - On some platforms, accept() can return a broken address. Detect this more quietly, and deal accordingly. Fixes bug 483. - It's not actually an error to find a non-pending entry in the DNS cache when canceling a pending resolve. Don't log unless stuff is fishy. Resolves bug 463. - Don't reset trusted dir server list when we set a configuration option. Patch from Robert Hogan. - Don't try to create the datadir when running --verify-config or --hash-password. Resolves bug 540. Changes in version 0.2.0.9-alpha - 2007-10-24 This ninth development snapshot switches clients to the new v3 directory system; allows servers to be listed in the network status even when they have the same nickname as a registered server; and fixes many other bugs including a big one that was causing some servers to disappear from the network status lists for a few hours each day. o Major features (directory system): - Clients now download v3 consensus networkstatus documents instead of v2 networkstatus documents. Clients and caches now base their opinions about routers on these consensus documents. Clients only download router descriptors listed in the consensus. - Authorities now list servers who have the same nickname as a different named server, but list them with a new flag, "Unnamed". Now we can list servers that happen to pick the same nickname as a server that registered two years ago and then disappeared. Partially implements proposal 122. - If the consensus lists a router as "Unnamed", the name is assigned to a different router: do not identify the router by that name. Partially implements proposal 122. - Authorities can now come to a consensus on which method to use to compute the consensus. This gives us forward compatibility. o Major bugfixes: - Stop publishing a new server descriptor just because we HUP or when we find our DirPort to be reachable but won't actually publish it. New descriptors without any real changes are dropped by the authorities, and can screw up our "publish every 18 hours" schedule. Bugfix on 0.1.2.x. - When a router wasn't listed in a new networkstatus, we were leaving the flags for that router alone -- meaning it remained Named, Running, etc -- even though absence from the networkstatus means that it shouldn't be considered to exist at all anymore. Now we clear all the flags for routers that fall out of the networkstatus consensus. Fixes bug 529; bugfix on 0.1.2.x. - Fix awful behavior in DownloadExtraInfo option where we'd fetch extrainfo documents and then discard them immediately for not matching the latest router. Bugfix on 0.2.0.1-alpha. o Minor features (v3 directory protocol): - Allow tor-gencert to generate a new certificate without replacing the signing key. - Allow certificates to include an address. - When we change our directory-cache settings, reschedule all voting and download operations. - Reattempt certificate downloads immediately on failure, as long as we haven't failed a threshold number of times yet. - Delay retrying consensus downloads while we're downloading certificates to verify the one we just got. Also, count getting a consensus that we already have (or one that isn't valid) as a failure, and count failing to get the certificates after 20 minutes as a failure. - Build circuits and download descriptors even if our consensus is a little expired. (This feature will go away once authorities are more reliable.) o Minor features (router descriptor cache): - If we find a cached-routers file that's been sitting around for more than 28 days unmodified, then most likely it's a leftover from when we upgraded to 0.2.0.8-alpha. Remove it. It has no good routers anyway. - When we (as a cache) download a descriptor because it was listed in a consensus, remember when the consensus was supposed to expire, and don't expire the descriptor until then. o Minor features (performance): - Call routerlist_remove_old_routers() much less often. This should speed startup, especially on directory caches. - Don't try to launch new descriptor downloads quite so often when we already have enough directory information to build circuits. - Base64 decoding was actually showing up on our profile when parsing the initial descriptor file; switch to an in-process all-at-once implementation that's about 3.5x times faster than calling out to OpenSSL. o Minor features (compilation): - Detect non-ASCII platforms (if any still exist) and refuse to build there: some of our code assumes that 'A' is 65 and so on. o Minor bugfixes (v3 directory authorities, bugfixes on 0.2.0.x): - Make the "next period" votes into "current period" votes immediately after publishing the consensus; avoid a heisenbug that made them stick around indefinitely. - When we discard a vote as a duplicate, do not report this as an error. - Treat missing v3 keys or certificates as an error when running as a v3 directory authority. - When we're configured to be a v3 authority, but we're only listed as a non-v3 authority in our DirServer line for ourself, correct the listing. - If an authority doesn't have a qualified hostname, just put its address in the vote. This fixes the problem where we referred to "moria on moria:9031." - Distinguish between detached signatures for the wrong period, and detached signatures for a divergent vote. - Fix a small memory leak when computing a consensus. - When there's no concensus, we were forming a vote every 30 minutes, but writing the "valid-after" line in our vote based on our configured V3AuthVotingInterval: so unless the intervals matched up, we immediately rejected our own vote because it didn't start at the voting interval that caused us to construct a vote. o Minor bugfixes (v3 directory protocol, bugfixes on 0.2.0.x): - Delete unverified-consensus when the real consensus is set. - Consider retrying a consensus networkstatus fetch immediately after one fails: don't wait 60 seconds to notice. - When fetching a consensus as a cache, wait until a newer consensus should exist before trying to replace the current one. - Use a more forgiving schedule for retrying failed consensus downloads than for other types. o Minor bugfixes (other directory issues): - Correct the implementation of "download votes by digest." Bugfix on 0.2.0.8-alpha. - Authorities no longer send back "400 you're unreachable please fix it" errors to Tor servers that aren't online all the time. We're supposed to tolerate these servers now. Bugfix on 0.1.2.x. o Minor bugfixes (controller): - Don't reset trusted dir server list when we set a configuration option. Patch from Robert Hogan; bugfix on 0.1.2.x. - Respond to INT and TERM SIGNAL commands before we execute the signal, in case the signal shuts us down. We had a patch in 0.1.2.1-alpha that tried to do this by queueing the response on the connection's buffer before shutting down, but that really isn't the same thing at all. Bug located by Matt Edman. o Minor bugfixes (misc): - Correctly check for bad options to the "PublishServerDescriptor" config option. Bugfix on 0.2.0.1-alpha; reported by Matt Edman. - Stop leaking memory on failing case of base32_decode, and make it accept upper-case letters. Bugfixes on 0.2.0.7-alpha. - Don't try to download extrainfo documents when we're trying to fetch enough directory info to build a circuit: having enough info should get priority. Bugfix on 0.2.0.x. - Don't complain that "your server has not managed to confirm that its ports are reachable" if we haven't been able to build any circuits yet. Bug found by spending four hours without a v3 consensus. Bugfix on 0.1.2.x. - Detect the reason for failing to mmap a descriptor file we just wrote, and give a more useful log message. Fixes bug 533. Bugfix on 0.1.2.x. o Code simplifications and refactoring: - Remove support for the old bw_accounting file: we've been storing bandwidth accounting information in the state file since 0.1.2.5-alpha. This may result in bandwidth accounting errors if you try to upgrade from 0.1.1.x or earlier, or if you try to downgrade to 0.1.1.x or earlier. - New convenience code to locate a file within the DataDirectory. - Move non-authority functionality out of dirvote.c. - Refactor the arguments for router_pick_{directory_|trusteddir}server so that they all take the same named flags. o Utilities - Include the "tor-ctrl.sh" bash script by Stefan Behte to provide Unix users an easy way to script their Tor process (e.g. by adjusting bandwidth based on the time of the day). Changes in version 0.2.0.8-alpha - 2007-10-12 This eighth development snapshot fixes a crash bug that's been bothering us since February 2007, lets bridge authorities store a list of bridge descriptors they've seen, gets v3 directory voting closer to working, starts caching v3 directory consensus documents on directory mirrors, and fixes a variety of smaller issues including some minor memory leaks. o Major features (router descriptor cache): - Store routers in a file called cached-descriptors instead of in cached-routers. Initialize cached-descriptors from cached-routers if the old format is around. The new format allows us to store annotations along with descriptors. - Use annotations to record the time we received each descriptor, its source, and its purpose. - Disable the SETROUTERPURPOSE controller command: it is now obsolete. - Controllers should now specify cache=no or cache=yes when using the +POSTDESCRIPTOR command. - Bridge authorities now write bridge descriptors to disk, meaning we can export them to other programs and begin distributing them to blocked users. o Major features (directory authorities): - When a v3 authority is missing votes or signatures, it now tries to fetch them. - Directory authorities track weighted fractional uptime as well as weighted mean-time-between failures. WFU is suitable for deciding whether a node is "usually up", while MTBF is suitable for deciding whether a node is "likely to stay up." We need both, because "usually up" is a good requirement for guards, while "likely to stay up" is a good requirement for long-lived connections. o Major features (v3 directory system): - Caches now download v3 network status documents as needed, and download the descriptors listed in them. - All hosts now attempt to download and keep fresh v3 authority certificates, and re-attempt after failures. - More internal-consistency checks for vote parsing. o Major bugfixes (crashes): - If a connection is shut down abruptly because of something that happened inside connection_flushed_some(), do not call connection_finished_flushing(). Should fix bug 451. Bugfix on 0.1.2.7-alpha. o Major bugfixes (performance): - Fix really bad O(n^2) performance when parsing a long list of routers: Instead of searching the entire list for an "extra-info " string which usually wasn't there, once for every routerinfo we read, just scan lines forward until we find one we like. Bugfix on 0.2.0.1. - When we add data to a write buffer in response to the data on that write buffer getting low because of a flush, do not consider the newly added data as a candidate for immediate flushing, but rather make it wait until the next round of writing. Otherwise, we flush and refill recursively, and a single greedy TLS connection can eat all of our bandwidth. Bugfix on 0.1.2.7-alpha. o Minor features (v3 authority system): - Add more ways for tools to download the votes that lead to the current consensus. - Send a 503 when low on bandwidth and a vote, consensus, or certificate is requested. - If-modified-since is now implemented properly for all kinds of certificate requests. o Minor bugfixes (network statuses): - Tweak the implementation of proposal 109 slightly: allow at most two Tor servers on the same IP address, except if it's the location of a directory authority, in which case allow five. Bugfix on 0.2.0.3-alpha. o Minor bugfixes (controller): - When sending a status event to the controller telling it that an OR address is reachable, set the port correctly. (Previously we were reporting the dir port.) Bugfix on 0.1.2.x. o Minor bugfixes (v3 directory system): - Fix logic to look up a cert by its signing key digest. Bugfix on 0.2.0.7-alpha. - Only change the reply to a vote to "OK" if it's not already set. This gets rid of annoying "400 OK" log messages, which may have been masking some deeper issue. Bugfix on 0.2.0.7-alpha. - When we get a valid consensus, recompute the voting schedule. - Base the valid-after time of a vote on the consensus voting schedule, not on our preferred schedule. - Make the return values and messages from signature uploads and downloads more sensible. - Fix a memory leak when serving votes and consensus documents, and another when serving certificates. o Minor bugfixes (performance): - Use a slightly simpler string hashing algorithm (copying Python's instead of Java's) and optimize our digest hashing algorithm to take advantage of 64-bit platforms and to remove some possibly-costly voodoo. - Fix a minor memory leak whenever we parse guards from our state file. Bugfix on 0.2.0.7-alpha. - Fix a minor memory leak whenever we write out a file. Bugfix on 0.2.0.7-alpha. - Fix a minor memory leak whenever a controller sends the PROTOCOLINFO command. Bugfix on 0.2.0.5-alpha. o Minor bugfixes (portability): - On some platforms, accept() can return a broken address. Detect this more quietly, and deal accordingly. Fixes bug 483. - Stop calling tor_strlower() on uninitialized memory in some cases. Bugfix in 0.2.0.7-alpha. o Minor bugfixes (usability): - Treat some 403 responses from directory servers as INFO rather than WARN-severity events. - It's not actually an error to find a non-pending entry in the DNS cache when canceling a pending resolve. Don't log unless stuff is fishy. Resolves bug 463. o Minor bugfixes (anonymity): - Never report that we've used more bandwidth than we're willing to relay: it leaks how much non-relay traffic we're using. Resolves bug 516. - When looking for a circuit to cannibalize, consider family as well as identity. Fixes bug 438. Bugfix on 0.1.0.x (which introduced circuit cannibalization). o Code simplifications and refactoring: - Make a bunch of functions static. Remove some dead code. - Pull out about a third of the really big routerlist.c; put it in a new module, networkstatus.c. - Merge the extra fields in local_routerstatus_t back into routerstatus_t: we used to need one routerstatus_t for each authority's opinion, plus a local_routerstatus_t for the locally computed consensus opinion. To save space, we put the locally modified fields into local_routerstatus_t, and only the common stuff into routerstatus_t. But once v3 directories are in use, clients and caches will no longer need to hold authority opinions; thus, the rationale for keeping the types separate is now gone. - Make the code used to reschedule and reattempt downloads more uniform. - Turn all 'Are we a directory server/mirror?' logic into a call to dirserver_mode(). - Remove the code to generate the oldest (v1) directory format. The code has been disabled since 0.2.0.5-alpha. Changes in version 0.2.0.7-alpha - 2007-09-21 This seventh development snapshot makes bridges work again, makes bridge authorities work for the first time, fixes two huge performance flaws in hidden services, and fixes a variety of minor issues. o New directory authorities: - Set up moria1 and tor26 as the first v3 directory authorities. See doc/spec/dir-spec.txt for details on the new directory design. o Major bugfixes (crashes): - Fix possible segfaults in functions called from rend_process_relay_cell(). Bugfix on 0.1.2.x. o Major bugfixes (bridges): - Fix a bug that made servers send a "404 Not found" in response to attempts to fetch their server descriptor. This caused Tor servers to take many minutes to establish reachability for their DirPort, and it totally crippled bridges. Bugfix on 0.2.0.5-alpha. - Make "UpdateBridgesFromAuthority" torrc option work: when bridge users configure that and specify a bridge with an identity fingerprint, now they will lookup the bridge descriptor at the default bridge authority via a one-hop tunnel, but once circuits are established they will switch to a three-hop tunnel for later connections to the bridge authority. Bugfix in 0.2.0.3-alpha. o Major bugfixes (hidden services): - Hidden services were choosing introduction points uniquely by hexdigest, but when constructing the hidden service descriptor they merely wrote the (potentially ambiguous) nickname. - Clients now use the v2 intro format for hidden service connections: they specify their chosen rendezvous point by identity digest rather than by (potentially ambiguous) nickname. Both are bugfixes on 0.1.2.x, and they could speed up hidden service connections dramatically. Thanks to Karsten Loesing. o Minor features (security): - As a client, do not believe any server that tells us that an address maps to an internal address space. - Make it possible to enable HashedControlPassword and CookieAuthentication at the same time. o Minor features (guard nodes): - Tag every guard node in our state file with the version that we believe added it, or with our own version if we add it. This way, if a user temporarily runs an old version of Tor and then switches back to a new one, she doesn't automatically lose her guards. o Minor features (speed): - When implementing AES counter mode, update only the portions of the counter buffer that need to change, and don't keep separate network-order and host-order counters when they are the same (i.e., on big-endian hosts.) o Minor features (controller): - Accept LF instead of CRLF on controller, since some software has a hard time generating real Internet newlines. - Add GETINFO values for the server status events "REACHABILITY_SUCCEEDED" and "GOOD_SERVER_DESCRIPTOR". Patch from Robert Hogan. o Removed features: - Routers no longer include bandwidth-history lines in their descriptors; this information is already available in extra-info documents, and including it in router descriptors took up 60% (!) of compressed router descriptor downloads. Completes implementation of proposal 104. - Remove the contrib scripts ExerciseServer.py, PathDemo.py, and TorControl.py, as they use the old v0 controller protocol, and are obsoleted by TorFlow anyway. - Drop support for v1 rendezvous descriptors, since we never used them anyway, and the code has probably rotted by now. Based on patch from Karsten Loesing. - On OSX, stop warning the user that kqueue support in libevent is "experimental", since it seems to have worked fine for ages. o Minor bugfixes: - When generating information telling us how to extend to a given router, do not try to include the nickname if it is absent. Fixes bug 467. Bugfix on 0.2.0.3-alpha. - Fix a user-triggerable (but not remotely-triggerable) segfault in expand_filename(). Bugfix on 0.1.2.x. - Fix a memory leak when freeing incomplete requests from DNSPort. Found by Niels Provos with valgrind. Bugfix on 0.2.0.1-alpha. - Don't try to access (or alter) the state file when running --list-fingerprint or --verify-config or --hash-password. (Resolves bug 499.) Bugfix on 0.1.2.x. - Servers used to decline to publish their DirPort if their BandwidthRate, RelayBandwidthRate, or MaxAdvertisedBandwidth were below a threshold. Now they only look at BandwidthRate and RelayBandwidthRate. Bugfix on 0.1.2.x. - Remove an optimization in the AES counter-mode code that assumed that the counter never exceeded 2^68. When the counter can be set arbitrarily as an IV (as it is by Karsten's new hidden services code), this assumption no longer holds. Bugfix on 0.1.2.x. - Resume listing "AUTHORITY" flag for authorities in network status. Bugfix on 0.2.0.3-alpha; reported by Alex de Joode. o Code simplifications and refactoring: - Revamp file-writing logic so we don't need to have the entire contents of a file in memory at once before we write to disk. Tor, meet stdio. - Turn "descriptor store" into a full-fledged type. - Move all NT services code into a separate source file. - Unify all code that computes medians, percentile elements, etc. - Get rid of a needless malloc when parsing address policies. Changes in version 0.1.2.17 - 2007-08-30 Tor 0.1.2.17 features a new Vidalia version in the Windows and OS X bundles. Vidalia 0.0.14 makes authentication required for the ControlPort in the default configuration, which addresses important security risks. Everybody who uses Vidalia (or another controller) should upgrade. In addition, this Tor update fixes major load balancing problems with path selection, which should speed things up a lot once many people have upgraded. o Major bugfixes (security): - We removed support for the old (v0) control protocol. It has been deprecated since Tor 0.1.1.1-alpha, and keeping it secure has become more of a headache than it's worth. o Major bugfixes (load balancing): - When choosing nodes for non-guard positions, weight guards proportionally less, since they already have enough load. Patch from Mike Perry. - Raise the "max believable bandwidth" from 1.5MB/s to 10MB/s. This will allow fast Tor servers to get more attention. - When we're upgrading from an old Tor version, forget our current guards and pick new ones according to the new weightings. These three load balancing patches could raise effective network capacity by a factor of four. Thanks to Mike Perry for measurements. o Major bugfixes (stream expiration): - Expire not-yet-successful application streams in all cases if they've been around longer than SocksTimeout. Right now there are some cases where the stream will live forever, demanding a new circuit every 15 seconds. Fixes bug 454; reported by lodger. o Minor features (controller): - Add a PROTOCOLINFO controller command. Like AUTHENTICATE, it is valid before any authentication has been received. It tells a controller what kind of authentication is expected, and what protocol is spoken. Implements proposal 119. o Minor bugfixes (performance): - Save on most routerlist_assert_ok() calls in routerlist.c, thus greatly speeding up loading cached-routers from disk on startup. - Disable sentinel-based debugging for buffer code: we squashed all the bugs that this was supposed to detect a long time ago, and now its only effect is to change our buffer sizes from nice powers of two (which platform mallocs tend to like) to values slightly over powers of two (which make some platform mallocs sad). o Minor bugfixes (misc): - If exit bandwidth ever exceeds one third of total bandwidth, then use the correct formula to weight exit nodes when choosing paths. Based on patch from Mike Perry. - Choose perfectly fairly among routers when choosing by bandwidth and weighting by fraction of bandwidth provided by exits. Previously, we would choose with only approximate fairness, and correct ourselves if we ran off the end of the list. - If we require CookieAuthentication but we fail to write the cookie file, we would warn but not exit, and end up in a state where no controller could authenticate. Now we exit. - If we require CookieAuthentication, stop generating a new cookie every time we change any piece of our config. - Refuse to start with certain directory authority keys, and encourage people using them to stop. - Terminate multi-line control events properly. Original patch from tup. - Fix a minor memory leak when we fail to find enough suitable servers to choose a circuit. - Stop leaking part of the descriptor when we run into a particularly unparseable piece of it. Changes in version 0.2.0.6-alpha - 2007-08-26 This sixth development snapshot features a new Vidalia version in the Windows and OS X bundles. Vidalia 0.0.14 makes authentication required for the ControlPort in the default configuration, which addresses important security risks. In addition, this snapshot fixes major load balancing problems with path selection, which should speed things up a lot once many people have upgraded. The directory authorities also use a new mean-time-between-failure approach to tracking which servers are stable, rather than just looking at the most recent uptime. o New directory authorities: - Set up Tonga as the default bridge directory authority. o Major features: - Directory authorities now track servers by weighted mean-times-between-failures. When we have 4 or more days of data, use measured MTBF rather than declared uptime to decide whether to call a router Stable. Implements proposal 108. o Major bugfixes (load balancing): - When choosing nodes for non-guard positions, weight guards proportionally less, since they already have enough load. Patch from Mike Perry. - Raise the "max believable bandwidth" from 1.5MB/s to 10MB/s. This will allow fast Tor servers to get more attention. - When we're upgrading from an old Tor version, forget our current guards and pick new ones according to the new weightings. These three load balancing patches could raise effective network capacity by a factor of four. Thanks to Mike Perry for measurements. o Major bugfixes (descriptor parsing): - Handle unexpected whitespace better in malformed descriptors. Bug found using Benedikt Boss's new Tor fuzzer! Bugfix on 0.2.0.x. o Minor features: - There is now an ugly, temporary "desc/all-recent-extrainfo-hack" GETINFO for Torstat to use until it can switch to using extrainfos. - Optionally (if built with -DEXPORTMALLINFO) export the output of mallinfo via http, as tor/mallinfo.txt. Only accessible from localhost. o Minor bugfixes: - Do not intermix bridge routers with controller-added routers. (Bugfix on 0.2.0.x) - Do not fail with an assert when accept() returns an unexpected address family. Addresses but does not wholly fix bug 483. (Bugfix on 0.2.0.x) - Let directory authorities startup even when they can't generate a descriptor immediately, e.g. because they don't know their address. - Stop putting the authentication cookie in a file called "0" in your working directory if you don't specify anything for the new CookieAuthFile option. Reported by Matt Edman. - Make it possible to read the PROTOCOLINFO response in a way that conforms to our control-spec. Reported by Matt Edman. - Fix a minor memory leak when we fail to find enough suitable servers to choose a circuit. Bugfix on 0.1.2.x. - Stop leaking part of the descriptor when we run into a particularly unparseable piece of it. Bugfix on 0.1.2.x. - Unmap the extrainfo cache file on exit. Changes in version 0.2.0.5-alpha - 2007-08-19 This fifth development snapshot fixes compilation on Windows again; fixes an obnoxious client-side bug that slowed things down and put extra load on the network; gets us closer to using the v3 directory voting scheme; makes it easier for Tor controllers to use cookie-based authentication; and fixes a variety of other bugs. o Removed features: - Version 1 directories are no longer generated in full. Instead, authorities generate and serve "stub" v1 directories that list no servers. This will stop Tor versions 0.1.0.x and earlier from working, but (for security reasons) nobody should be running those versions anyway. o Major bugfixes (compilation, 0.2.0.x): - Try to fix Win32 compilation again: improve checking for IPv6 types. - Try to fix MSVC compilation: build correctly on platforms that do not define s6_addr16 or s6_addr32. - Fix compile on platforms without getaddrinfo: bug found by Li-Hui Zhou. o Major bugfixes (stream expiration): - Expire not-yet-successful application streams in all cases if they've been around longer than SocksTimeout. Right now there are some cases where the stream will live forever, demanding a new circuit every 15 seconds. Bugfix on 0.1.2.7-alpha; fixes bug 454; reported by lodger. o Minor features (directory servers): - When somebody requests a list of statuses or servers, and we have none of those, return a 404 rather than an empty 200. o Minor features (directory voting): - Store v3 consensus status consensuses on disk, and reload them on startup. o Minor features (security): - Warn about unsafe ControlPort configurations. - Refuse to start with certain directory authority keys, and encourage people using them to stop. o Minor features (controller): - Add a PROTOCOLINFO controller command. Like AUTHENTICATE, it is valid before any authentication has been received. It tells a controller what kind of authentication is expected, and what protocol is spoken. Implements proposal 119. - New config option CookieAuthFile to choose a new location for the cookie authentication file, and config option CookieAuthFileGroupReadable to make it group-readable. o Minor features (unit testing): - Add command-line arguments to unit-test executable so that we can invoke any chosen test from the command line rather than having to run the whole test suite at once; and so that we can turn on logging for the unit tests. o Minor bugfixes (on 0.1.2.x): - If we require CookieAuthentication but we fail to write the cookie file, we would warn but not exit, and end up in a state where no controller could authenticate. Now we exit. - If we require CookieAuthentication, stop generating a new cookie every time we change any piece of our config. - When loading bandwidth history, do not believe any information in the future. Fixes bug 434. - When loading entry guard information, do not believe any information in the future. - When we have our clock set far in the future and generate an onion key, then re-set our clock to be correct, we should not stop the onion key from getting rotated. - Clean up torrc sample config file. - Do not automatically run configure from autogen.sh. This non-standard behavior tended to annoy people who have built other programs. o Minor bugfixes (on 0.2.0.x): - Fix a bug with AutomapHostsOnResolve that would always cause the second request to fail. Bug reported by Kate. Bugfix on 0.2.0.3-alpha. - Fix a bug in ADDRMAP controller replies that would sometimes try to print a NULL. Patch from tup. - Read v3 directory authority keys from the right location. - Numerous bugfixes to directory voting code. Changes in version 0.1.2.16 - 2007-08-01 Tor 0.1.2.16 fixes a critical security vulnerability that allows a remote attacker in certain situations to rewrite the user's torrc configuration file. This can completely compromise anonymity of users in most configurations, including those running the Vidalia bundles, TorK, etc. Or worse. o Major security fixes: - Close immediately after missing authentication on control port; do not allow multiple authentication attempts. Changes in version 0.2.0.4-alpha - 2007-08-01 This fourth development snapshot fixes a critical security vulnerability for most users, specifically those running Vidalia, TorK, etc. Everybody should upgrade to either 0.1.2.16 or 0.2.0.4-alpha. o Major security fixes: - Close immediately after missing authentication on control port; do not allow multiple authentication attempts. o Major bugfixes (compilation): - Fix win32 compilation: apparently IN_ADDR and IN6_ADDR are already defined there. o Minor features (performance): - Be even more aggressive about releasing RAM from small empty buffers. Thanks to our free-list code, this shouldn't be too performance-intensive. - Disable sentinel-based debugging for buffer code: we squashed all the bugs that this was supposed to detect a long time ago, and now its only effect is to change our buffer sizes from nice powers of two (which platform mallocs tend to like) to values slightly over powers of two (which make some platform mallocs sad). - Log malloc statistics from mallinfo() on platforms where it exists. Changes in version 0.2.0.3-alpha - 2007-07-29 This third development snapshot introduces new experimental blocking-resistance features and a preliminary version of the v3 directory voting design, and includes many other smaller features and bugfixes. o Major features: - The first pieces of our "bridge" design for blocking-resistance are implemented. People can run bridge directory authorities; people can run bridges; and people can configure their Tor clients with a set of bridges to use as the first hop into the Tor network. See http://archives.seul.org/or/talk/Jul-2007/msg00249.html for details. - Create listener connections before we setuid to the configured User and Group. Now non-Windows users can choose port values under 1024, start Tor as root, and have Tor bind those ports before it changes to another UID. (Windows users could already pick these ports.) - Added a new ConstrainedSockets config option to set SO_SNDBUF and SO_RCVBUF on TCP sockets. Hopefully useful for Tor servers running on "vserver" accounts. (Patch from coderman.) - Be even more aggressive about separating local traffic from relayed traffic when RelayBandwidthRate is set. (Refines proposal 111.) o Major features (experimental): - First cut of code for "v3 dir voting": directory authorities will vote on a common network status document rather than each publishing their own opinion. This code needs more testing and more corner-case handling before it's ready for use. o Security fixes: - Directory authorities now call routers Fast if their bandwidth is at least 100KB/s, and consider their bandwidth adequate to be a Guard if it is at least 250KB/s, no matter the medians. This fix complements proposal 107. [Bugfix on 0.1.2.x] - Directory authorities now never mark more than 3 servers per IP as Valid and Running. (Implements proposal 109, by Kevin Bauer and Damon McCoy.) - Minor change to organizationName and commonName generation procedures in TLS certificates during Tor handshakes, to invalidate some earlier censorware approaches. This is not a long-term solution, but applying it will give us a bit of time to look into the epidemiology of countermeasures as they spread. o Major bugfixes (directory): - Rewrite directory tokenization code to never run off the end of a string. Fixes bug 455. Patch from croup. [Bugfix on 0.1.2.x] o Minor features (controller): - Add a SOURCE_ADDR field to STREAM NEW events so that controllers can match requests to applications. (Patch from Robert Hogan.) - Report address and port correctly on connections to DNSPort. (Patch from Robert Hogan.) - Add a RESOLVE command to launch hostname lookups. (Original patch from Robert Hogan.) - Add GETINFO status/enough-dir-info to let controllers tell whether Tor has downloaded sufficient directory information. (Patch from Tup.) - You can now use the ControlSocket option to tell Tor to listen for controller connections on Unix domain sockets on systems that support them. (Patch from Peter Palfrader.) - STREAM NEW events are generated for DNSPort requests and for tunneled directory connections. (Patch from Robert Hogan.) - New "GETINFO address-mappings/*" command to get address mappings with expiry information. "addr-mappings/*" is now deprecated. (Patch from Tup.) o Minor features (misc): - Merge in some (as-yet-unused) IPv6 address manipulation code. (Patch from croup.) - The tor-gencert tool for v3 directory authorities now creates all files as readable to the file creator only, and write-protects the authority identity key. - When dumping memory usage, list bytes used in buffer memory free-lists. - When running with dmalloc, dump more stats on hup and on exit. - Directory authorities now fail quickly and (relatively) harmlessly if they generate a network status document that is somehow malformed. o Traffic load balancing improvements: - If exit bandwidth ever exceeds one third of total bandwidth, then use the correct formula to weight exit nodes when choosing paths. (Based on patch from Mike Perry.) - Choose perfectly fairly among routers when choosing by bandwidth and weighting by fraction of bandwidth provided by exits. Previously, we would choose with only approximate fairness, and correct ourselves if we ran off the end of the list. [Bugfix on 0.1.2.x] o Performance improvements: - Be more aggressive with freeing buffer RAM or putting it on the memory free lists. - Use Critical Sections rather than Mutexes for synchronizing threads on win32; Mutexes are heavier-weight, and designed for synchronizing between processes. o Deprecated and removed features: - RedirectExits is now deprecated. - Stop allowing address masks that do not correspond to bit prefixes. We have warned about these for a really long time; now it's time to reject them. (Patch from croup.) o Minor bugfixes (directory): - Fix another crash bug related to extra-info caching. (Bug found by Peter Palfrader.) [Bugfix on 0.2.0.2-alpha] - Directories no longer return a "304 not modified" when they don't have the networkstatus the client asked for. Also fix a memory leak when returning 304 not modified. [Bugfixes on 0.2.0.2-alpha] - We had accidentally labelled 0.1.2.x directory servers as not suitable for begin_dir requests, and had labelled no directory servers as suitable for uploading extra-info documents. [Bugfix on 0.2.0.1-alpha] o Minor bugfixes (dns): - Fix a crash when DNSPort is set more than once. (Patch from Robert Hogan.) [Bugfix on 0.2.0.2-alpha] - Add DNSPort connections to the global connection list, so that we can time them out correctly. (Bug found by Robert Hogan.) [Bugfix on 0.2.0.2-alpha] - Fix a dangling reference that could lead to a crash when DNSPort is changed or closed (Patch from Robert Hogan.) [Bugfix on 0.2.0.2-alpha] o Minor bugfixes (controller): - Provide DNS expiry times in GMT, not in local time. For backward compatibility, ADDRMAP events only provide GMT expiry in an extended field. "GETINFO address-mappings" always does the right thing. - Use CRLF line endings properly in NS events. - Terminate multi-line control events properly. (Original patch from tup.) [Bugfix on 0.1.2.x-alpha] - Do not include spaces in SOURCE_ADDR fields in STREAM events. Resolves bug 472. [Bugfix on 0.2.0.x-alpha] Changes in version 0.1.2.15 - 2007-07-17 Tor 0.1.2.15 fixes several crash bugs, fixes some anonymity-related problems, fixes compilation on BSD, and fixes a variety of other bugs. Everybody should upgrade. o Major bugfixes (compilation): - Fix compile on FreeBSD/NetBSD/OpenBSD. Oops. o Major bugfixes (crashes): - Try even harder not to dereference the first character after an mmap(). Reported by lodger. - Fix a crash bug in directory authorities when we re-number the routerlist while inserting a new router. - When the cached-routers file is an even multiple of the page size, don't run off the end and crash. (Fixes bug 455; based on idea from croup.) - Fix eventdns.c behavior on Solaris: It is critical to include orconfig.h _before_ sys/types.h, so that we can get the expected definition of _FILE_OFFSET_BITS. o Major bugfixes (security): - Fix a possible buffer overrun when using BSD natd support. Bug found by croup. - When sending destroy cells from a circuit's origin, don't include the reason for tearing down the circuit. The spec says we didn't, and now we actually don't. Reported by lodger. - Keep streamids from different exits on a circuit separate. This bug may have allowed other routers on a given circuit to inject cells into streams. Reported by lodger; fixes bug 446. - If there's a never-before-connected-to guard node in our list, never choose any guards past it. This way we don't expand our guard list unless we need to. o Minor bugfixes (guard nodes): - Weight guard selection by bandwidth, so that low-bandwidth nodes don't get overused as guards. o Minor bugfixes (directory): - Correctly count the number of authorities that recommend each version. Previously, we were under-counting by 1. - Fix a potential crash bug when we load many server descriptors at once and some of them make others of them obsolete. Fixes bug 458. o Minor bugfixes (hidden services): - Stop tearing down the whole circuit when the user asks for a connection to a port that the hidden service didn't configure. Resolves bug 444. o Minor bugfixes (misc): - On Windows, we were preventing other processes from reading cached-routers while Tor was running. Reported by janbar. - Fix a possible (but very unlikely) bug in picking routers by bandwidth. Add a log message to confirm that it is in fact unlikely. Patch from lodger. - Backport a couple of memory leak fixes. - Backport miscellaneous cosmetic bugfixes. Changes in version 0.2.0.2-alpha - 2007-06-02 o Major bugfixes on 0.2.0.1-alpha: - Fix an assertion failure related to servers without extra-info digests. Resolves bugs 441 and 442. o Minor features (directory): - Support "If-Modified-Since" when answering HTTP requests for directories, running-routers documents, and network-status documents. (There's no need to support it for router descriptors, since those are downloaded by descriptor digest.) o Minor build issues: - Clear up some MIPSPro compiler warnings. - When building from a tarball on a machine that happens to have SVK installed, report the micro-revision as whatever version existed in the tarball, not as "x". Changes in version 0.2.0.1-alpha - 2007-06-01 This early development snapshot provides new features for people running Tor as both a client and a server (check out the new RelayBandwidth config options); lets Tor run as a DNS proxy; and generally moves us forward on a lot of fronts. o Major features, server usability: - New config options RelayBandwidthRate and RelayBandwidthBurst: a separate set of token buckets for relayed traffic. Right now relayed traffic is defined as answers to directory requests, and OR connections that don't have any local circuits on them. o Major features, client usability: - A client-side DNS proxy feature to replace the need for dns-proxy-tor: Just set "DNSPort 9999", and Tor will now listen for DNS requests on port 9999, use the Tor network to resolve them anonymously, and send the reply back like a regular DNS server. The code still only implements a subset of DNS. - Make PreferTunneledDirConns and TunnelDirConns work even when we have no cached directory info. This means Tor clients can now do all of their connections protected by TLS. o Major features, performance and efficiency: - Directory authorities accept and serve "extra info" documents for routers. These documents contain fields from router descriptors that aren't usually needed, and that use a lot of excess bandwidth. Once these fields are removed from router descriptors, the bandwidth savings should be about 60%. [Partially implements proposal 104.] - Servers upload extra-info documents to any authority that accepts them. Authorities (and caches that have been configured to download extra-info documents) download them as needed. [Partially implements proposal 104.] - Change the way that Tor buffers data that it is waiting to write. Instead of queueing data cells in an enormous ring buffer for each client->OR or OR->OR connection, we now queue cells on a separate queue for each circuit. This lets us use less slack memory, and will eventually let us be smarter about prioritizing different kinds of traffic. - Use memory pools to allocate cells with better speed and memory efficiency, especially on platforms where malloc() is inefficient. - Stop reading on edge connections when their corresponding circuit buffers are full; start again as the circuits empty out. o Major features, other: - Add an HSAuthorityRecordStats option that hidden service authorities can use to track statistics of overall hidden service usage without logging information that would be very useful to an attacker. - Start work implementing multi-level keys for directory authorities: Add a standalone tool to generate key certificates. (Proposal 103.) o Security fixes: - Directory authorities now call routers Stable if they have an uptime of at least 30 days, even if that's not the median uptime in the network. Implements proposal 107, suggested by Kevin Bauer and Damon McCoy. o Minor fixes (resource management): - Count the number of open sockets separately from the number of active connection_t objects. This will let us avoid underusing our allocated connection limit. - We no longer use socket pairs to link an edge connection to an anonymous directory connection or a DirPort test connection. Instead, we track the link internally and transfer the data in-process. This saves two sockets per "linked" connection (at the client and at the server), and avoids the nasty Windows socketpair() workaround. - Keep unused 4k and 16k buffers on free lists, rather than wasting 8k for every single inactive connection_t. Free items from the 4k/16k-buffer free lists when they haven't been used for a while. o Minor features (build): - Make autoconf search for libevent, openssl, and zlib consistently. - Update deprecated macros in configure.in. - When warning about missing headers, tell the user to let us know if the compile succeeds anyway, so we can downgrade the warning. - Include the current subversion revision as part of the version string: either fetch it directly if we're in an SVN checkout, do some magic to guess it if we're in an SVK checkout, or use the last-detected version if we're building from a .tar.gz. Use this version consistently in log messages. o Minor features (logging): - Always prepend "Bug: " to any log message about a bug. - Put a platform string (e.g. "Linux i686") in the startup log message, so when people paste just their logs, we know if it's OpenBSD or Windows or what. - When logging memory usage, break down memory used in buffers by buffer type. o Minor features (directory system): - New config option V2AuthoritativeDirectory that all directory authorities should set. This will let future authorities choose not to serve V2 directory information. - Directory authorities allow multiple router descriptors and/or extra info documents to be uploaded in a single go. This will make implementing proposal 104 simpler. o Minor features (controller): - Add a new config option __DisablePredictedCircuits designed for use by the controller, when we don't want Tor to build any circuits preemptively. - Let the controller specify HOP=%d as an argument to ATTACHSTREAM, so we can exit from the middle of the circuit. - Implement "getinfo status/circuit-established". - Implement "getinfo status/version/..." so a controller can tell whether the current version is recommended, and whether any versions are good, and how many authorities agree. (Patch from shibz.) o Minor features (hidden services): - Allow multiple HiddenServicePort directives with the same virtual port; when they occur, the user is sent round-robin to one of the target ports chosen at random. Partially fixes bug 393 by adding limited ad-hoc round-robining. o Minor features (other): - More unit tests. - Add a new AutomapHostsOnResolve option: when it is enabled, any resolve request for hosts matching a given pattern causes Tor to generate an internal virtual address mapping for that host. This allows DNSPort to work sensibly with hidden service users. By default, .exit and .onion addresses are remapped; the list of patterns can be reconfigured with AutomapHostsSuffixes. - Add an "-F" option to tor-resolve to force a resolve for a .onion address. Thanks to the AutomapHostsOnResolve option, this is no longer a completely silly thing to do. - If Tor is invoked from something that isn't a shell (e.g. Vidalia), now we expand "-f ~/.tor/torrc" correctly. Suggested by Matt Edman. - Treat "2gb" when given in torrc for a bandwidth as meaning 2gb, minus 1 byte: the actual maximum declared bandwidth. o Removed features: - Removed support for the old binary "version 0" controller protocol. This has been deprecated since 0.1.1, and warnings have been issued since 0.1.2. When we encounter a v0 control message, we now send back an error and close the connection. - Remove the old "dns worker" server DNS code: it hasn't been default since 0.1.2.2-alpha, and all the servers seem to be using the new eventdns code. o Minor bugfixes (portability): - Even though Windows is equally happy with / and \ as path separators, try to use \ consistently on Windows and / consistently on Unix: it makes the log messages nicer. - Correctly report platform name on Windows 95 OSR2 and Windows 98 SE. - Read resolv.conf files correctly on platforms where read() returns partial results on small file reads. o Minor bugfixes (directory): - Correctly enforce that elements of directory objects do not appear more often than they are allowed to appear. - When we are reporting the DirServer line we just parsed, we were logging the second stanza of the key fingerprint, not the first. o Minor bugfixes (logging): - When we hit an EOF on a log (probably because we're shutting down), don't try to remove the log from the list: just mark it as unusable. (Bulletproofs against bug 222.) o Minor bugfixes (other): - In the exitlist script, only consider the most recently published server descriptor for each server. Also, when the user requests a list of servers that _reject_ connections to a given address, explicitly exclude the IPs that also have servers that accept connections to that address. (Resolves bug 405.) - Stop allowing hibernating servers to be "stable" or "fast". - On Windows, we were preventing other processes from reading cached-routers while Tor was running. (Reported by janbar) - Make the NodeFamilies config option work. (Reported by lodger -- it has never actually worked, even though we added it in Oct 2004.) - Check return values from pthread_mutex functions. - Don't save non-general-purpose router descriptors to the disk cache, because we have no way of remembering what their purpose was when we restart. - Add even more asserts to hunt down bug 417. - Build without verbose warnings even on (not-yet-released) gcc 4.2. - Fix a possible (but very unlikely) bug in picking routers by bandwidth. Add a log message to confirm that it is in fact unlikely. o Minor bugfixes (controller): - Make 'getinfo fingerprint' return a 551 error if we're not a server, so we match what the control spec claims we do. Reported by daejees. - Fix a typo in an error message when extendcircuit fails that caused us to not follow the \r\n-based delimiter protocol. Reported by daejees. o Code simplifications and refactoring: - Stop passing around circuit_t and crypt_path_t pointers that are implicit in other procedure arguments. - Drop the old code to choke directory connections when the corresponding OR connections got full: thanks to the cell queue feature, OR conns don't get full any more. - Make dns_resolve() handle attaching connections to circuits properly, so the caller doesn't have to. - Rename wants_to_read and wants_to_write to read/write_blocked_on_bw. - Keep the connection array as a dynamic smartlist_t, rather than as a fixed-sized array. This is important, as the number of connections is becoming increasingly decoupled from the number of sockets. Changes in version 0.1.2.14 - 2007-05-25 Tor 0.1.2.14 changes the addresses of two directory authorities (this change especially affects those who serve or use hidden services), and fixes several other crash- and security-related bugs. o Directory authority changes: - Two directory authorities (moria1 and moria2) just moved to new IP addresses. This change will particularly affect those who serve or use hidden services. o Major bugfixes (crashes): - If a directory server runs out of space in the connection table as it's processing a begin_dir request, it will free the exit stream but leave it attached to the circuit, leading to unpredictable behavior. (Reported by seeess, fixes bug 425.) - Fix a bug in dirserv_remove_invalid() that would cause authorities to corrupt memory under some really unlikely scenarios. - Tighten router parsing rules. (Bugs reported by Benedikt Boss.) - Avoid segfaults when reading from mmaped descriptor file. (Reported by lodger.) o Major bugfixes (security): - When choosing an entry guard for a circuit, avoid using guards that are in the same family as the chosen exit -- not just guards that are exactly the chosen exit. (Reported by lodger.) o Major bugfixes (resource management): - If a directory authority is down, skip it when deciding where to get networkstatus objects or descriptors. Otherwise we keep asking every 10 seconds forever. Fixes bug 384. - Count it as a failure if we fetch a valid network-status but we don't want to keep it. Otherwise we'll keep fetching it and keep not wanting to keep it. Fixes part of bug 422. - If all of our dirservers have given us bad or no networkstatuses lately, then stop hammering them once per minute even when we think they're failed. Fixes another part of bug 422. o Minor bugfixes: - Actually set the purpose correctly for descriptors inserted with purpose=controller. - When we have k non-v2 authorities in our DirServer config, we ignored the last k authorities in the list when updating our network-statuses. - Correctly back-off from requesting router descriptors that we are having a hard time downloading. - Read resolv.conf files correctly on platforms where read() returns partial results on small file reads. - Don't rebuild the entire router store every time we get 32K of routers: rebuild it when the journal gets very large, or when the gaps in the store get very large. o Minor features: - When routers publish SVN revisions in their router descriptors, authorities now include those versions correctly in networkstatus documents. - Warn when using a version of libevent before 1.3b to run a server on OSX or BSD: these versions interact badly with userspace threads. Changes in version 0.1.2.13 - 2007-04-24 This release features some major anonymity fixes, such as safer path selection; better client performance; faster bootstrapping, better address detection, and better DNS support for servers; write limiting as well as read limiting to make servers easier to run; and a huge pile of other features and bug fixes. The bundles also ship with Vidalia 0.0.11. Tor 0.1.2.13 is released in memory of Rob Levin (1955-2006), aka lilo of the Freenode IRC network, remembering his patience and vision for free speech on the Internet. o Minor fixes: - Fix a memory leak when we ask for "all" networkstatuses and we get one we don't recognize. - Add more asserts to hunt down bug 417. - Disable kqueue on OS X 10.3 and earlier, to fix bug 371. Changes in version 0.1.2.12-rc - 2007-03-16 o Major bugfixes: - Fix an infinite loop introduced in 0.1.2.7-alpha when we serve directory information requested inside Tor connections (i.e. via begin_dir cells). It only triggered when the same connection was serving other data at the same time. Reported by seeess. o Minor bugfixes: - When creating a circuit via the controller, send a 'launched' event when we're done, so we follow the spec better. Changes in version 0.1.2.11-rc - 2007-03-15 o Minor bugfixes (controller), reported by daejees: - Correct the control spec to match how the code actually responds to 'getinfo addr-mappings/*'. - The control spec described a GUARDS event, but the code implemented a GUARD event. Standardize on GUARD, but let people ask for GUARDS too. Changes in version 0.1.2.10-rc - 2007-03-07 o Major bugfixes (Windows): - Do not load the NT services library functions (which may not exist) just to detect if we're a service trying to shut down. Now we run on Win98 and friends again. o Minor bugfixes (other): - Clarify a couple of log messages. - Fix a misleading socks5 error number. Changes in version 0.1.2.9-rc - 2007-03-02 o Major bugfixes (Windows): - On MinGW, use "%I64u" to printf/scanf 64-bit integers, instead of the usual GCC "%llu". This prevents a bug when saving 64-bit int configuration values: the high-order 32 bits would get truncated. In particular, we were being bitten by the default MaxAdvertisedBandwidth of 128 TB turning into 0. (Fixes bug 400 and maybe also bug 397.) o Minor bugfixes (performance): - Use OpenSSL's AES implementation on platforms where it's faster. This could save us as much as 10% CPU usage. o Minor bugfixes (server): - Do not rotate onion key immediately after setting it for the first time. o Minor bugfixes (directory authorities): - Stop calling servers that have been hibernating for a long time "stable". Also, stop letting hibernating or obsolete servers affect uptime and bandwidth cutoffs. - Stop listing hibernating servers in the v1 directory. o Minor bugfixes (hidden services): - Upload hidden service descriptors slightly less often, to reduce load on authorities. o Minor bugfixes (other): - Fix an assert that could trigger if a controller quickly set then cleared EntryNodes. Bug found by Udo van den Heuvel. - On architectures where sizeof(int)>4, still clamp declarable bandwidth to INT32_MAX. - Fix a potential race condition in the rpm installer. Found by Stefan Nordhausen. - Try to fix eventdns warnings once and for all: do not treat a dns rcode of 2 as indicating that the server is completely bad; it sometimes means that the server is just bad for the request in question. (may fix the last of bug 326.) - Disable encrypted directory connections when we don't have a server descriptor for the destination. We'll get this working again in the 0.2.0 branch. Changes in version 0.1.2.8-beta - 2007-02-26 o Major bugfixes (crashes): - Stop crashing when the controller asks us to resetconf more than one config option at once. (Vidalia 0.0.11 does this.) - Fix a crash that happened on Win98 when we're given command-line arguments: don't try to load NT service functions from advapi32.dll except when we need them. (Bug introduced in 0.1.2.7-alpha; resolves bug 389.) - Fix a longstanding obscure crash bug that could occur when we run out of DNS worker processes. (Resolves bug 390.) o Major bugfixes (hidden services): - Correctly detect whether hidden service descriptor downloads are in-progress. (Suggested by Karsten Loesing; fixes bug 399.) o Major bugfixes (accounting): - When we start during an accounting interval before it's time to wake up, remember to wake up at the correct time. (May fix bug 342.) o Minor bugfixes (controller): - Give the controller END_STREAM_REASON_DESTROY events _before_ we clear the corresponding on_circuit variable, and remember later that we don't need to send a redundant CLOSED event. Resolves part 3 of bug 367. - Report events where a resolve succeeded or where we got a socks protocol error correctly, rather than calling both of them "INTERNAL". - Change reported stream target addresses to IP consistently when we finally get the IP from an exit node. - Send log messages to the controller even if they happen to be very long. o Minor bugfixes (other): - Display correct results when reporting which versions are recommended, and how recommended they are. (Resolves bug 383.) - Improve our estimates for directory bandwidth to be less random: guess that an unrecognized directory will have the average bandwidth from all known directories, not that it will have the average bandwidth from those directories earlier than it on the list. - If we start a server with ClientOnly 1, then set ClientOnly to 0 and hup, stop triggering an assert based on an empty onion_key. - On platforms with no working mmap() equivalent, don't warn the user when cached-routers doesn't exist. - Warn the user when mmap() [or its equivalent] fails for some reason other than file-not-found. - Don't warn the user when cached-routers.new doesn't exist: that's perfectly fine when starting up for the first time. - When EntryNodes are configured, rebuild the guard list to contain, in order: the EntryNodes that were guards before; the rest of the EntryNodes; the nodes that were guards before. - Mask out all signals in sub-threads; only the libevent signal handler should be processing them. This should prevent some crashes on some machines using pthreads. (Patch from coderman.) - Fix switched arguments on memset in the implementation of tor_munmap() for systems with no mmap() call. - When Tor receives a router descriptor that it asked for, but no longer wants (because it has received fresh networkstatuses in the meantime), do not warn the user. Cache the descriptor if we're a cache; drop it if we aren't. - Make earlier entry guards _really_ get retried when the network comes back online. - On a malformed DNS reply, always give an error to the corresponding DNS request. - Build with recent libevents on platforms that do not define the nonstandard types "u_int8_t" and friends. o Minor features (controller): - Warn the user when an application uses the obsolete binary v0 control protocol. We're planning to remove support for it during the next development series, so it's good to give people some advance warning. - Add STREAM_BW events to report per-entry-stream bandwidth use. (Patch from Robert Hogan.) - Rate-limit SIGNEWNYM signals in response to controllers that impolitely generate them for every single stream. (Patch from mwenge; closes bug 394.) - Make REMAP stream events have a SOURCE (cache or exit), and make them generated in every case where we get a successful connected or resolved cell. o Minor bugfixes (performance): - Call router_have_min_dir_info half as often. (This is showing up in some profiles, but not others.) - When using GCC, make log_debug never get called at all, and its arguments never get evaluated, when no debug logs are configured. (This is showing up in some profiles, but not others.) o Minor features: - Remove some never-implemented options. Mark PathlenCoinWeight as obsolete. - Implement proposal 106: Stop requiring clients to have well-formed certificates; stop checking nicknames in certificates. (Clients have certificates so that they can look like Tor servers, but in the future we might want to allow them to look like regular TLS clients instead. Nicknames in certificates serve no purpose other than making our protocol easier to recognize on the wire.) - Revise messages on handshake failure again to be even more clear about which are incoming connections and which are outgoing. - Discard any v1 directory info that's over 1 month old (for directories) or over 1 week old (for running-routers lists). - Do not warn when individual nodes in the configuration's EntryNodes, ExitNodes, etc are down: warn only when all possible nodes are down. (Fixes bug 348.) - Always remove expired routers and networkstatus docs before checking whether we have enough information to build circuits. (Fixes bug 373.) - Put a lower-bound on MaxAdvertisedBandwidth. Changes in version 0.1.2.7-alpha - 2007-02-06 o Major bugfixes (rate limiting): - Servers decline directory requests much more aggressively when they're low on bandwidth. Otherwise they end up queueing more and more directory responses, which can't be good for latency. - But never refuse directory requests from local addresses. - Fix a memory leak when sending a 503 response for a networkstatus request. - Be willing to read or write on local connections (e.g. controller connections) even when the global rate limiting buckets are empty. - If our system clock jumps back in time, don't publish a negative uptime in the descriptor. Also, don't let the global rate limiting buckets go absurdly negative. - Flush local controller connection buffers periodically as we're writing to them, so we avoid queueing 4+ megabytes of data before trying to flush. o Major bugfixes (NT services): - Install as NT_AUTHORITY\LocalService rather than as SYSTEM; add a command-line flag so that admins can override the default by saying "tor --service install --user "SomeUser"". This will not affect existing installed services. Also, warn the user that the service will look for its configuration file in the service user's %appdata% directory. (We can't do the 'hardwire the user's appdata directory' trick any more, since we may not have read access to that directory.) o Major bugfixes (other): - Previously, we would cache up to 16 old networkstatus documents indefinitely, if they came from nontrusted authorities. Now we discard them if they are more than 10 days old. - Fix a crash bug in the presence of DNS hijacking (reported by Andrew Del Vecchio). - Detect and reject malformed DNS responses containing circular pointer loops. - If exits are rare enough that we're not marking exits as guards, ignore exit bandwidth when we're deciding the required bandwidth to become a guard. - When we're handling a directory connection tunneled over Tor, don't fill up internal memory buffers with all the data we want to tunnel; instead, only add it if the OR connection that will eventually receive it has some room for it. (This can lead to slowdowns in tunneled dir connections; a better solution will have to wait for 0.2.0.) o Minor bugfixes (dns): - Add some defensive programming to eventdns.c in an attempt to catch possible memory-stomping bugs. - Detect and reject DNS replies containing IPv4 or IPv6 records with an incorrect number of bytes. (Previously, we would ignore the extra bytes.) - Fix as-yet-unused reverse IPv6 lookup code so it sends nybbles in the correct order, and doesn't crash. - Free memory held in recently-completed DNS lookup attempts on exit. This was not a memory leak, but may have been hiding memory leaks. - Handle TTL values correctly on reverse DNS lookups. - Treat failure to parse resolv.conf as an error. o Minor bugfixes (other): - Fix crash with "tor --list-fingerprint" (reported by seeess). - When computing clock skew from directory HTTP headers, consider what time it was when we finished asking for the directory, not what time it is now. - Expire socks connections if they spend too long waiting for the handshake to finish. Previously we would let them sit around for days, if the connecting application didn't close them either. - And if the socks handshake hasn't started, don't send a "DNS resolve socks failed" handshake reply; just close it. - Stop using C functions that OpenBSD's linker doesn't like. - Don't launch requests for descriptors unless we have networkstatuses from at least half of the authorities. This delays the first download slightly under pathological circumstances, but can prevent us from downloading a bunch of descriptors we don't need. - Do not log IPs with TLS failures for incoming TLS connections. (Fixes bug 382.) - If the user asks to use invalid exit nodes, be willing to use unstable ones. - Stop using the reserved ac_cv namespace in our configure script. - Call stat() slightly less often; use fstat() when possible. - Refactor the way we handle pending circuits when an OR connection completes or fails, in an attempt to fix a rare crash bug. - Only rewrite a conn's address based on X-Forwarded-For: headers if it's a parseable public IP address; and stop adding extra quotes to the resulting address. o Major features: - Weight directory requests by advertised bandwidth. Now we can let servers enable write limiting but still allow most clients to succeed at their directory requests. (We still ignore weights when choosing a directory authority; I hope this is a feature.) o Minor features: - Create a new file ReleaseNotes which was the old ChangeLog. The new ChangeLog file now includes the summaries for all development versions too. - Check for addresses with invalid characters at the exit as well as at the client, and warn less verbosely when they fail. You can override this by setting ServerDNSAllowNonRFC953Addresses to 1. - Adapt a patch from goodell to let the contrib/exitlist script take arguments rather than require direct editing. - Inform the server operator when we decide not to advertise a DirPort due to AccountingMax enabled or a low BandwidthRate. It was confusing Zax, so now we're hopefully more helpful. - Bring us one step closer to being able to establish an encrypted directory tunnel without knowing a descriptor first. Still not ready yet. As part of the change, now assume we can use a create_fast cell if we don't know anything about a router. - Allow exit nodes to use nameservers running on ports other than 53. - Servers now cache reverse DNS replies. - Add an --ignore-missing-torrc command-line option so that we can get the "use sensible defaults if the configuration file doesn't exist" behavior even when specifying a torrc location on the command line. o Minor features (controller): - Track reasons for OR connection failure; make these reasons available via the controller interface. (Patch from Mike Perry.) - Add a SOCKS_BAD_HOSTNAME client status event so controllers can learn when clients are sending malformed hostnames to Tor. - Clean up documentation for controller status events. - Add a REMAP status to stream events to note that a stream's address has changed because of a cached address or a MapAddress directive. Changes in version 0.1.2.6-alpha - 2007-01-09 o Major bugfixes: - Fix an assert error introduced in 0.1.2.5-alpha: if a single TLS connection handles more than 4 gigs in either direction, we crash. - Fix an assert error introduced in 0.1.2.5-alpha: if we're an advertised exit node, somebody might try to exit from us when we're bootstrapping and before we've built our descriptor yet. Refuse the connection rather than crashing. o Minor bugfixes: - Warn if we (as a server) find that we've resolved an address that we weren't planning to resolve. - Warn that using select() on any libevent version before 1.1 will be unnecessarily slow (even for select()). - Flush ERR-level controller status events just like we currently flush ERR-level log events, so that a Tor shutdown doesn't prevent the controller from learning about current events. o Minor features (more controller status events): - Implement EXTERNAL_ADDRESS server status event so controllers can learn when our address changes. - Implement BAD_SERVER_DESCRIPTOR server status event so controllers can learn when directories reject our descriptor. - Implement SOCKS_UNKNOWN_PROTOCOL client status event so controllers can learn when a client application is speaking a non-socks protocol to our SocksPort. - Implement DANGEROUS_SOCKS client status event so controllers can learn when a client application is leaking DNS addresses. - Implement BUG general status event so controllers can learn when Tor is unhappy about its internal invariants. - Implement CLOCK_SKEW general status event so controllers can learn when Tor thinks the system clock is set incorrectly. - Implement GOOD_SERVER_DESCRIPTOR and ACCEPTED_SERVER_DESCRIPTOR server status events so controllers can learn when their descriptors are accepted by a directory. - Implement CHECKING_REACHABILITY and REACHABILITY_{SUCCEEDED|FAILED} server status events so controllers can learn about Tor's progress in deciding whether it's reachable from the outside. - Implement BAD_LIBEVENT general status event so controllers can learn when we have a version/method combination in libevent that needs to be changed. - Implement NAMESERVER_STATUS, NAMESERVER_ALL_DOWN, DNS_HIJACKED, and DNS_USELESS server status events so controllers can learn about changes to DNS server status. o Minor features (directory): - Authorities no longer recommend exits as guards if this would shift too much load to the exit nodes. Changes in version 0.1.2.5-alpha - 2007-01-06 o Major features: - Enable write limiting as well as read limiting. Now we sacrifice capacity if we're pushing out lots of directory traffic, rather than overrunning the user's intended bandwidth limits. - Include TLS overhead when counting bandwidth usage; previously, we would count only the bytes sent over TLS, but not the bytes used to send them. - Support running the Tor service with a torrc not in the same directory as tor.exe and default to using the torrc located in the %appdata%\Tor\ of the user who installed the service. Patch from Matt Edman. - Servers now check for the case when common DNS requests are going to wildcarded addresses (i.e. all getting the same answer), and change their exit policy to reject *:* if it's happening. - Implement BEGIN_DIR cells, so we can connect to the directory server via TLS to do encrypted directory requests rather than plaintext. Enable via the TunnelDirConns and PreferTunneledDirConns config options if you like. o Minor features (config and docs): - Start using the state file to store bandwidth accounting data: the bw_accounting file is now obsolete. We'll keep generating it for a while for people who are still using 0.1.2.4-alpha. - Try to batch changes to the state file so that we do as few disk writes as possible while still storing important things in a timely fashion. - The state file and the bw_accounting file get saved less often when the AvoidDiskWrites config option is set. - Make PIDFile work on Windows (untested). - Add internal descriptions for a bunch of configuration options: accessible via controller interface and in comments in saved options files. - Reject *:563 (NNTPS) in the default exit policy. We already reject NNTP by default, so this seems like a sensible addition. - Clients now reject hostnames with invalid characters. This should avoid some inadvertent info leaks. Add an option AllowNonRFC953Hostnames to disable this behavior, in case somebody is running a private network with hosts called @, !, and #. - Add a maintainer script to tell us which options are missing documentation: "make check-docs". - Add a new address-spec.txt document to describe our special-case addresses: .exit, .onion, and .noconnnect. o Minor features (DNS): - Ongoing work on eventdns infrastructure: now it has dns server and ipv6 support. One day Tor will make use of it. - Add client-side caching for reverse DNS lookups. - Add support to tor-resolve tool for reverse lookups and SOCKS5. - When we change nameservers or IP addresses, reset and re-launch our tests for DNS hijacking. o Minor features (directory): - Authorities now specify server versions in networkstatus. This adds about 2% to the size of compressed networkstatus docs, and allows clients to tell which servers support BEGIN_DIR and which don't. The implementation is forward-compatible with a proposed future protocol version scheme not tied to Tor versions. - DirServer configuration lines now have an orport= option so clients can open encrypted tunnels to the authorities without having downloaded their descriptors yet. Enabled for moria1, moria2, tor26, and lefkada now in the default configuration. - Directory servers are more willing to send a 503 "busy" if they are near their write limit, especially for v1 directory requests. Now they can use their limited bandwidth for actual Tor traffic. - Clients track responses with status 503 from dirservers. After a dirserver has given us a 503, we try not to use it until an hour has gone by, or until we have no dirservers that haven't given us a 503. - When we get a 503 from a directory, and we're not a server, we don't count the failure against the total number of failures allowed for the thing we're trying to download. - Report X-Your-Address-Is correctly from tunneled directory connections; don't report X-Your-Address-Is when it's an internal address; and never believe reported remote addresses when they're internal. - Protect against an unlikely DoS attack on directory servers. - Add a BadDirectory flag to network status docs so that authorities can (eventually) tell clients about caches they believe to be broken. o Minor features (controller): - Have GETINFO dir/status/* work on hosts with DirPort disabled. - Reimplement GETINFO so that info/names stays in sync with the actual keys. - Implement "GETINFO fingerprint". - Implement "SETEVENTS GUARD" so controllers can get updates on entry guard status as it changes. o Minor features (clean up obsolete pieces): - Remove some options that have been deprecated since at least 0.1.0.x: AccountingMaxKB, LogFile, DebugLogFile, LogLevel, and SysLog. Use AccountingMax instead of AccountingMaxKB, and use Log to set log options. - We no longer look for identity and onion keys in "identity.key" and "onion.key" -- these were replaced by secret_id_key and secret_onion_key in 0.0.8pre1. - We no longer require unrecognized directory entries to be preceded by "opt". o Major bugfixes (security): - Stop sending the HttpProxyAuthenticator string to directory servers when directory connections are tunnelled through Tor. - Clients no longer store bandwidth history in the state file. - Do not log introduction points for hidden services if SafeLogging is set. - When generating bandwidth history, round down to the nearest 1k. When storing accounting data, round up to the nearest 1k. - When we're running as a server, remember when we last rotated onion keys, so that we will rotate keys once they're a week old even if we never stay up for a week ourselves. o Major bugfixes (other): - Fix a longstanding bug in eventdns that prevented the count of timed-out resolves from ever being reset. This bug caused us to give up on a nameserver the third time it timed out, and try it 10 seconds later... and to give up on it every time it timed out after that. - Take out the '5 second' timeout from the connection retry schedule. Now the first connect attempt will wait a full 10 seconds before switching to a new circuit. Perhaps this will help a lot. Based on observations from Mike Perry. - Fix a bug on the Windows implementation of tor_mmap_file() that would prevent the cached-routers file from ever loading. Reported by John Kimble. o Minor bugfixes: - Fix an assert failure when a directory authority sets AuthDirRejectUnlisted and then receives a descriptor from an unlisted router. Reported by seeess. - Avoid a double-free when parsing malformed DirServer lines. - Fix a bug when a BSD-style PF socket is first used. Patch from Fabian Keil. - Fix a bug in 0.1.2.2-alpha that prevented clients from asking to resolve an address at a given exit node even when they ask for it by name. - Servers no longer ever list themselves in their "family" line, even if configured to do so. This makes it easier to configure family lists conveniently. - When running as a server, don't fall back to 127.0.0.1 when no nameservers are configured in /etc/resolv.conf; instead, make the user fix resolv.conf or specify nameservers explicitly. (Resolves bug 363.) - Stop accepting certain malformed ports in configured exit policies. - Don't re-write the fingerprint file every restart, unless it has changed. - Stop warning when a single nameserver fails: only warn when _all_ of our nameservers have failed. Also, when we only have one nameserver, raise the threshold for deciding that the nameserver is dead. - Directory authorities now only decide that routers are reachable if their identity keys are as expected. - When the user uses bad syntax in the Log config line, stop suggesting other bad syntax as a replacement. - Correctly detect ipv6 DNS capability on OpenBSD. o Minor bugfixes (controller): - Report the circuit number correctly in STREAM CLOSED events. Bug reported by Mike Perry. - Do not report bizarre values for results of accounting GETINFOs when the last second's write or read exceeds the allotted bandwidth. - Report "unrecognized key" rather than an empty string when the controller tries to fetch a networkstatus that doesn't exist. Changes in version 0.1.1.26 - 2006-12-14 o Security bugfixes: - Stop sending the HttpProxyAuthenticator string to directory servers when directory connections are tunnelled through Tor. - Clients no longer store bandwidth history in the state file. - Do not log introduction points for hidden services if SafeLogging is set. o Minor bugfixes: - Fix an assert failure when a directory authority sets AuthDirRejectUnlisted and then receives a descriptor from an unlisted router (reported by seeess). Changes in version 0.1.2.4-alpha - 2006-12-03 o Major features: - Add support for using natd; this allows FreeBSDs earlier than 5.1.2 to have ipfw send connections through Tor without using SOCKS. (Patch from Zajcev Evgeny with tweaks from tup.) o Minor features: - Make all connections to addresses of the form ".noconnect" immediately get closed. This lets application/controller combos successfully test whether they're talking to the same Tor by watching for STREAM events. - Make cross.sh cross-compilation script work even when autogen.sh hasn't been run. (Patch from Michael Mohr.) - Statistics dumped by -USR2 now include a breakdown of public key operations, for profiling. o Major bugfixes: - Fix a major leak when directory authorities parse their approved-routers list, a minor memory leak when we fail to pick an exit node, and a few rare leaks on errors. - Handle TransPort connections even when the server sends data before the client sends data. Previously, the connection would just hang until the client sent data. (Patch from tup based on patch from Zajcev Evgeny.) - Avoid assert failure when our cached-routers file is empty on startup. o Minor bugfixes: - Don't log spurious warnings when we see a circuit close reason we don't recognize; it's probably just from a newer version of Tor. - Have directory authorities allow larger amounts of drift in uptime without replacing the server descriptor: previously, a server that restarted every 30 minutes could have 48 "interesting" descriptors per day. - Start linking to the Tor specification and Tor reference manual correctly in the Windows installer. - Add Vidalia to the OS X uninstaller script, so when we uninstall Tor/Privoxy we also uninstall Vidalia. - Resume building on Irix64, and fix a lot of warnings from its MIPSpro C compiler. - Don't corrupt last_guessed_ip in router_new_address_suggestion() when we're running as a client. Changes in version 0.1.1.25 - 2006-11-04 o Major bugfixes: - When a client asks us to resolve (rather than connect to) an address, and we have a cached answer, give them the cached answer. Previously, we would give them no answer at all. - We were building exactly the wrong circuits when we predict hidden service requirements, meaning Tor would have to build all its circuits on demand. - If none of our live entry guards have a high uptime, but we require a guard with a high uptime, try adding a new guard before we give up on the requirement. This patch should make long-lived connections more stable on average. - When testing reachability of our DirPort, don't launch new tests when there's already one in progress -- unreachable servers were stacking up dozens of testing streams. o Security bugfixes: - When the user sends a NEWNYM signal, clear the client-side DNS cache too. Otherwise we continue to act on previous information. o Minor bugfixes: - Avoid a memory corruption bug when creating a hash table for the first time. - Avoid possibility of controller-triggered crash when misusing certain commands from a v0 controller on platforms that do not handle printf("%s",NULL) gracefully. - Avoid infinite loop on unexpected controller input. - Don't log spurious warnings when we see a circuit close reason we don't recognize; it's probably just from a newer version of Tor. - Add Vidalia to the OS X uninstaller script, so when we uninstall Tor/Privoxy we also uninstall Vidalia. Changes in version 0.1.2.3-alpha - 2006-10-29 o Minor features: - Prepare for servers to publish descriptors less often: never discard a descriptor simply for being too old until either it is recommended by no authorities, or until we get a better one for the same router. Make caches consider retaining old recommended routers for even longer. - If most authorities set a BadExit flag for a server, clients don't think of it as a general-purpose exit. Clients only consider authorities that advertise themselves as listing bad exits. - Directory servers now provide 'Pragma: no-cache' and 'Expires' headers for content, so that we can work better in the presence of caching HTTP proxies. - Allow authorities to list nodes as bad exits by fingerprint or by address. o Minor features, controller: - Add a REASON field to CIRC events; for backward compatibility, this field is sent only to controllers that have enabled the extended event format. Also, add additional reason codes to explain why a given circuit has been destroyed or truncated. (Patches from Mike Perry) - Add a REMOTE_REASON field to extended CIRC events to tell the controller about why a remote OR told us to close a circuit. - Stream events also now have REASON and REMOTE_REASON fields, working much like those for circuit events. - There's now a GETINFO ns/... field so that controllers can ask Tor about the current status of a router. - A new event type "NS" to inform a controller when our opinion of a router's status has changed. - Add a GETINFO events/names and GETINFO features/names so controllers can tell which events and features are supported. - A new CLEARDNSCACHE signal to allow controllers to clear the client-side DNS cache without expiring circuits. o Security bugfixes: - When the user sends a NEWNYM signal, clear the client-side DNS cache too. Otherwise we continue to act on previous information. o Minor bugfixes: - Avoid sending junk to controllers or segfaulting when a controller uses EVENT_NEW_DESC with verbose nicknames. - Stop triggering asserts if the controller tries to extend hidden service circuits (reported by mwenge). - Avoid infinite loop on unexpected controller input. - When the controller does a "GETINFO network-status", tell it about even those routers whose descriptors are very old, and use long nicknames where appropriate. - Change NT service functions to be loaded on demand. This lets us build with MinGW without breaking Tor for Windows 98 users. - Do DirPort reachability tests less often, since a single test chews through many circuits before giving up. - In the hidden service example in torrc.sample, stop recommending esoteric and discouraged hidden service options. - When stopping an NT service, wait up to 10 sec for it to actually stop. Patch from Matt Edman; resolves bug 295. - Fix handling of verbose nicknames with ORCONN controller events: make them show up exactly when requested, rather than exactly when not requested. - When reporting verbose nicknames in entry_guards_getinfo(), avoid printing a duplicate "$" in the keys we send (reported by mwenge). - Correctly set maximum connection limit on Cygwin. (This time for sure!) - Try to detect Windows correctly when cross-compiling. - Detect the size of the routers file correctly even if it is corrupted (on systems without mmap) or not page-aligned (on systems with mmap). This bug was harmless. - Sometimes we didn't bother sending a RELAY_END cell when an attempt to open a stream fails; now we do in more cases. This should make clients able to find a good exit faster in some cases, since unhandleable requests will now get an error rather than timing out. - Resolve two memory leaks when rebuilding the on-disk router cache (reported by fookoowa). - Clean up minor code warnings suggested by the MIPSpro C compiler, and reported by some Centos users. - Controller signals now work on non-Unix platforms that don't define SIGUSR1 and SIGUSR2 the way we expect. - Patch from Michael Mohr to contrib/cross.sh, so it checks more values before failing, and always enables eventdns. - Libevent-1.2 exports, but does not define in its headers, strlcpy. Try to fix this in configure.in by checking for most functions before we check for libevent. Changes in version 0.1.2.2-alpha - 2006-10-07 o Major features: - Make our async eventdns library on-by-default for Tor servers, and plan to deprecate the separate dnsworker threads. - Add server-side support for "reverse" DNS lookups (using PTR records so clients can determine the canonical hostname for a given IPv4 address). Only supported by servers using eventdns; servers now announce in their descriptors whether they support eventdns. - Specify and implement client-side SOCKS5 interface for reverse DNS lookups (see doc/socks-extensions.txt). - Add a BEGIN_DIR relay cell type for an easier in-protocol way to connect to directory servers through Tor. Previously, clients needed to find Tor exits to make private connections to directory servers. - Avoid choosing Exit nodes for entry or middle hops when the total bandwidth available from non-Exit nodes is much higher than the total bandwidth available from Exit nodes. - Workaround for name servers (like Earthlink's) that hijack failing DNS requests and replace the no-such-server answer with a "helpful" redirect to an advertising-driven search portal. Also work around DNS hijackers who "helpfully" decline to hijack known-invalid RFC2606 addresses. Config option "ServerDNSDetectHijacking 0" lets you turn it off. - Send out a burst of long-range padding cells once we've established that we're reachable. Spread them over 4 circuits, so hopefully a few will be fast. This exercises our bandwidth and bootstraps us into the directory more quickly. o New/improved config options: - Add new config option "ResolvConf" to let the server operator choose an alternate resolve.conf file when using eventdns. - Add an "EnforceDistinctSubnets" option to control our "exclude servers on the same /16" behavior. It's still on by default; this is mostly for people who want to operate private test networks with all the machines on the same subnet. - If one of our entry guards is on the ExcludeNodes list, or the directory authorities don't think it's a good guard, treat it as if it were unlisted: stop using it as a guard, and throw it off the guards list if it stays that way for a long time. - Allow directory authorities to be marked separately as authorities for the v1 directory protocol, the v2 directory protocol, and as hidden service directories, to make it easier to retire old authorities. V1 authorities should set "HSAuthoritativeDir 1" to continue being hidden service authorities too. - Remove 8888 as a LongLivedPort, and add 6697 (IRCS). o Minor features, controller: - Fix CIRC controller events so that controllers can learn the identity digests of non-Named servers used in circuit paths. - Let controllers ask for more useful identifiers for servers. Instead of learning identity digests for un-Named servers and nicknames for Named servers, the new identifiers include digest, nickname, and indication of Named status. Off by default; see control-spec.txt for more information. - Add a "getinfo address" controller command so it can display Tor's best guess to the user. - New controller event to alert the controller when our server descriptor has changed. - Give more meaningful errors on controller authentication failure. o Minor features, other: - When asked to resolve a hostname, don't use non-exit servers unless requested to do so. This allows servers with broken DNS to be useful to the network. - Divide eventdns log messages into warn and info messages. - Reserve the nickname "Unnamed" for routers that can't pick a hostname: any router can call itself Unnamed; directory authorities will never allocate Unnamed to any particular router; clients won't believe that any router is the canonical Unnamed. - Only include function names in log messages for info/debug messages. For notice/warn/err, the content of the message should be clear on its own, and printing the function name only confuses users. - Avoid some false positives during reachability testing: don't try to test via a server that's on the same /24 as us. - If we fail to build a circuit to an intended enclave, and it's not mandatory that we use that enclave, stop wanting it. - When eventdns is enabled, allow multithreaded builds on NetBSD and OpenBSD. (We had previously disabled threads on these platforms because they didn't have working thread-safe resolver functions.) o Major bugfixes, anonymity/security: - If a client asked for a server by name, and there's a named server in our network-status but we don't have its descriptor yet, we could return an unnamed server instead. - Fix NetBSD bug that could allow someone to force uninitialized RAM to be sent to a server's DNS resolver. This only affects NetBSD and other platforms that do not bounds-check tolower(). - Reject (most) attempts to use Tor circuits with length one. (If many people start using Tor as a one-hop proxy, exit nodes become a more attractive target for compromise.) - Just because your DirPort is open doesn't mean people should be able to remotely teach you about hidden service descriptors. Now only accept rendezvous posts if you've got HSAuthoritativeDir set. o Major bugfixes, other: - Don't crash on race condition in dns.c: tor_assert(!resolve->expire) - When a client asks the server to resolve (not connect to) an address, and it has a cached answer, give them the cached answer. Previously, the server would give them no answer at all. - Allow really slow clients to not hang up five minutes into their directory downloads (suggested by Adam J. Richter). - We were building exactly the wrong circuits when we anticipated hidden service requirements, meaning Tor would have to build all its circuits on demand. - Avoid crashing when we mmap a router cache file of size 0. - When testing reachability of our DirPort, don't launch new tests when there's already one in progress -- unreachable servers were stacking up dozens of testing streams. o Minor bugfixes, correctness: - If we're a directory mirror and we ask for "all" network status documents, we would discard status documents from authorities we don't recognize. - Avoid a memory corruption bug when creating a hash table for the first time. - Avoid controller-triggered crash when misusing certain commands from a v0 controller on platforms that do not handle printf("%s",NULL) gracefully. - Don't crash when a controller sends a third argument to an "extendcircuit" request. - Controller protocol fixes: fix encoding in "getinfo addr-mappings" response; fix error code when "getinfo dir/status/" fails. - Avoid crash when telling controller stream-status and a stream is detached. - Patch from Adam Langley to fix assert() in eventdns.c. - Fix a debug log message in eventdns to say "X resolved to Y" instead of "X resolved to X". - Make eventdns give strings for DNS errors, not just error numbers. - Track unreachable entry guards correctly: don't conflate 'unreachable by us right now' with 'listed as down by the directory authorities'. With the old code, if a guard was unreachable by us but listed as running, it would clog our guard list forever. - Behave correctly in case we ever have a network with more than 2GB/s total advertised capacity. - Make TrackExitHosts case-insensitive, and fix the behavior of ".suffix" TrackExitHosts items to avoid matching in the middle of an address. - Finally fix the openssl warnings from newer gccs that believe that ignoring a return value is okay, but casting a return value and then ignoring it is a sign of madness. - Prevent the contrib/exitlist script from printing the same result more than once. - Patch from Steve Hildrey: Generate network status correctly on non-versioning dirservers. - Don't listen to the X-Your-Address-Is hint if you did the lookup via Tor; otherwise you'll think you're the exit node's IP address. o Minor bugfixes, performance: - Two small performance improvements on parsing descriptors. - Major performance improvement on inserting descriptors: change algorithm from O(n^2) to O(n). - Make the common memory allocation path faster on machines where malloc(0) returns a pointer. - Start remembering X-Your-Address-Is directory hints even if you're a client, so you can become a server more smoothly. - Avoid duplicate entries on MyFamily line in server descriptor. o Packaging, features: - Remove architecture from OS X builds. The official builds are now universal binaries. - The Debian package now uses --verify-config when (re)starting, to distinguish configuration errors from other errors. - Update RPMs to require libevent 1.1b. o Packaging, bugfixes: - Patches so Tor builds with MinGW on Windows. - Patches so Tor might run on Cygwin again. - Resume building on non-gcc compilers and ancient gcc. Resume building with the -O0 compile flag. Resume building cleanly on Debian woody. - Run correctly on OS X platforms with case-sensitive filesystems. - Correct includes for net/if.h and net/pfvar.h on OpenBSD (from Tup). - Add autoconf checks so Tor can build on Solaris x86 again. o Documentation - Documented (and renamed) ServerDNSSearchDomains and ServerDNSResolvConfFile options. - Be clearer that the *ListenAddress directives can be repeated multiple times. Changes in version 0.1.1.24 - 2006-09-29 o Major bugfixes: - Allow really slow clients to not hang up five minutes into their directory downloads (suggested by Adam J. Richter). - Fix major performance regression from 0.1.0.x: instead of checking whether we have enough directory information every time we want to do something, only check when the directory information has changed. This should improve client CPU usage by 25-50%. - Don't crash if, after a server has been running for a while, it can't resolve its hostname. o Minor bugfixes: - Allow Tor to start when RunAsDaemon is set but no logs are set. - Don't crash when the controller receives a third argument to an "extendcircuit" request. - Controller protocol fixes: fix encoding in "getinfo addr-mappings" response; fix error code when "getinfo dir/status/" fails. - Fix configure.in to not produce broken configure files with more recent versions of autoconf. Thanks to Clint for his auto* voodoo. - Fix security bug on NetBSD that could allow someone to force uninitialized RAM to be sent to a server's DNS resolver. This only affects NetBSD and other platforms that do not bounds-check tolower(). - Warn user when using libevent 1.1a or earlier with win32 or kqueue methods: these are known to be buggy. - If we're a directory mirror and we ask for "all" network status documents, we would discard status documents from authorities we don't recognize. Changes in version 0.1.2.1-alpha - 2006-08-27 o Major features: - Add "eventdns" async dns library from Adam Langley, tweaked to build on OSX and Windows. Only enabled if you pass the --enable-eventdns argument to configure. - Allow servers with no hostname or IP address to learn their IP address by asking the directory authorities. This code only kicks in when you would normally have exited with a "no address" error. Nothing's authenticated, so use with care. - Rather than waiting a fixed amount of time between retrying application connections, we wait only 5 seconds for the first, 10 seconds for the second, and 15 seconds for each retry after that. Hopefully this will improve the expected user experience. - Patch from Tup to add support for transparent AP connections: this basically bundles the functionality of trans-proxy-tor into the Tor mainline. Now hosts with compliant pf/netfilter implementations can redirect TCP connections straight to Tor without diverting through SOCKS. Needs docs. - Busy directory servers save lots of memory by spooling server descriptors, v1 directories, and v2 networkstatus docs to buffers as needed rather than en masse. Also mmap the cached-routers files, so we don't need to keep the whole thing in memory too. - Automatically avoid picking more than one node from the same /16 network when constructing a circuit. - Revise and clean up the torrc.sample that we ship with; add a section for BandwidthRate and BandwidthBurst. o Minor features: - Split circuit_t into origin_circuit_t and or_circuit_t, and split connection_t into edge, or, dir, control, and base structs. These will save quite a bit of memory on busy servers, and they'll also help us track down bugs in the code and bugs in the spec. - Experimentally re-enable kqueue on OSX when using libevent 1.1b or later. Log when we are doing this, so we can diagnose it when it fails. (Also, recommend libevent 1.1b for kqueue and win32 methods; deprecate libevent 1.0b harder; make libevent recommendation system saner.) - Start being able to build universal binaries on OS X (thanks to Phobos). - Export the default exit policy via the control port, so controllers don't need to guess what it is / will be later. - Add a man page entry for ProtocolWarnings. - Add TestVia config option to the man page. - Remove even more protocol-related warnings from Tor server logs, such as bad TLS handshakes and malformed begin cells. - Stop fetching descriptors if you're not a dir mirror and you haven't tried to establish any circuits lately. [This currently causes some dangerous behavior, because when you start up again you'll use your ancient server descriptors.] - New DirPort behavior: if you have your dirport set, you download descriptors aggressively like a directory mirror, whether or not your ORPort is set. - Get rid of the router_retry_connections notion. Now routers no longer try to rebuild long-term connections to directory authorities, and directory authorities no longer try to rebuild long-term connections to all servers. We still don't hang up connections in these two cases though -- we need to look at it more carefully to avoid flapping, and we likely need to wait til 0.1.1.x is obsolete. - Drop compatibility with obsolete Tors that permit create cells to have the wrong circ_id_type. - Re-enable per-connection rate limiting. Get rid of the "OP bandwidth" concept. Lay groundwork for "bandwidth classes" -- separate global buckets that apply depending on what sort of conn it is. - Start publishing one minute or so after we find our ORPort to be reachable. This will help reduce the number of descriptors we have for ourselves floating around, since it's quite likely other things (e.g. DirPort) will change during that minute too. - Fork the v1 directory protocol into its own spec document, and mark dir-spec.txt as the currently correct (v2) spec. o Major bugfixes: - When we find our DirPort to be reachable, publish a new descriptor so we'll tell the world (reported by pnx). - Publish a new descriptor after we hup/reload. This is important if our config has changed such that we'll want to start advertising our DirPort now, etc. - Allow Tor to start when RunAsDaemon is set but no logs are set. - When we have a state file we cannot parse, tell the user and move it aside. Now we avoid situations where the user starts Tor in 1904, Tor writes a state file with that timestamp in it, the user fixes her clock, and Tor refuses to start. - Fix configure.in to not produce broken configure files with more recent versions of autoconf. Thanks to Clint for his auto* voodoo. - "tor --verify-config" now exits with -1(255) or 0 depending on whether the config options are bad or good. - Resolve bug 321 when using dnsworkers: append a period to every address we resolve at the exit node, so that we do not accidentally pick up local addresses, and so that failing searches are retried in the resolver search domains. (This is already solved for eventdns.) (This breaks Blossom servers for now.) - If we are using an exit enclave and we can't connect, e.g. because its webserver is misconfigured to not listen on localhost, then back off and try connecting from somewhere else before we fail. o Minor bugfixes: - Start compiling on MinGW on Windows (patches from Mike Chiussi). - Start compiling on MSVC6 on Windows (patches from Frediano Ziglio). - Fix bug 314: Tor clients issued "unsafe socks" warnings even when the IP address is mapped through MapAddress to a hostname. - Start passing "ipv4" hints to getaddrinfo(), so servers don't do useless IPv6 DNS resolves. - Patch suggested by Karsten Loesing: respond to SIGNAL command before we execute the signal, in case the signal shuts us down. - Clean up AllowInvalidNodes man page entry. - Claim a commonname of Tor, rather than TOR, in TLS handshakes. - Add more asserts to track down an assert error on a windows Tor server with connection_add being called with socket == -1. - Handle reporting OR_CONN_EVENT_NEW events to the controller. - Fix misleading log messages: an entry guard that is "unlisted", as well as not known to be "down" (because we've never heard of it), is not therefore "up". - Remove code to special-case "-cvs" ending, since it has not actually mattered since 0.0.9. - Make our socks5 handling more robust to broken socks clients: throw out everything waiting on the buffer in between socks handshake phases, since they can't possibly (so the theory goes) have predicted what we plan to respond to them. Changes in version 0.1.1.23 - 2006-07-30 o Major bugfixes: - Fast Tor servers, especially exit nodes, were triggering asserts due to a bug in handling the list of pending DNS resolves. Some bugs still remain here; we're hunting them. - Entry guards could crash clients by sending unexpected input. - More fixes on reachability testing: if you find yourself reachable, then don't ever make any client requests (so you stop predicting circuits), then hup or have your clock jump, then later your IP changes, you won't think circuits are working, so you won't try to test reachability, so you won't publish. o Minor bugfixes: - Avoid a crash if the controller does a resetconf firewallports and then a setconf fascistfirewall=1. - Avoid an integer underflow when the dir authority decides whether a router is stable: we might wrongly label it stable, and compute a slightly wrong median stability, when a descriptor is published later than now. - Fix a place where we might trigger an assert if we can't build our own server descriptor yet. Changes in version 0.1.1.22 - 2006-07-05 o Major bugfixes: - Fix a big bug that was causing servers to not find themselves reachable if they changed IP addresses. Since only 0.1.1.22+ servers can do reachability testing correctly, now we automatically make sure to test via one of these. - Fix to allow clients and mirrors to learn directory info from descriptor downloads that get cut off partway through. - Directory authorities had a bug in deciding if a newly published descriptor was novel enough to make everybody want a copy -- a few servers seem to be publishing new descriptors many times a minute. o Minor bugfixes: - Fix a rare bug that was causing some servers to complain about "closing wedged cpuworkers" and skip some circuit create requests. - Make the Exit flag in directory status documents actually work. Changes in version 0.1.1.21 - 2006-06-10 o Crash and assert fixes from 0.1.1.20: - Fix a rare crash on Tor servers that have enabled hibernation. - Fix a seg fault on startup for Tor networks that use only one directory authority. - Fix an assert from a race condition that occurs on Tor servers while exiting, where various threads are trying to log that they're exiting, and delete the logs, at the same time. - Make our unit tests pass again on certain obscure platforms. o Other fixes: - Add support for building SUSE RPM packages. - Speed up initial bootstrapping for clients: if we are making our first ever connection to any entry guard, then don't mark it down right after that. - When only one Tor server in the network is labelled as a guard, and we've already picked him, we would cycle endlessly picking him again, being unhappy about it, etc. Now we specifically exclude current guards when picking a new guard. - Servers send create cells more reliably after the TLS connection is established: we were sometimes forgetting to send half of them when we had more than one pending. - If we get a create cell that asks us to extend somewhere, but the Tor server there doesn't match the expected digest, we now send a destroy cell back, rather than silently doing nothing. - Make options->RedirectExit work again. - Make cookie authentication for the controller work again. - Stop being picky about unusual characters in the arguments to mapaddress. It's none of our business. - Add a new config option "TestVia" that lets you specify preferred middle hops to use for test circuits. Perhaps this will let me debug the reachability problems better. o Log / documentation fixes: - If we're a server and some peer has a broken TLS certificate, don't log about it unless ProtocolWarnings is set, i.e., we want to hear about protocol violations by others. - Fix spelling of VirtualAddrNetwork in man page. - Add a better explanation at the top of the autogenerated torrc file about what happened to our old torrc. Changes in version 0.1.1.20 - 2006-05-23 o Bugfixes: - Downgrade a log severity where servers complain that they're invalid. - Avoid a compile warning on FreeBSD. - Remove string size limit on NEWDESC messages; solve bug 291. - Correct the RunAsDaemon entry in the man page; ignore RunAsDaemon more thoroughly when we're running on windows. Changes in version 0.1.1.19-rc - 2006-05-03 o Minor bugs: - Regenerate our local descriptor if it's dirty and we try to use it locally (e.g. if it changes during reachability detection). - If we setconf our ORPort to 0, we continued to listen on the old ORPort and receive connections. - Avoid a second warning about machine/limits.h on Debian GNU/kFreeBSD. - Be willing to add our own routerinfo into the routerlist. Now authorities will include themselves in their directories and network-statuses. - Stop trying to upload rendezvous descriptors to every directory authority: only try the v1 authorities. - Servers no longer complain when they think they're not registered with the directory authorities. There were too many false positives. - Backport dist-rpm changes so rpms can be built without errors. o Features: - Implement an option, VirtualAddrMask, to set which addresses get handed out in response to mapaddress requests. This works around a bug in tsocks where 127.0.0.0/8 is never socksified. Changes in version 0.1.1.18-rc - 2006-04-10 o Major fixes: - Work harder to download live network-statuses from all the directory authorities we know about. Improve the threshold decision logic so we're more robust to edge cases. - When fetching rendezvous descriptors, we were willing to ask v2 authorities too, which would always return 404. o Minor fixes: - Stop listing down or invalid nodes in the v1 directory. This will reduce its bulk by about 1/3, and reduce load on directory mirrors. - When deciding whether a router is Fast or Guard-worthy, consider his advertised BandwidthRate and not just the BandwidthCapacity. - No longer ship INSTALL and README files -- they are useless now. - Force rpmbuild to behave and honor target_cpu. - Avoid warnings about machine/limits.h on Debian GNU/kFreeBSD. - Start to include translated versions of the tor-doc-*.html files, along with the screenshots. Still needs more work. - Start sending back 512 and 451 errors if mapaddress fails, rather than not sending anything back at all. - When we fail to bind or listen on an incoming or outgoing socket, we should close it before failing. otherwise we just leak it. (thanks to weasel for finding.) - Allow "getinfo dir/status/foo" to work, as long as your DirPort is enabled. (This is a hack, and will be fixed in 0.1.2.x.) - Make NoPublish (even though deprecated) work again. - Fix a minor security flaw where a versioning auth dirserver could list a recommended version many times in a row to make clients more convinced that it's recommended. - Fix crash bug if there are two unregistered servers running with the same nickname, one of them is down, and you ask for them by nickname in your EntryNodes or ExitNodes. Also, try to pick the one that's running rather than an arbitrary one. - Fix an infinite loop we could hit if we go offline for too long. - Complain when we hit WSAENOBUFS on recv() or write() too. Perhaps this will help us hunt the bug. - If you're not a versioning dirserver, don't put the string "client-versions \nserver-versions \n" in your network-status. - Lower the minimum required number of file descriptors to 1000, so we can have some overhead for Valgrind on Linux, where the default ulimit -n is 1024. o New features: - Add tor.dizum.com as the fifth authoritative directory server. - Add a new config option FetchUselessDescriptors, off by default, for when you plan to run "exitlist" on your client and you want to know about even the non-running descriptors. Changes in version 0.1.1.17-rc - 2006-03-28 o Major fixes: - Clients and servers since 0.1.1.10-alpha have been expiring connections whenever they are idle for 5 minutes and they *do* have circuits on them. Oops. With this new version, clients will discard their previous entry guard choices and avoid choosing entry guards running these flawed versions. - Fix memory leak when uncompressing concatenated zlib streams. This was causing substantial leaks over time on Tor servers. - The v1 directory was including servers as much as 48 hours old, because that's how the new routerlist->routers works. Now only include them if they're 20 hours old or less. o Minor fixes: - Resume building on irix64, netbsd 2.0, etc. - On non-gcc compilers (e.g. solaris), use "-g -O" instead of "-Wall -g -O2". - Stop writing the "router.desc" file, ever. Nothing uses it anymore, and it is confusing some users. - Mirrors stop caching the v1 directory so often. - Make the max number of old descriptors that a cache will hold rise with the number of directory authorities, so we can scale. - Change our win32 uname() hack to be more forgiving about what win32 versions it thinks it's found. o New features: - Add lefkada.eecs.harvard.edu as a fourth authoritative directory server. - When the controller's *setconf commands fail, collect an error message in a string and hand it back to the controller. - Make the v2 dir's "Fast" flag based on relative capacity, just like "Stable" is based on median uptime. Name everything in the top 7/8 Fast, and only the top 1/2 gets to be a Guard. - Log server fingerprint on startup, so new server operators don't have to go hunting around their filesystem for it. - Return a robots.txt on our dirport to discourage google indexing. - Let the controller ask for GETINFO dir/status/foo so it can ask directly rather than connecting to the dir port. Only works when dirport is set for now. o New config options rather than constants in the code: - SocksTimeout: How long do we let a socks connection wait unattached before we fail it? - CircuitBuildTimeout: Cull non-open circuits that were born at least this many seconds ago. - CircuitIdleTimeout: Cull open clean circuits that were born at least this many seconds ago. Changes in version 0.1.1.16-rc - 2006-03-18 o Bugfixes on 0.1.1.15-rc: - Fix assert when the controller asks to attachstream a connect-wait or resolve-wait stream. - Now do address rewriting when the controller asks us to attach to a particular circuit too. This will let Blossom specify "moria2.exit" without having to learn what moria2's IP address is. - Make the "tor --verify-config" command-line work again, so people can automatically check if their torrc will parse. - Authoritative dirservers no longer require an open connection from a server to consider him "reachable". We need this change because when we add new auth dirservers, old servers won't know not to hang up on them. - Let Tor build on Sun CC again. - Fix an off-by-one buffer size in dirserv.c that magically never hit our three authorities but broke sjmurdoch's own tor network. - If we as a directory mirror don't know of any v1 directory authorities, then don't try to cache any v1 directories. - Stop warning about unknown servers in our family when they are given as hex digests. - Stop complaining as quickly to the server operator that he hasn't registered his nickname/key binding. - Various cleanups so we can add new V2 Auth Dirservers. - Change "AllowUnverifiedNodes" to "AllowInvalidNodes", to reflect the updated flags in our v2 dir protocol. - Resume allowing non-printable characters for exit streams (both for connecting and for resolving). Now we tolerate applications that don't follow the RFCs. But continue to block malformed names at the socks side. o Bugfixes on 0.1.0.x: - Fix assert bug in close_logs(): when we close and delete logs, remove them all from the global "logfiles" list. - Fix minor integer overflow in calculating when we expect to use up our bandwidth allocation before hibernating. - Fix a couple of bugs in OpenSSL detection. Also, deal better when there are multiple SSLs installed with different versions. - When we try to be a server and Address is not explicitly set and our hostname resolves to a private IP address, try to use an interface address if it has a public address. Now Windows machines that think of themselves as localhost can work by default. o New features: - Let the controller ask for GETINFO dir/server/foo so it can ask directly rather than connecting to the dir port. - Let the controller tell us about certain router descriptors that it doesn't want Tor to use in circuits. Implement SETROUTERPURPOSE and modify +POSTDESCRIPTOR to do this. - New config option SafeSocks to reject all application connections using unsafe socks protocols. Defaults to off. Changes in version 0.1.1.15-rc - 2006-03-11 o Bugfixes and cleanups: - When we're printing strings from the network, don't try to print non-printable characters. This protects us against shell escape sequence exploits, and also against attacks to fool humans into misreading their logs. - Fix a bug where Tor would fail to establish any connections if you left it off for 24 hours and then started it: we were happy with the obsolete network statuses, but they all referred to router descriptors that were too old to fetch, so we ended up with no valid router descriptors. - Fix a seg fault in the controller's "getinfo orconn-status" command while listing status on incoming handshaking connections. Introduce a status name "NEW" for these connections. - If we get a linelist or linelist_s config option from the torrc (e.g. ExitPolicy) and it has no value, warn and skip rather than silently resetting it to its default. - Don't abandon entry guards until they've been down or gone for a whole month. - Cleaner and quieter log messages. o New features: - New controller signal NEWNYM that makes new application requests use clean circuits. - Add a new circuit purpose 'controller' to let the controller ask for a circuit that Tor won't try to use. Extend the EXTENDCIRCUIT controller command to let you specify the purpose if you're starting a new circuit. Add a new SETCIRCUITPURPOSE controller command to let you change a circuit's purpose after it's been created. - Accept "private:*" in routerdesc exit policies; not generated yet because older Tors do not understand it. - Add BSD-style contributed startup script "rc.subr" from Peter Thoenen. Changes in version 0.1.1.14-alpha - 2006-02-20 o Bugfixes on 0.1.1.x: - Don't die if we ask for a stdout or stderr log (even implicitly) and we're set to RunAsDaemon -- just warn. - We still had a few bugs in the OR connection rotation code that caused directory servers to slowly aggregate connections to other fast Tor servers. This time for sure! - Make log entries on Win32 include the name of the function again. - We were treating a pair of exit policies if they were equal even if one said accept and the other said reject -- causing us to not always publish a new descriptor since we thought nothing had changed. - Retry pending server downloads as well as pending networkstatus downloads when we unexpectedly get a socks request. - We were ignoring the IS_FAST flag in the directory status, meaning we were willing to pick trivial-bandwidth nodes for "fast" connections. - If the controller's SAVECONF command fails (e.g. due to file permissions), let the controller know that it failed. o Features: - If we're trying to be a Tor server and running Windows 95/98/ME as a server, explain that we'll likely crash. - When we're a server, a client asks for an old-style directory, and our write bucket is empty, don't give it to him. This way small servers can continue to serve the directory *sometimes*, without getting overloaded. - Compress exit policies even more -- look for duplicate lines and remove them. - Clients now honor the "guard" flag in the router status when picking entry guards, rather than looking at is_fast or is_stable. - Retain unrecognized lines in $DATADIR/state file, so that we can be forward-compatible. - Generate 18.0.0.0/8 address policy format in descs when we can; warn when the mask is not reducible to a bit-prefix. - Let the user set ControlListenAddress in the torrc. This can be dangerous, but there are some cases (like a secured LAN) where it makes sense. - Split ReachableAddresses into ReachableDirAddresses and ReachableORAddresses, so we can restrict Dir conns to port 80 and OR conns to port 443. - Now we can target arch and OS in rpm builds (contributed by Phobos). Also make the resulting dist-rpm filename match the target arch. - New config options to help controllers: FetchServerDescriptors and FetchHidServDescriptors for whether to fetch server info and hidserv info or let the controller do it, and PublishServerDescriptor and PublishHidServDescriptors. - Also let the controller set the __AllDirActionsPrivate config option if you want all directory fetches/publishes to happen via Tor (it assumes your controller bootstraps your circuits). Changes in version 0.1.0.17 - 2006-02-17 o Crash bugfixes on 0.1.0.x: - When servers with a non-zero DirPort came out of hibernation, sometimes they would trigger an assert. o Other important bugfixes: - On platforms that don't have getrlimit (like Windows), we were artificially constraining ourselves to a max of 1024 connections. Now just assume that we can handle as many as 15000 connections. Hopefully this won't cause other problems. o Backported features: - When we're a server, a client asks for an old-style directory, and our write bucket is empty, don't give it to him. This way small servers can continue to serve the directory *sometimes*, without getting overloaded. - Whenever you get a 503 in response to a directory fetch, try once more. This will become important once servers start sending 503's whenever they feel busy. - Fetch a new directory every 120 minutes, not every 40 minutes. Now that we have hundreds of thousands of users running the old directory algorithm, it's starting to hurt a lot. - Bump up the period for forcing a hidden service descriptor upload from 20 minutes to 1 hour. Changes in version 0.1.1.13-alpha - 2006-02-09 o Crashes in 0.1.1.x: - When you tried to setconf ORPort via the controller, Tor would crash. So people using TorCP to become a server were sad. - Solve (I hope) the stack-smashing bug that we were seeing on fast servers. The problem appears to be something do with OpenSSL's random number generation, or how we call it, or something. Let me know if the crashes continue. - Turn crypto hardware acceleration off by default, until we find somebody smart who can test it for us. (It appears to produce seg faults in at least some cases.) - Fix a rare assert error when we've tried all intro points for a hidden service and we try fetching the service descriptor again: "Assertion conn->state != AP_CONN_STATE_RENDDESC_WAIT failed" o Major fixes: - Fix a major load balance bug: we were round-robining in 16 KB chunks, and servers with bandwidthrate of 20 KB, while downloading a 600 KB directory, would starve their other connections. Now we try to be a bit more fair. - Dir authorities and mirrors were never expiring the newest descriptor for each server, causing memory and directory bloat. - Fix memory-bloating and connection-bloating bug on servers: We were never closing any connection that had ever had a circuit on it, because we were checking conn->n_circuits == 0, yet we had a bug that let it go negative. - Make Tor work using squid as your http proxy again -- squid returns an error if you ask for a URL that's too long, and it uses a really generic error message. Plus, many people are behind a transparent squid so they don't even realize it. - On platforms that don't have getrlimit (like Windows), we were artificially constraining ourselves to a max of 1024 connections. Now just assume that we can handle as many as 15000 connections. Hopefully this won't cause other problems. - Add a new config option ExitPolicyRejectPrivate which defaults to 1. This means all exit policies will begin with rejecting private addresses, unless the server operator explicitly turns it off. o Major features: - Clients no longer download descriptors for non-running descriptors. - Before we add new directory authorities, we should make it clear that only v1 authorities should receive/publish hidden service descriptors. o Minor features: - As soon as we've fetched some more directory info, immediately try to download more server descriptors. This way we don't have a 10 second pause during initial bootstrapping. - Remove even more loud log messages that the server operator can't do anything about. - When we're running an obsolete or un-recommended version, make the log message more clear about what the problem is and what versions *are* still recommended. - Provide a more useful warn message when our onion queue gets full: the CPU is too slow or the exit policy is too liberal. - Don't warn when we receive a 503 from a dirserver/cache -- this will pave the way for them being able to refuse if they're busy. - When we fail to bind a listener, try to provide a more useful log message: e.g., "Is Tor already running?" - Adjust tor-spec to parameterize cell and key lengths. Now Ian Goldberg can prove things about our handshake protocol more easily. - MaxConn has been obsolete for a while now. Document the ConnLimit config option, which is a *minimum* number of file descriptors that must be available else Tor refuses to start. - Apply Matt Ghali's --with-syslog-facility patch to ./configure if you log to syslog and want something other than LOG_DAEMON. - Make dirservers generate a separate "guard" flag to mean, "would make a good entry guard". Make clients parse it and vote on it. Not used by clients yet. - Implement --with-libevent-dir option to ./configure. Also, improve search techniques to find libevent, and use those for openssl too. - Bump the default bandwidthrate to 3 MB, and burst to 6 MB - Only start testing reachability once we've established a circuit. This will make startup on dirservers less noisy. - Don't try to upload hidden service descriptors until we have established a circuit. - Fix the controller's "attachstream 0" command to treat conn like it just connected, doing address remapping, handling .exit and .onion idioms, and so on. Now we're more uniform in making sure that the controller hears about new and closing connections. Changes in version 0.1.1.12-alpha - 2006-01-11 o Bugfixes on 0.1.1.x: - The fix to close duplicate server connections was closing all Tor client connections if they didn't establish a circuit quickly enough. Oops. - Fix minor memory issue (double-free) that happened on exit. o Bugfixes on 0.1.0.x: - Tor didn't warn when it failed to open a log file. Changes in version 0.1.1.11-alpha - 2006-01-10 o Crashes in 0.1.1.x: - Include all the assert/crash fixes from 0.1.0.16. - If you start Tor and then quit very quickly, there were some races that tried to free things that weren't allocated yet. - Fix a rare memory stomp if you're running hidden services. - Fix segfault when specifying DirServer in config without nickname. - Fix a seg fault when you finish connecting to a server but at that moment you dump his server descriptor. - Extendcircuit and Attachstream controller commands would assert/crash if you don't give them enough arguments. - Fix an assert error when we're out of space in the connection_list and we try to post a hidden service descriptor (reported by weasel). - If you specify a relative torrc path and you set RunAsDaemon in your torrc, then it chdir()'s to the new directory. If you HUP, it tries to load the new torrc location, fails, and exits. The fix: no longer allow a relative path to torrc using -f. o Major features: - Implement "entry guards": automatically choose a handful of entry nodes and stick with them for all circuits. Only pick new guards when the ones you have are unsuitable, and if the old guards become suitable again, switch back. This will increase security dramatically against certain end-point attacks. The EntryNodes config option now provides some hints about which entry guards you want to use most; and StrictEntryNodes means to only use those. - New directory logic: download by descriptor digest, not by fingerprint. Caches try to download all listed digests from authorities; clients try to download "best" digests from caches. This avoids partitioning and isolating attacks better. - Make the "stable" router flag in network-status be the median of the uptimes of running valid servers, and make clients pay attention to the network-status flags. Thus the cutoff adapts to the stability of the network as a whole, making IRC, IM, etc connections more reliable. o Major fixes: - Tor servers with dynamic IP addresses were needing to wait 18 hours before they could start doing reachability testing using the new IP address and ports. This is because they were using the internal descriptor to learn what to test, yet they were only rebuilding the descriptor once they decided they were reachable. - Tor 0.1.1.9 and 0.1.1.10 had a serious bug that caused clients to download certain server descriptors, throw them away, and then fetch them again after 30 minutes. Now mirrors throw away these server descriptors so clients can't get them. - We were leaving duplicate connections to other ORs open for a week, rather than closing them once we detect a duplicate. This only really affected authdirservers, but it affected them a lot. - Spread the authdirservers' reachability testing over the entire testing interval, so we don't try to do 500 TLS's at once every 20 minutes. o Minor fixes: - If the network is down, and we try to connect to a conn because we have a circuit in mind, and we timeout (30 seconds) because the network never answers, we were expiring the circuit, but we weren't obsoleting the connection or telling the entry_guards functions. - Some Tor servers process billions of cells per day. These statistics need to be uint64_t's. - Check for integer overflows in more places, when adding elements to smartlists. This could possibly prevent a buffer overflow on malicious huge inputs. I don't see any, but I haven't looked carefully. - ReachableAddresses kept growing new "reject *:*" lines on every setconf/reload. - When you "setconf log" via the controller, it should remove all logs. We were automatically adding back in a "log notice stdout". - Newly bootstrapped Tor networks couldn't establish hidden service circuits until they had nodes with high uptime. Be more tolerant. - We were marking servers down when they could not answer every piece of the directory request we sent them. This was far too harsh. - Fix the torify (tsocks) config file to not use Tor for localhost connections. - Directory authorities now go to the proper authority when asking for a networkstatus, even when they want a compressed one. - Fix a harmless bug that was causing Tor servers to log "Got an end because of misc error, but we're not an AP. Closing." - Authorities were treating their own descriptor changes as cosmetic, meaning the descriptor available in the network-status and the descriptor that clients downloaded were different. - The OS X installer was adding a symlink for tor_resolve but the binary was called tor-resolve (reported by Thomas Hardly). - Workaround a problem with some http proxies where they refuse GET requests that specify "Content-Length: 0" (reported by Adrian). - Fix wrong log message when you add a "HiddenServiceNodes" config line without any HiddenServiceDir line (reported by Chris Thomas). o Minor features: - Write the TorVersion into the state file so we have a prayer of keeping forward and backward compatibility. - Revive the FascistFirewall config option rather than eliminating it: now it's a synonym for ReachableAddresses *:80,*:443. - Clients choose directory servers from the network status lists, not from their internal list of router descriptors. Now they can go to caches directly rather than needing to go to authorities to bootstrap. - Directory authorities ignore router descriptors that have only cosmetic differences: do this for 0.1.0.x servers now too. - Add a new flag to network-status indicating whether the server can answer v2 directory requests too. - Authdirs now stop whining so loudly about bad descriptors that they fetch from other dirservers. So when there's a log complaint, it's for sure from a freshly uploaded descriptor. - Reduce memory requirements in our structs by changing the order of fields. - There used to be two ways to specify your listening ports in a server descriptor: on the "router" line and with a separate "ports" line. Remove support for the "ports" line. - New config option "AuthDirRejectUnlisted" for auth dirservers as a panic button: if we get flooded with unusable servers we can revert to only listing servers in the approved-routers file. - Auth dir servers can now mark a fingerprint as "!reject" or "!invalid" in the approved-routers file (as its nickname), to refuse descriptors outright or include them but marked as invalid. - Servers store bandwidth history across restarts/crashes. - Add reasons to DESTROY and RELAY_TRUNCATED cells, so clients can get a better idea of why their circuits failed. Not used yet. - Directory mirrors now cache up to 16 unrecognized network-status docs. Now we can add new authdirservers and they'll be cached too. - When picking a random directory, prefer non-authorities if any are known. - New controller option "getinfo desc/all-recent" to fetch the latest server descriptor for every router that Tor knows about. Changes in version 0.1.0.16 - 2006-01-02 o Crash bugfixes on 0.1.0.x: - On Windows, build with a libevent patch from "I-M Weasel" to avoid corrupting the heap, losing FDs, or crashing when we need to resize the fd_sets. (This affects the Win32 binaries, not Tor's sources.) - It turns out sparc64 platforms crash on unaligned memory access too -- so detect and avoid this. - Handle truncated compressed data correctly (by detecting it and giving an error). - Fix possible-but-unlikely free(NULL) in control.c. - When we were closing connections, there was a rare case that stomped on memory, triggering seg faults and asserts. - Avoid potential infinite recursion when building a descriptor. (We don't know that it ever happened, but better to fix it anyway.) - We were neglecting to unlink marked circuits from soon-to-close OR connections, which caused some rare scribbling on freed memory. - Fix a memory stomping race bug when closing the joining point of two rendezvous circuits. - Fix an assert in time parsing found by Steven Murdoch. o Other bugfixes on 0.1.0.x: - When we're doing reachability testing, provide more useful log messages so the operator knows what to expect. - Do not check whether DirPort is reachable when we are suppressing advertising it because of hibernation. - When building with -static or on Solaris, we sometimes needed -ldl. - When we're deciding whether a stream has enough circuits around that can handle it, count the freshly dirty ones and not the ones that are so dirty they won't be able to handle it. - When we're expiring old circuits, we had a logic error that caused us to close new rendezvous circuits rather than old ones. - Give a more helpful log message when you try to change ORPort via the controller: you should upgrade Tor if you want that to work. - We were failing to parse Tor versions that start with "Tor ". - Tolerate faulty streams better: when a stream fails for reason exitpolicy, stop assuming that the router is lying about his exit policy. When a stream fails for reason misc, allow it to retry just as if it was resolvefailed. When a stream has failed three times, reset its failure count so we can try again and get all three tries. Changes in version 0.1.1.10-alpha - 2005-12-11 o Correctness bugfixes on 0.1.0.x: - On Windows, build with a libevent patch from "I-M Weasel" to avoid corrupting the heap, losing FDs, or crashing when we need to resize the fd_sets. (This affects the Win32 binaries, not Tor's sources.) - Stop doing the complex voodoo overkill checking for insecure Diffie-Hellman keys. Just check if it's in [2,p-2] and be happy. - When we were closing connections, there was a rare case that stomped on memory, triggering seg faults and asserts. - We were neglecting to unlink marked circuits from soon-to-close OR connections, which caused some rare scribbling on freed memory. - When we're deciding whether a stream has enough circuits around that can handle it, count the freshly dirty ones and not the ones that are so dirty they won't be able to handle it. - Recover better from TCP connections to Tor servers that are broken but don't tell you (it happens!); and rotate TLS connections once a week. - When we're expiring old circuits, we had a logic error that caused us to close new rendezvous circuits rather than old ones. - Fix a scary-looking but apparently harmless bug where circuits would sometimes start out in state CIRCUIT_STATE_OR_WAIT at servers, and never switch to state CIRCUIT_STATE_OPEN. - When building with -static or on Solaris, we sometimes needed to build with -ldl. - Give a useful message when people run Tor as the wrong user, rather than telling them to start chowning random directories. - We were failing to inform the controller about new .onion streams. o Security bugfixes on 0.1.0.x: - Refuse server descriptors if the fingerprint line doesn't match the included identity key. Tor doesn't care, but other apps (and humans) might actually be trusting the fingerprint line. - We used to kill the circuit when we receive a relay command we don't recognize. Now we just drop it. - Start obeying our firewall options more rigorously: . If we can't get to a dirserver directly, try going via Tor. . Don't ever try to connect (as a client) to a place our firewall options forbid. . If we specify a proxy and also firewall options, obey the firewall options even when we're using the proxy: some proxies can only proxy to certain destinations. - Fix a bug found by Lasse Overlier: when we were making internal circuits (intended to be cannibalized later for rendezvous and introduction circuits), we were picking them so that they had useful exit nodes. There was no need for this, and it actually aids some statistical attacks. - Start treating internal circuits and exit circuits separately. It's important to keep them separate because internal circuits have their last hops picked like middle hops, rather than like exit hops. So exiting on them will break the user's expectations. o Bugfixes on 0.1.1.x: - Take out the mis-feature where we tried to detect IP address flapping for people with DynDNS, and chose not to upload a new server descriptor sometimes. - Try to be compatible with OpenSSL 0.9.6 again. - Log fix: when the controller is logging about .onion addresses, sometimes it didn't include the ".onion" part of the address. - Don't try to modify options->DirServers internally -- if the user didn't specify any, just add the default ones directly to the trusted dirserver list. This fixes a bug where people running controllers would use SETCONF on some totally unrelated config option, and Tor would start yelling at them about changing their DirServer lines. - Let the controller's redirectstream command specify a port, in case the controller wants to change that too. - When we requested a pile of server descriptors, we sometimes accidentally launched a duplicate request for the first one. - Bugfix for trackhostexits: write down the fingerprint of the chosen exit, not its nickname, because the chosen exit might not be verified. - When parsing foo.exit, if foo is unknown, and we are leaving circuits unattached, set the chosen_exit field and leave the address empty. This matters because controllers got confused otherwise. - Directory authorities no longer try to download server descriptors that they know they will reject. o Features and updates: - Replace balanced trees with hash tables: this should make stuff significantly faster. - Resume using the AES counter-mode implementation that we ship, rather than OpenSSL's. Ours is significantly faster. - Many other CPU and memory improvements. - Add a new config option FastFirstHopPK (on by default) so clients do a trivial crypto handshake for their first hop, since TLS has already taken care of confidentiality and authentication. - Add a new config option TestSocks so people can see if their applications are using socks4, socks4a, socks5-with-ip, or socks5-with-hostname. This way they don't have to keep mucking with tcpdump and wondering if something got cached somewhere. - Warn when listening on a public address for socks. I suspect a lot of people are setting themselves up as open socks proxies, and they have no idea that jerks on the Internet are using them, since they simply proxy the traffic into the Tor network. - Add "private:*" as an alias in configuration for policies. Now you can simplify your exit policy rather than needing to list every single internal or nonroutable network space. - Add a new controller event type that allows controllers to get all server descriptors that were uploaded to a router in its role as authoritative dirserver. - Start shipping socks-extensions.txt, tor-doc-unix.html, tor-doc-server.html, and stylesheet.css in the tarball. - Stop shipping tor-doc.html in the tarball. Changes in version 0.1.1.9-alpha - 2005-11-15 o Usability improvements: - Start calling it FooListenAddress rather than FooBindAddress, since few of our users know what it means to bind an address or port. - Reduce clutter in server logs. We're going to try to make them actually usable now. New config option ProtocolWarnings that lets you hear about how _other Tors_ are breaking the protocol. Off by default. - Divide log messages into logging domains. Once we put some sort of interface on this, it will let people looking at more verbose log levels specify the topics they want to hear more about. - Make directory servers return better http 404 error messages instead of a generic "Servers unavailable". - Check for even more Windows version flags when writing the platform string in server descriptors, and note any we don't recognize. - Clean up more of the OpenSSL memory when exiting, so we can detect memory leaks better. - Make directory authorities be non-versioning, non-naming by default. Now we can add new directory servers without requiring their operators to pay close attention. - When logging via syslog, include the pid whenever we provide a log entry. Suggested by Todd Fries. o Performance improvements: - Directory servers now silently throw away new descriptors that haven't changed much if the timestamps are similar. We do this to tolerate older Tor servers that upload a new descriptor every 15 minutes. (It seemed like a good idea at the time.) - Inline bottleneck smartlist functions; use fast versions by default. - Add a "Map from digest to void*" abstraction digestmap_t so we can do less hex encoding/decoding. Use it in router_get_by_digest() to resolve a performance bottleneck. - Allow tor_gzip_uncompress to extract as much as possible from truncated compressed data. Try to extract as many descriptors as possible from truncated http responses (when DIR_PURPOSE_FETCH_ROUTERDESC). - Make circ->onionskin a pointer, not a static array. moria2 was using 125000 circuit_t's after it had been up for a few weeks, which translates to 20+ megs of wasted space. - The private half of our EDH handshake keys are now chosen out of 320 bits, not 1024 bits. (Suggested by Ian Goldberg.) o Security improvements: - Start making directory caches retain old routerinfos, so soon clients can start asking by digest of descriptor rather than by fingerprint of server. - Add half our entropy from RAND_poll in OpenSSL. This knows how to use egd (if present), openbsd weirdness (if present), vms/os2 weirdness (if we ever port there), and more in the future. o Bugfixes on 0.1.0.x: - Do round-robin writes of at most 16 kB per write. This might be more fair on loaded Tor servers, and it might resolve our Windows crash bug. It might also slow things down. - Our TLS handshakes were generating a single public/private keypair for the TLS context, rather than making a new one for each new connections. Oops. (But we were still rotating them periodically, so it's not so bad.) - When we were cannibalizing a circuit with a particular exit node in mind, we weren't checking to see if that exit node was already present earlier in the circuit. Oops. - When a Tor server's IP changes (e.g. from a dyndns address), upload a new descriptor so clients will learn too. - Really busy servers were keeping enough circuits open on stable connections that they were wrapping around the circuit_id space. (It's only two bytes.) This exposed a bug where we would feel free to reuse a circuit_id even if it still exists but has been marked for close. Try to fix this bug. Some bug remains. - If we would close a stream early (e.g. it asks for a .exit that we know would refuse it) but the LeaveStreamsUnattached config option is set by the controller, then don't close it. o Bugfixes on 0.1.1.8-alpha: - Fix a big pile of memory leaks, some of them serious. - Do not try to download a routerdesc if we would immediately reject it as obsolete. - Resume inserting a newline between all router descriptors when generating (old style) signed directories, since our spec says we do. - When providing content-type application/octet-stream for server descriptors using .z, we were leaving out the content-encoding header. Oops. (Everything tolerated this just fine, but that doesn't mean we need to be part of the problem.) - Fix a potential seg fault in getconf and getinfo using version 1 of the controller protocol. - Avoid crash: do not check whether DirPort is reachable when we are suppressing it because of hibernation. - Make --hash-password not crash on exit. Changes in version 0.1.1.8-alpha - 2005-10-07 o New features (major): - Clients don't download or use the directory anymore. Now they download and use network-statuses from the trusted dirservers, and fetch individual server descriptors as needed from mirrors. See dir-spec.txt for all the gory details. - Be more conservative about whether to advertise our DirPort. The main change is to not advertise if we're running at capacity and either a) we could hibernate or b) our capacity is low and we're using a default DirPort. - Use OpenSSL's AES when OpenSSL has version 0.9.7 or later. o New features (minor): - Try to be smart about when to retry network-status and server-descriptor fetches. Still needs some tuning. - Stop parsing, storing, or using running-routers output (but mirrors still cache and serve it). - Consider a threshold of versioning dirservers (dirservers who have an opinion about which Tor versions are still recommended) before deciding whether to warn the user that he's obsolete. - Dirservers can now reject/invalidate by key and IP, with the config options "AuthDirInvalid" and "AuthDirReject". This is useful since currently we automatically list servers as running and usable even if we know they're jerks. - Provide dire warnings to any users who set DirServer; move it out of torrc.sample and into torrc.complete. - Add MyFamily to torrc.sample in the server section. - Add nicknames to the DirServer line, so we can refer to them without requiring all our users to memorize their IP addresses. - When we get an EOF or a timeout on a directory connection, note how many bytes of serverdesc we are dropping. This will help us determine whether it is smart to parse incomplete serverdesc responses. - Add a new function to "change pseudonyms" -- that is, to stop using any currently-dirty circuits for new streams, so we don't link new actions to old actions. Currently it's only called on HUP (or SIGNAL RELOAD). - On sighup, if UseHelperNodes changed to 1, use new circuits. - Start using RAND_bytes rather than RAND_pseudo_bytes from OpenSSL. Also, reseed our entropy every hour, not just at startup. And entropy in 512-bit chunks, not 160-bit chunks. o Fixes on 0.1.1.7-alpha: - Nobody ever implemented EVENT_ADDRMAP for control protocol version 0, so don't let version 0 controllers ask for it. - If you requested something with too many newlines via the v1 controller protocol, you could crash tor. - Fix a number of memory leaks, including some pretty serious ones. - Re-enable DirPort testing again, so Tor servers will be willing to advertise their DirPort if it's reachable. - On TLS handshake, only check the other router's nickname against its expected nickname if is_named is set. o Fixes forward-ported from 0.1.0.15: - Don't crash when we don't have any spare file descriptors and we try to spawn a dns or cpu worker. - Make the numbers in read-history and write-history into uint64s, so they don't overflow and publish negatives in the descriptor. o Fixes on 0.1.0.x: - For the OS X package's modified privoxy config file, comment out the "logfile" line so we don't log everything passed through privoxy. - We were whining about using socks4 or socks5-with-local-lookup even when it's an IP in the "virtual" range we designed exactly for this case. - We were leaking some memory every time the client changes IPs. - Never call free() on tor_malloc()d memory. This will help us use dmalloc to detect memory leaks. - Check for named servers when looking them up by nickname; warn when we'recalling a non-named server by its nickname; don't warn twice about the same name. - Try to list MyFamily elements by key, not by nickname, and warn if we've not heard of the server. - Make windows platform detection (uname equivalent) smarter. - It turns out sparc64 doesn't like unaligned access either. Changes in version 0.1.0.15 - 2005-09-23 o Bugfixes on 0.1.0.x: - Reject ports 465 and 587 (spam targets) in default exit policy. - Don't crash when we don't have any spare file descriptors and we try to spawn a dns or cpu worker. - Get rid of IgnoreVersion undocumented config option, and make us only warn, never exit, when we're running an obsolete version. - Don't try to print a null string when your server finds itself to be unreachable and the Address config option is empty. - Make the numbers in read-history and write-history into uint64s, so they don't overflow and publish negatives in the descriptor. - Fix a minor memory leak in smartlist_string_remove(). - We were only allowing ourselves to upload a server descriptor at most every 20 minutes, even if it changed earlier than that. - Clean up log entries that pointed to old URLs. Changes in version 0.1.1.7-alpha - 2005-09-14 o Fixes on 0.1.1.6-alpha: - Exit servers were crashing when people asked them to make a connection to an address not in their exit policy. - Looking up a non-existent stream for a v1 control connection would cause a segfault. - Fix a seg fault if we ask a dirserver for a descriptor by fingerprint but he doesn't know about him. - SETCONF was appending items to linelists, not clearing them. - SETCONF SocksBindAddress killed Tor if it fails to bind. Now back out and refuse the setconf if it would fail. - Downgrade the dirserver log messages when whining about unreachability. o New features: - Add Peter Palfrader's check-tor script to tor/contrib/ It lets you easily check whether a given server (referenced by nickname) is reachable by you. - Numerous changes to move towards client-side v2 directories. Not enabled yet. o Fixes on 0.1.0.x: - If the user gave tor an odd number of command-line arguments, we were silently ignoring the last one. Now we complain and fail. [This wins the oldest-bug prize -- this bug has been present since November 2002, as released in Tor 0.0.0.] - Do not use unaligned memory access on alpha, mips, or mipsel. It *works*, but is very slow, so we treat them as if it doesn't. - Retry directory requests if we fail to get an answer we like from a given dirserver (we were retrying before, but only if we fail to connect). - When writing the RecommendedVersions line, sort them first. - When the client asked for a rendezvous port that the hidden service didn't want to provide, we were sending an IP address back along with the end cell. Fortunately, it was zero. But stop that anyway. - Correct "your server is reachable" log entries to indicate that it was self-testing that told us so. Changes in version 0.1.1.6-alpha - 2005-09-09 o Fixes on 0.1.1.5-alpha: - We broke fascistfirewall in 0.1.1.5-alpha. Oops. - Fix segfault in unit tests in 0.1.1.5-alpha. Oops. - Fix bug with tor_memmem finding a match at the end of the string. - Make unit tests run without segfaulting. - Resolve some solaris x86 compile warnings. - Handle duplicate lines in approved-routers files without warning. - Fix bug where as soon as a server refused any requests due to his exit policy (e.g. when we ask for localhost and he tells us that's 127.0.0.1 and he won't do it), we decided he wasn't obeying his exit policy using him for any exits. - Only do openssl hardware accelerator stuff if openssl version is at least 0.9.7. o New controller features/fixes: - Add a "RESETCONF" command so you can set config options like AllowUnverifiedNodes and LongLivedPorts to "". Also, if you give a config option in the torrc with no value, then it clears it entirely (rather than setting it to its default). - Add a "GETINFO config-file" to tell us where torrc is. - Avoid sending blank lines when GETINFO replies should be empty. - Add a QUIT command for the controller (for using it manually). - Fix a bug in SAVECONF that was adding default dirservers and other redundant entries to the torrc file. o Start on the new directory design: - Generate, publish, cache, serve new network-status format. - Publish individual descriptors (by fingerprint, by "all", and by "tell me yours"). - Publish client and server recommended versions separately. - Allow tor_gzip_uncompress() to handle multiple concatenated compressed strings. Serve compressed groups of router descriptors. The compression logic here could be more memory-efficient. - Distinguish v1 authorities (all currently trusted directories) from v2 authorities (all trusted directories). - Change DirServers config line to note which dirs are v1 authorities. - Add configuration option "V1AuthoritativeDirectory 1" which moria1, moria2, and tor26 should set. - Remove option when getting directory cache to see whether they support running-routers; they all do now. Replace it with one to see whether caches support v2 stuff. o New features: - Dirservers now do their own external reachability testing of each Tor server, and only list them as running if they've been found to be reachable. We also send back warnings to the server's logs if it uploads a descriptor that we already believe is unreachable. - Implement exit enclaves: if we know an IP address for the destination, and there's a running Tor server at that address which allows exit to the destination, then extend the circuit to that exit first. This provides end-to-end encryption and end-to-end authentication. Also, if the user wants a .exit address or enclave, use 4 hops rather than 3, and cannibalize a general circ for it if you can. - Permit transitioning from ORPort=0 to ORPort!=0, and back, from the controller. Also, rotate dns and cpu workers if the controller changes options that will affect them; and initialize the dns worker cache tree whether or not we start out as a server. - Only upload a new server descriptor when options change, 18 hours have passed, uptime is reset, or bandwidth changes a lot. - Check [X-]Forwarded-For headers in HTTP requests when generating log messages. This lets people run dirservers (and caches) behind Apache but still know which IP addresses are causing warnings. o Config option changes: - Replace (Fascist)Firewall* config options with a new ReachableAddresses option that understands address policies. For example, "ReachableAddresses *:80,*:443" - Get rid of IgnoreVersion undocumented config option, and make us only warn, never exit, when we're running an obsolete version. - Make MonthlyAccountingStart config option truly obsolete now. o Fixes on 0.1.0.x: - Reject ports 465 and 587 in the default exit policy, since people have started using them for spam too. - It turns out we couldn't bootstrap a network since we added reachability detection in 0.1.0.1-rc. Good thing the Tor network has never gone down. Add an AssumeReachable config option to let servers and dirservers bootstrap. When we're trying to build a high-uptime or high-bandwidth circuit but there aren't enough suitable servers, try being less picky rather than simply failing. - Our logic to decide if the OR we connected to was the right guy was brittle and maybe open to a mitm for unverified routers. - We weren't cannibalizing circuits correctly for CIRCUIT_PURPOSE_C_ESTABLISH_REND and CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, so we were being forced to build those from scratch. This should make hidden services faster. - Predict required circuits better, with an eye toward making hidden services faster on the service end. - Retry streams if the exit node sends back a 'misc' failure. This should result in fewer random failures. Also, after failing from resolve failed or misc, reset the num failures, so we give it a fair shake next time we try. - Clean up the rendezvous warn log msgs, and downgrade some to info. - Reduce severity on logs about dns worker spawning and culling. - When we're shutting down and we do something like try to post a server descriptor or rendezvous descriptor, don't complain that we seem to be unreachable. Of course we are, we're shutting down. - Add TTLs to RESOLVED, CONNECTED, and END_REASON_EXITPOLICY cells. We don't use them yet, but maybe one day our DNS resolver will be able to discover them. - Make ContactInfo mandatory for authoritative directory servers. - Require server descriptors to list IPv4 addresses -- hostnames are no longer allowed. This also fixes some potential security problems with people providing hostnames as their address and then preferentially resolving them to partition users. - Change log line for unreachability to explicitly suggest /etc/hosts as the culprit. Also make it clearer what IP address and ports we're testing for reachability. - Put quotes around user-supplied strings when logging so users are more likely to realize if they add bad characters (like quotes) to the torrc. - Let auth dir servers start without specifying an Address config option. - Make unit tests (and other invocations that aren't the real Tor) run without launching listeners, creating subdirectories, and so on. Changes in version 0.1.1.5-alpha - 2005-08-08 o Bugfixes included in 0.1.0.14. o Bugfixes on 0.1.0.x: - If you write "HiddenServicePort 6667 127.0.0.1 6668" in your torrc rather than "HiddenServicePort 6667 127.0.0.1:6668", it would silently using ignore the 6668. Changes in version 0.1.0.14 - 2005-08-08 o Bugfixes on 0.1.0.x: - Fix the other half of the bug with crypto handshakes (CVE-2005-2643). - Fix an assert trigger if you send a 'signal term' via the controller when it's listening for 'event info' messages. Changes in version 0.1.1.4-alpha - 2005-08-04 o Bugfixes included in 0.1.0.13. o Features: - Improve tor_gettimeofday() granularity on windows. - Make clients regenerate their keys when their IP address changes. - Implement some more GETINFO goodness: expose helper nodes, config options, getinfo keys. Changes in version 0.1.0.13 - 2005-08-04 o Bugfixes on 0.1.0.x: - Fix a critical bug in the security of our crypto handshakes. - Fix a size_t underflow in smartlist_join_strings2() that made it do bad things when you hand it an empty smartlist. - Fix Windows installer to ship Tor license (thanks to Aphex for pointing out this oversight) and put a link to the doc directory in the start menu. - Explicitly set no-unaligned-access for sparc: it turns out the new gcc's let you compile broken code, but that doesn't make it not-broken. Changes in version 0.1.1.3-alpha - 2005-07-23 o Bugfixes on 0.1.1.2-alpha: - Fix a bug in handling the controller's "post descriptor" function. - Fix several bugs in handling the controller's "extend circuit" function. - Fix a bug in handling the controller's "stream status" event. - Fix an assert failure if we have a controller listening for circuit events and we go offline. - Re-allow hidden service descriptors to publish 0 intro points. - Fix a crash when generating your hidden service descriptor if you don't have enough intro points already. o New features on 0.1.1.2-alpha: - New controller function "getinfo accounting", to ask how many bytes we've used in this time period. - Experimental support for helper nodes: a lot of the risk from a small static adversary comes because users pick new random nodes every time they rebuild a circuit. Now users will try to stick to the same small set of entry nodes if they can. Not enabled by default yet. o Bugfixes on 0.1.0.12: - If you're an auth dir server, always publish your dirport, even if you haven't yet found yourself to be reachable. - Fix a size_t underflow in smartlist_join_strings2() that made it do bad things when you hand it an empty smartlist. Changes in version 0.1.0.12 - 2005-07-18 o New directory servers: - tor26 has changed IP address. o Bugfixes on 0.1.0.x: - Fix a possible double-free in tor_gzip_uncompress(). - When --disable-threads is set, do not search for or link against pthreads libraries. - Don't trigger an assert if an authoritative directory server claims its dirport is 0. - Fix bug with removing Tor as an NT service: some people were getting "The service did not return an error." Thanks to Matt Edman for the fix. Changes in version 0.1.1.2-alpha - 2005-07-15 o New directory servers: - tor26 has changed IP address. o Bugfixes on 0.1.0.x, crashes/leaks: - Port the servers-not-obeying-their-exit-policies fix from 0.1.0.11. - Fix an fd leak in start_daemon(). - On Windows, you can't always reopen a port right after you've closed it. So change retry_listeners() to only close and re-open ports that have changed. - Fix a possible double-free in tor_gzip_uncompress(). o Bugfixes on 0.1.0.x, usability: - When tor_socketpair() fails in Windows, give a reasonable Windows-style errno back. - Let people type "tor --install" as well as "tor -install" when they want to make it an NT service. - NT service patch from Matt Edman to improve error messages. - When the controller asks for a config option with an abbreviated name, give the full name in our response. - Correct the man page entry on TrackHostExitsExpire. - Looks like we were never delivering deflated (i.e. compressed) running-routers lists, even when asked. Oops. - When --disable-threads is set, do not search for or link against pthreads libraries. o Bugfixes on 0.1.1.x: - Fix a seg fault with autodetecting which controller version is being used. o Features: - New hidden service descriptor format: put a version in it, and let people specify introduction/rendezvous points that aren't in "the directory" (which is subjective anyway). - Allow the DEBUG controller event to work again. Mark certain log entries as "don't tell this to controllers", so we avoid cycles. Changes in version 0.1.0.11 - 2005-06-30 o Bugfixes on 0.1.0.x: - Fix major security bug: servers were disregarding their exit policies if clients behaved unexpectedly. - Make OS X init script check for missing argument, so we don't confuse users who invoke it incorrectly. - Fix a seg fault in "tor --hash-password foo". - The MAPADDRESS control command was broken. Changes in version 0.1.1.1-alpha - 2005-06-29 o Bugfixes: - Make OS X init script check for missing argument, so we don't confuse users who invoke it incorrectly. - Fix a seg fault in "tor --hash-password foo". - Fix a possible way to DoS dirservers. - When we complain that your exit policy implicitly allows local or private address spaces, name them explicitly so operators can fix it. - Make the log message less scary when all the dirservers are temporarily unreachable. - We were printing the number of idle dns workers incorrectly when culling them. o Features: - Revised controller protocol (version 1) that uses ascii rather than binary. Add supporting libraries in python and java so you can use the controller from your applications without caring how our protocol works. - Spiffy new support for crypto hardware accelerators. Can somebody test this? Changes in version 0.0.9.10 - 2005-06-16 o Bugfixes on 0.0.9.x (backported from 0.1.0.10): - Refuse relay cells that claim to have a length larger than the maximum allowed. This prevents a potential attack that could read arbitrary memory (e.g. keys) from an exit server's process (CVE-2005-2050). Changes in version 0.1.0.10 - 2005-06-14 o Allow a few EINVALs from libevent before dying. Warn on kqueue with libevent before 1.1a. Changes in version 0.1.0.9-rc - 2005-06-09 o Bugfixes: - Reset buf->highwater every time buf_shrink() is called, not just on a successful shrink. This was causing significant memory bloat. - Fix buffer overflow when checking hashed passwords. - Security fix: if seeding the RNG on Win32 fails, quit. - Allow seeding the RNG on Win32 even when you're not running as Administrator. - Disable threading on Solaris too. Something is wonky with it, cpuworkers, and reentrant libs. - Reenable the part of the code that tries to flush as soon as an OR outbuf has a full TLS record available. Perhaps this will make OR outbufs not grow as huge except in rare cases, thus saving lots of CPU time plus memory. - Reject malformed .onion addresses rather then passing them on as normal web requests. - Adapt patch from Adam Langley: fix possible memory leak in tor_lookup_hostname(). - Initialize libevent later in the startup process, so the logs are already established by the time we start logging libevent warns. - Use correct errno on win32 if libevent fails. - Check and warn about known-bad/slow libevent versions. - Pay more attention to the ClientOnly config option. - Have torctl.in/tor.sh.in check for location of su binary (needed on FreeBSD) - Correct/add man page entries for LongLivedPorts, ExitPolicy, KeepalivePeriod, ClientOnly, NoPublish, HttpProxy, HttpsProxy, HttpProxyAuthenticator - Stop warning about sigpipes in the logs. We're going to pretend that getting these occassionally is normal and fine. - Resolve OS X installer bugs: stop claiming to be 0.0.9.2 in certain installer screens; and don't put stuff into StartupItems unless the user asks you to. - Require servers that use the default dirservers to have public IP addresses. We have too many servers that are configured with private IPs and their admins never notice the log entries complaining that their descriptors are being rejected. - Add OSX uninstall instructions. An actual uninstall script will come later. Changes in version 0.1.0.8-rc - 2005-05-23 o Bugfixes: - It turns out that kqueue on OS X 10.3.9 was causing kernel panics. Disable kqueue on all OS X Tors. - Fix RPM: remove duplicate line accidentally added to the rpm spec file. - Disable threads on openbsd too, since its gethostaddr is not reentrant either. - Tolerate libevent 0.8 since it still works, even though it's ancient. - Enable building on Red Hat 9.0 again. - Allow the middle hop of the testing circuit to be running any version, now that most of them have the bugfix to let them connect to unknown servers. This will allow reachability testing to work even when 0.0.9.7-0.0.9.9 become obsolete. - Handle relay cells with rh.length too large. This prevents a potential attack that could read arbitrary memory (maybe even keys) from the exit server's process. - We screwed up the dirport reachability testing when we don't yet have a cached version of the directory. Hopefully now fixed. - Clean up router_load_single_router() (used by the controller), so it doesn't seg fault on error. - Fix a minor memory leak when somebody establishes an introduction point at your Tor server. - If a socks connection ends because read fails, don't warn that you're not sending a socks reply back. o Features: - Add HttpProxyAuthenticator config option too, that works like the HttpsProxyAuthenticator config option. - Encode hashed controller passwords in hex instead of base64, to make it easier to write controllers. Changes in version 0.1.0.7-rc - 2005-05-17 o Bugfixes: - Fix a bug in the OS X package installer that prevented it from installing on Tiger. - Fix a script bug in the OS X package installer that made it complain during installation. - Find libevent even if it's hiding in /usr/local/ and your CFLAGS and LDFLAGS don't tell you to look there. - Be able to link with libevent as a shared library (the default after 1.0d), even if it's hiding in /usr/local/lib and even if you haven't added /usr/local/lib to your /etc/ld.so.conf, assuming you're running gcc. Otherwise fail and give a useful error message. - Fix a bug in the RPM packager: set home directory for _tor to something more reasonable when first installing. - Free a minor amount of memory that is still reachable on exit. Changes in version 0.1.0.6-rc - 2005-05-14 o Bugfixes: - Implement --disable-threads configure option. Disable threads on netbsd by default, because it appears to have no reentrant resolver functions. - Apple's OS X 10.4.0 ships with a broken kqueue. The new libevent release (1.1) detects and disables kqueue if it's broken. - Append default exit policy before checking for implicit internal addresses. Now we don't log a bunch of complaints on startup when using the default exit policy. - Some people were putting "Address " in their torrc, and they had a buggy resolver that resolved " " to 0.0.0.0. Oops. - If DataDir is ~/.tor, and that expands to /.tor, then default to LOCALSTATEDIR/tor instead. - Fix fragmented-message bug in TorControl.py. - Resolve a minor bug which would prevent unreachable dirports from getting suppressed in the published descriptor. - When the controller gave us a new descriptor, we weren't resolving it immediately, so Tor would think its address was 0.0.0.0 until we fetched a new directory. - Fix an uppercase/lowercase case error in suppressing a bogus libevent warning on some Linuxes. o Features: - Begin scrubbing sensitive strings from logs by default. Turn off the config option SafeLogging if you need to do debugging. - Switch to a new buffer management algorithm, which tries to avoid reallocing and copying quite as much. In first tests it looks like it uses *more* memory on average, but less cpu. - First cut at support for "create-fast" cells. Clients can use these when extending to their first hop, since the TLS already provides forward secrecy and authentication. Not enabled on clients yet. - When dirservers refuse a router descriptor, we now log its contactinfo, platform, and the poster's IP address. - Call tor_free_all instead of connections_free_all after forking, to save memory on systems that need to fork. - Whine at you if you're a server and you don't set your contactinfo. - Implement --verify-config command-line option to check if your torrc is valid without actually launching Tor. - Rewrite address "serifos.exit" to "localhost.serifos.exit" rather than just rejecting it. Changes in version 0.1.0.5-rc - 2005-04-27 o Bugfixes: - Stop trying to print a null pointer if an OR conn fails because we didn't like its cert. o Features: - Switch our internal buffers implementation to use a ring buffer, to hopefully improve performance for fast servers a lot. - Add HttpsProxyAuthenticator support (basic auth only), based on patch from Adam Langley. - Bump the default BandwidthRate from 1 MB to 2 MB, to accommodate the fast servers that have been joining lately. - Give hidden service accesses extra time on the first attempt, since 60 seconds is often only barely enough. This might improve robustness more. - Improve performance for dirservers: stop re-parsing the whole directory every time you regenerate it. - Add more debugging info to help us find the weird dns freebsd pthreads bug; cleaner debug messages to help track future issues. Changes in version 0.0.9.9 - 2005-04-23 o Bugfixes on 0.0.9.x: - If unofficial Tor clients connect and send weird TLS certs, our Tor server triggers an assert. This release contains a minimal backport from the broader fix that we put into 0.1.0.4-rc. Changes in version 0.1.0.4-rc - 2005-04-23 o Bugfixes: - If unofficial Tor clients connect and send weird TLS certs, our Tor server triggers an assert. Stop asserting, and start handling TLS errors better in other situations too. - When the controller asks us to tell it about all the debug-level logs, it turns out we were generating debug-level logs while telling it about them, which turns into a bad loop. Now keep track of whether you're sending a debug log to the controller, and don't log when you are. - Fix the "postdescriptor" feature of the controller interface: on non-complete success, only say "done" once. o Features: - Clients are now willing to load balance over up to 2mB, not 1mB, of advertised bandwidth capacity. - Add a NoPublish config option, so you can be a server (e.g. for testing running Tor servers in other Tor networks) without publishing your descriptor to the primary dirservers. Changes in version 0.1.0.3-rc - 2005-04-08 o Improvements on 0.1.0.2-rc: - Client now retries when streams end early for 'hibernating' or 'resource limit' reasons, rather than failing them. - More automated handling for dirserver operators: - Automatically approve nodes running 0.1.0.2-rc or later, now that the the reachability detection stuff is working. - Now we allow two unverified servers with the same nickname but different keys. But if a nickname is verified, only that nickname+key are allowed. - If you're an authdirserver connecting to an address:port, and it's not the OR you were expecting, forget about that descriptor. If he *was* the one you were expecting, then forget about all other descriptors for that address:port. - Allow servers to publish descriptors from 12 hours in the future. Corollary: only whine about clock skew from the dirserver if he's a trusted dirserver (since now even verified servers could have quite wrong clocks). - Adjust maximum skew and age for rendezvous descriptors: let skew be 48 hours rather than 90 minutes. - Efficiency improvements: - Keep a big splay tree of (circid,orconn)->circuit mappings to make it much faster to look up a circuit for each relay cell. - Remove most calls to assert_all_pending_dns_resolves_ok(), since they're eating our cpu on exit nodes. - Stop wasting time doing a case insensitive comparison for every dns name every time we do any lookup. Canonicalize the names to lowercase and be done with it. - Start sending 'truncated' cells back rather than destroy cells, if the circuit closes in front of you. This means we won't have to abandon partially built circuits. - Only warn once per nickname from add_nickname_list_to_smartlist per failure, so an entrynode or exitnode choice that's down won't yell so much. - Put a note in the torrc about abuse potential with the default exit policy. - Revise control spec and implementation to allow all log messages to be sent to controller with their severities intact (suggested by Matt Edman). Update TorControl to handle new log event types. - Provide better explanation messages when controller's POSTDESCRIPTOR fails. - Stop putting nodename in the Platform string in server descriptors. It doesn't actually help, and it is confusing/upsetting some people. o Bugfixes on 0.1.0.2-rc: - We were printing the host mask wrong in exit policies in server descriptors. This isn't a critical bug though, since we were still obeying the exit policy internally. - Fix Tor when compiled with libevent but without pthreads: move connection_unregister() from _connection_free() to connection_free(). - Fix an assert trigger (already fixed in 0.0.9.x): when we have the rare mysterious case of accepting a conn on 0.0.0.0:0, then when we look through the connection array, we'll find any of the cpu/dnsworkers. This is no good. o Bugfixes on 0.0.9.8: - Fix possible bug on threading platforms (e.g. win32) which was leaking a file descriptor whenever a cpuworker or dnsworker died. - When using preferred entry or exit nodes, ignore whether the circuit wants uptime or capacity. They asked for the nodes, they get the nodes. - chdir() to your datadirectory at the *end* of the daemonize process, not the beginning. This was a problem because the first time you run tor, if your datadir isn't there, and you have runasdaemon set to 1, it will try to chdir to it before it tries to create it. Oops. - Handle changed router status correctly when dirserver reloads fingerprint file. We used to be dropping all unverified descriptors right then. The bug was hidden because we would immediately fetch a directory from another dirserver, which would include the descriptors we just dropped. - When we're connecting to an OR and he's got a different nickname/key than we were expecting, only complain loudly if we're an OP or a dirserver. Complaining loudly to the OR admins just confuses them. - Tie MAX_DIR_SIZE to MAX_BUF_SIZE, so now directory sizes won't get artificially capped at 500kB. Changes in version 0.0.9.8 - 2005-04-07 o Bugfixes on 0.0.9.x: - We have a bug that I haven't found yet. Sometimes, very rarely, cpuworkers get stuck in the 'busy' state, even though the cpuworker thinks of itself as idle. This meant that no new circuits ever got established. Here's a workaround to kill any cpuworker that's been busy for more than 100 seconds. Changes in version 0.1.0.2-rc - 2005-04-01 o Bugfixes on 0.1.0.1-rc: - Fixes on reachability detection: - Don't check for reachability while hibernating. - If ORPort is reachable but DirPort isn't, still publish the descriptor, but zero out DirPort until it's found reachable. - When building testing circs for ORPort testing, use only high-bandwidth nodes, so fewer circuits fail. - Complain about unreachable ORPort separately from unreachable DirPort, so the user knows what's going on. - Make sure we only conclude ORPort reachability if we didn't initiate the conn. Otherwise we could falsely conclude that we're reachable just because we connected to the guy earlier and he used that same pipe to extend to us. - Authdirservers shouldn't do ORPort reachability detection, since they're in clique mode, so it will be rare to find a server not already connected to them. - When building testing circuits, always pick middle hops running Tor 0.0.9.7, so we avoid the "can't extend to unknown routers" bug. (This is a kludge; it will go away when 0.0.9.x becomes obsolete.) - When we decide we're reachable, actually publish our descriptor right then. - Fix bug in redirectstream in the controller. - Fix the state descriptor strings so logs don't claim edge streams are in a different state than they actually are. - Use recent libevent features when possible (this only really affects win32 and osx right now, because the new libevent with these features hasn't been released yet). Add code to suppress spurious libevent log msgs. - Prevent possible segfault in connection_close_unattached_ap(). - Fix newlines on torrc in win32. - Improve error msgs when tor-resolve fails. o Improvements on 0.0.9.x: - New experimental script tor/contrib/ExerciseServer.py (needs more work) that uses the controller interface to build circuits and fetch pages over them. This will help us bootstrap servers that have lots of capacity but haven't noticed it yet. - New experimental script tor/contrib/PathDemo.py (needs more work) that uses the controller interface to let you choose whole paths via addresses like "...path" - When we've connected to an OR and handshaked but didn't like the result, we were closing the conn without sending destroy cells back for pending circuits. Now send those destroys. Changes in version 0.0.9.7 - 2005-04-01 o Bugfixes on 0.0.9.x: - Fix another race crash bug (thanks to Glenn Fink for reporting). - Compare identity to identity, not to nickname, when extending to a router not already in the directory. This was preventing us from extending to unknown routers. Oops. - Make sure to create OS X Tor user in <500 range, so we aren't creating actual system users. - Note where connection-that-hasn't-sent-end was marked, and fix a few really loud instances of this harmless bug (it's fixed more in 0.1.0.x). Changes in version 0.1.0.1-rc - 2005-03-28 o New features: - Add reachability testing. Your Tor server will automatically try to see if its ORPort and DirPort are reachable from the outside, and it won't upload its descriptor until it decides they are. - Handle unavailable hidden services better. Handle slow or busy hidden services better. - Add support for CONNECTing through https proxies, with "HttpsProxy" config option. - New exit policy: accept most low-numbered ports, rather than rejecting most low-numbered ports. - More Tor controller support (still experimental). See http://tor.eff.org/doc/control-spec.txt for all the new features, including signals to emulate unix signals from any platform; redirectstream; extendcircuit; mapaddress; getinfo; postdescriptor; closestream; closecircuit; etc. - Make nt services work and start on startup on win32 (based on patch by Matt Edman). - Add a new AddressMap config directive to rewrite incoming socks addresses. This lets you, for example, declare an implicit required exit node for certain sites. - Add a new TrackHostExits config directive to trigger addressmaps for certain incoming socks addresses -- for sites that break when your exit keeps changing (based on patch by Mike Perry). - Redo the client-side dns cache so it's just an addressmap too. - Notice when our IP changes, and reset stats/uptime/reachability. - When an application is using socks5, give him the whole variety of potential socks5 responses (connect refused, host unreachable, etc), rather than just "success" or "failure". - A more sane version numbering system. See http://tor.eff.org/cvs/tor/doc/version-spec.txt for details. - New contributed script "exitlist": a simple python script to parse directories and find Tor nodes that exit to listed addresses/ports. - New contributed script "privoxy-tor-toggle" to toggle whether Privoxy uses Tor. Seems to be configured for Debian by default. - Report HTTP reasons to client when getting a response from directory servers -- so you can actually know what went wrong. - New config option MaxAdvertisedBandwidth which lets you advertise a low bandwidthrate (to not attract as many circuits) while still allowing a higher bandwidthrate in reality. o Robustness/stability fixes: - Make Tor use Niels Provos's libevent instead of its current poll-but-sometimes-select mess. This will let us use faster async cores (like epoll, kpoll, and /dev/poll), and hopefully work better on Windows too. - pthread support now too. This was forced because when we forked, we ended up wasting a lot of duplicate ram over time. Also switch to foo_r versions of some library calls to allow reentry and threadsafeness. - Better handling for heterogeneous / unreliable nodes: - Annotate circuits w/ whether they aim to contain high uptime nodes and/or high capacity nodes. When building circuits, choose appropriate nodes. - This means that every single node in an intro rend circuit, not just the last one, will have a minimum uptime. - New config option LongLivedPorts to indicate application streams that will want high uptime circuits. - Servers reset uptime when a dir fetch entirely fails. This hopefully reflects stability of the server's network connectivity. - If somebody starts his tor server in Jan 2004 and then fixes his clock, don't make his published uptime be a year. - Reset published uptime when you wake up from hibernation. - Introduce a notion of 'internal' circs, which are chosen without regard to the exit policy of the last hop. Intro and rendezvous circs must be internal circs, to avoid leaking information. Resolve and connect streams can use internal circs if they want. - New circuit pooling algorithm: make sure to have enough circs around to satisfy any predicted ports, and also make sure to have 2 internal circs around if we've required internal circs lately (and with high uptime if we've seen that lately too). - Split NewCircuitPeriod option into NewCircuitPeriod (30 secs), which describes how often we retry making new circuits if current ones are dirty, and MaxCircuitDirtiness (10 mins), which describes how long we're willing to make use of an already-dirty circuit. - Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND circ as necessary, if there are any completed ones lying around when we try to launch one. - Make hidden services try to establish a rendezvous for 30 seconds, rather than for n (where n=3) attempts to build a circuit. - Change SHUTDOWN_WAIT_LENGTH from a fixed 30 secs to a config option "ShutdownWaitLength". - Try to be more zealous about calling connection_edge_end when things go bad with edge conns in connection.c. - Revise tor-spec to add more/better stream end reasons. - Revise all calls to connection_edge_end to avoid sending "misc", and to take errno into account where possible. o Bug fixes: - Fix a race condition that can trigger an assert, when we have a pending create cell and an OR connection fails right then. - Fix several double-mark-for-close bugs, e.g. where we were finding a conn for a cell even if that conn is already marked for close. - Make sequence of log messages when starting on win32 with no config file more reasonable. - When choosing an exit node for a new non-internal circ, don't take into account whether it'll be useful for any pending x.onion addresses -- it won't. - Turn addr_policy_compare from a tristate to a quadstate; this should help address our "Ah, you allow 1.2.3.4:80. You are a good choice for google.com" problem. - Make "platform" string in descriptor more accurate for Win32 servers, so it's not just "unknown platform". - Fix an edge case in parsing config options (thanks weasel). If they say "--" on the commandline, it's not an option. - Reject odd-looking addresses at the client (e.g. addresses that contain a colon), rather than having the server drop them because they're malformed. - tor-resolve requests were ignoring .exit if there was a working circuit they could use instead. - REUSEADDR on normal platforms means you can rebind to the port right after somebody else has let it go. But REUSEADDR on win32 means to let you bind to the port _even when somebody else already has it bound_! So, don't do that on Win32. - Change version parsing logic: a version is "obsolete" if it is not recommended and (1) there is a newer recommended version in the same series, or (2) there are no recommended versions in the same series, but there are some recommended versions in a newer series. A version is "new" if it is newer than any recommended version in the same series. - Stop most cases of hanging up on a socks connection without sending the socks reject. o Helpful fixes: - Require BandwidthRate to be at least 20kB/s for servers. - When a dirserver causes you to give a warn, mention which dirserver it was. - New config option DirAllowPrivateAddresses for authdirservers. Now by default they refuse router descriptors that have non-IP or private-IP addresses. - Stop publishing socksport in the directory, since it's not actually meant to be public. For compatibility, publish a 0 there for now. - Change DirFetchPeriod/StatusFetchPeriod to have a special "Be smart" value, that is low for servers and high for clients. - If our clock jumps forward by 100 seconds or more, assume something has gone wrong with our network and abandon all not-yet-used circs. - Warn when exit policy implicitly allows local addresses. - If we get an incredibly skewed timestamp from a dirserver mirror that isn't a verified OR, don't warn -- it's probably him that's wrong. - Since we ship our own Privoxy on OS X, tweak it so it doesn't write cookies to disk and doesn't log each web request to disk. (Thanks to Brett Carrington for pointing this out.) - When a client asks us for a dir mirror and we don't have one, launch an attempt to get a fresh one. - If we're hibernating and we get a SIGINT, exit immediately. - Add --with-dmalloc ./configure option, to track memory leaks. - And try to free all memory on closing, so we can detect what we're leaking. - Cache local dns resolves correctly even when they're .exit addresses. - Give a better warning when some other server advertises an ORPort that is actually an apache running ssl. - Add "opt hibernating 1" to server descriptor to make it clearer whether the server is hibernating. Changes in version 0.0.9.6 - 2005-03-24 o Bugfixes on 0.0.9.x (crashes and asserts): - Add new end stream reasons to maintainance branch. Fix bug where reason (8) could trigger an assert. Prevent bug from recurring. - Apparently win32 stat wants paths to not end with a slash. - Fix assert triggers in assert_cpath_layer_ok(), where we were blowing away the circuit that conn->cpath_layer points to, then checking to see if the circ is well-formed. Backport check to make sure we dont use the cpath on a closed connection. - Prevent circuit_resume_edge_reading_helper() from trying to package inbufs for marked-for-close streams. - Don't crash on hup if your options->address has become unresolvable. - Some systems (like OS X) sometimes accept() a connection and tell you the remote host is 0.0.0.0:0. If this happens, due to some other mis-features, we get confused; so refuse the conn for now. o Bugfixes on 0.0.9.x (other): - Fix harmless but scary "Unrecognized content encoding" warn message. - Add new stream error reason: TORPROTOCOL reason means "you are not speaking a version of Tor I understand; say bye-bye to your stream." - Be willing to cache directories from up to ROUTER_MAX_AGE seconds into the future, now that we are more tolerant of skew. This resolves a bug where a Tor server would refuse to cache a directory because all the directories it gets are too far in the future; yet the Tor server never logs any complaints about clock skew. - Mac packaging magic: make man pages useable, and do not overwrite existing torrc files. - Make OS X log happily to /var/log/tor/tor.log Changes in version 0.0.9.5 - 2005-02-22 o Bugfixes on 0.0.9.x: - Fix an assert race at exit nodes when resolve requests fail. - Stop picking unverified dir mirrors--it only leads to misery. - Patch from Matt Edman to make NT services work better. Service support is still not compiled into the executable by default. - Patch from Dmitri Bely so the Tor service runs better under the win32 SYSTEM account. - Make tor-resolve actually work (?) on Win32. - Fix a sign bug when getrlimit claims to have 4+ billion file descriptors available. - Stop refusing to start when bandwidthburst == bandwidthrate. - When create cells have been on the onion queue more than five seconds, just send back a destroy and take them off the list. Changes in version 0.0.9.4 - 2005-02-03 o Bugfixes on 0.0.9: - Fix an assert bug that took down most of our servers: when a server claims to have 1 GB of bandwidthburst, don't freak out. - Don't crash as badly if we have spawned the max allowed number of dnsworkers, or we're out of file descriptors. - Block more file-sharing ports in the default exit policy. - MaxConn is now automatically set to the hard limit of max file descriptors we're allowed (ulimit -n), minus a few for logs, etc. - Give a clearer message when servers need to raise their ulimit -n when they start running out of file descriptors. - SGI Compatibility patches from Jan Schaumann. - Tolerate a corrupt cached directory better. - When a dirserver hasn't approved your server, list which one. - Go into soft hibernation after 95% of the bandwidth is used, not 99%. This is especially important for daily hibernators who have a small accounting max. Hopefully it will result in fewer cut connections when the hard hibernation starts. - Load-balance better when using servers that claim more than 800kB/s of capacity. - Make NT services work (experimental, only used if compiled in). Changes in version 0.0.9.3 - 2005-01-21 o Bugfixes on 0.0.9: - Backport the cpu use fixes from main branch, so busy servers won't need as much processor time. - Work better when we go offline and then come back, or when we run Tor at boot before the network is up. We do this by optimistically trying to fetch a new directory whenever an application request comes in and we think we're offline -- the human is hopefully a good measure of when the network is back. - Backport some minimal hidserv bugfixes: keep rend circuits open as long as you keep using them; actually publish hidserv descriptors shortly after they change, rather than waiting 20-40 minutes. - Enable Mac startup script by default. - Fix duplicate dns_cancel_pending_resolve reported by Giorgos Pallas. - When you update AllowUnverifiedNodes or FirewallPorts via the controller's setconf feature, we were always appending, never resetting. - When you update HiddenServiceDir via setconf, it was screwing up the order of reading the lines, making it fail. - Do not rewrite a cached directory back to the cache; otherwise we will think it is recent and not fetch a newer one on startup. - Workaround for webservers that lie about Content-Encoding: Tor now tries to autodetect compressed directories and compression itself. This lets us Proxypass dir fetches through apache. Changes in version 0.0.9.2 - 2005-01-04 o Bugfixes on 0.0.9 (crashes and asserts): - Fix an assert on startup when the disk is full and you're logging to a file. - If you do socks4 with an IP of 0.0.0.x but *don't* provide a socks4a style address, then we'd crash. - Fix an assert trigger when the running-routers string we get from a dirserver is broken. - Make worker threads start and run on win32. Now win32 servers may work better. - Bandaid (not actually fix, but now it doesn't crash) an assert where the dns worker dies mysteriously and the main Tor process doesn't remember anything about the address it was resolving. o Bugfixes on 0.0.9 (Win32): - Workaround for brain-damaged __FILE__ handling on MSVC: keep Nick's name out of the warning/assert messages. - Fix a superficial "unhandled error on read" bug on win32. - The win32 installer no longer requires a click-through for our license, since our Free Software license grants rights but does not take any away. - Win32: When connecting to a dirserver fails, try another one immediately. (This was already working for non-win32 Tors.) - Stop trying to parse $HOME on win32 when hunting for default DataDirectory. - Make tor-resolve.c work on win32 by calling network_init(). o Bugfixes on 0.0.9 (other): - Make 0.0.9.x build on Solaris again. - Due to a fencepost error, we were blowing away the \n when reporting confvalue items in the controller. So asking for multiple config values at once couldn't work. - When listing circuits that are pending on an opening OR connection, if we're an OR we were listing circuits that *end* at us as being pending on every listener, dns/cpu worker, etc. Stop that. - Dirservers were failing to create 'running-routers' or 'directory' strings if we had more than some threshold of routers. Fix them so they can handle any number of routers. - Fix a superficial "Duplicate mark for close" bug. - Stop checking for clock skew for OR connections, even for servers. - Fix a fencepost error that was chopping off the last letter of any nickname that is the maximum allowed nickname length. - Update URLs in log messages so they point to the new website. - Fix a potential problem in mangling server private keys while writing to disk (not triggered yet, as far as we know). - Include the licenses for other free software we include in Tor, now that we're shipping binary distributions more regularly. Changes in version 0.0.9.1 - 2004-12-15 o Bugfixes on 0.0.9: - Make hibernation actually work. - Make HashedControlPassword config option work. - When we're reporting event circuit status to a controller, don't use the stream status code. Changes in version 0.0.9 - 2004-12-12 o Cleanups: - Clean up manpage and torrc.sample file. - Clean up severities and text of log warnings. o Mistakes: - Make servers trigger an assert when they enter hibernation. Changes in version 0.0.9rc7 - 2004-12-08 o Bugfixes on 0.0.9rc: - Fix a stack-trashing crash when an exit node begins hibernating. - Avoid looking at unallocated memory while considering which ports we need to build circuits to cover. - Stop a sigpipe: when an 'end' cell races with eof from the app, we shouldn't hold-open-until-flush if the eof arrived first. - Fix a bug with init_cookie_authentication() in the controller. - When recommending new-format log lines, if the upper bound is LOG_ERR, leave it implicit. o Bugfixes on 0.0.8.1: - Fix a whole slew of memory leaks. - Fix isspace() and friends so they still make Solaris happy but also so they don't trigger asserts on win32. - Fix parse_iso_time on platforms without strptime (eg win32). - win32: tolerate extra "readable" events better. - win32: when being multithreaded, leave parent fdarray open. - Make unit tests work on win32. Changes in version 0.0.9rc6 - 2004-12-06 o Bugfixes on 0.0.9pre: - Clean up some more integer underflow opportunities (not exploitable we think). - While hibernating, hup should not regrow our listeners. - Send an end to the streams we close when we hibernate, rather than just chopping them off. - React to eof immediately on non-open edge connections. o Bugfixes on 0.0.8.1: - Calculate timeout for waiting for a connected cell from the time we sent the begin cell, not from the time the stream started. If it took a long time to establish the circuit, we would time out right after sending the begin cell. - Fix router_compare_addr_to_addr_policy: it was not treating a port of * as always matching, so we were picking reject *:* nodes as exit nodes too. Oops. o Features: - New circuit building strategy: keep a list of ports that we've used in the past 6 hours, and always try to have 2 circuits open or on the way that will handle each such port. Seed us with port 80 so web users won't complain that Tor is "slow to start up". - Make kill -USR1 dump more useful stats about circuits. - When warning about retrying or giving up, print the address, so the user knows which one it's talking about. - If you haven't used a clean circuit in an hour, throw it away, just to be on the safe side. (This means after 6 hours a totally unused Tor client will have no circuits open.) Changes in version 0.0.9rc5 - 2004-12-01 o Bugfixes on 0.0.8.1: - Disallow NDEBUG. We don't ever want anybody to turn off debug. - Let resolve conns retry/expire also, rather than sticking around forever. - If we are using select, make sure we stay within FD_SETSIZE. o Bugfixes on 0.0.9pre: - Fix integer underflow in tor_vsnprintf() that may be exploitable, but doesn't seem to be currently; thanks to Ilja van Sprundel for finding it. - If anybody set DirFetchPostPeriod, give them StatusFetchPeriod instead. Impose minima and maxima for all *Period options; impose even tighter maxima for fetching if we are a caching dirserver. Clip rather than rejecting. - Fetch cached running-routers from servers that serve it (that is, authdirservers and servers running 0.0.9rc5-cvs or later.) o Features: - Accept *:706 (silc) in default exit policy. - Implement new versioning format for post 0.1. - Support "foo.nickname.exit" addresses, to let Alice request the address "foo" as viewed by exit node "nickname". Based on a patch by Geoff Goodell. - Make tor --version --version dump the cvs Id of every file. Changes in version 0.0.9rc4 - 2004-11-28 o Bugfixes on 0.0.8.1: - Make windows sockets actually non-blocking (oops), and handle win32 socket errors better. o Bugfixes on 0.0.9rc1: - Actually catch the -USR2 signal. Changes in version 0.0.9rc3 - 2004-11-25 o Bugfixes on 0.0.8.1: - Flush the log file descriptor after we print "Tor opening log file", so we don't see those messages days later. o Bugfixes on 0.0.9rc1: - Make tor-resolve work again. - Avoid infinite loop in tor-resolve if tor hangs up on it. - Fix an assert trigger for clients/servers handling resolves. Changes in version 0.0.9rc2 - 2004-11-24 o Bugfixes on 0.0.9rc1: - I broke socks5 support while fixing the eof bug. - Allow unitless bandwidths and intervals; they default to bytes and seconds. - New servers don't start out hibernating; they are active until they run out of bytes, so they have a better estimate of how long it takes, and so their operators can know they're working. Changes in version 0.0.9rc1 - 2004-11-23 o Bugfixes on 0.0.8.1: - Finally fix a bug that's been plaguing us for a year: With high load, circuit package window was reaching 0. Whenever we got a circuit-level sendme, we were reading a lot on each socket, but only writing out a bit. So we would eventually reach eof. This would be noticed and acted on even when there were still bytes sitting in the inbuf. - When poll() is interrupted, we shouldn't believe the revents values. o Bugfixes on 0.0.9pre6: - Fix hibernate bug that caused pre6 to be broken. - Don't keep rephist info for routers that haven't had activity for 24 hours. (This matters now that clients have keys, since we track them too.) - Never call close_temp_logs while validating log options. - Fix backslash-escaping on tor.sh.in and torctl.in. o Features: - Implement weekly/monthly/daily accounting: now you specify your hibernation properties by AccountingMax N bytes|KB|MB|GB|TB AccountingStart day|week|month [day] HH:MM Defaults to "month 1 0:00". - Let bandwidth and interval config options be specified as 5 bytes, kb, kilobytes, etc; and as seconds, minutes, hours, days, weeks. - kill -USR2 now moves all logs to loglevel debug (kill -HUP to get back to normal.) - If your requested entry or exit node has advertised bandwidth 0, pick it anyway. - Be more greedy about filling up relay cells -- we try reading again once we've processed the stuff we read, in case enough has arrived to fill the last cell completely. - Apply NT service patch from Osamu Fujino. Still needs more work. Changes in version 0.0.9pre6 - 2004-11-15 o Bugfixes on 0.0.8.1: - Fix assert failure on malformed socks4a requests. - Use identity comparison, not nickname comparison, to choose which half of circuit-ID-space each side gets to use. This is needed because sometimes we think of a router as a nickname, and sometimes as a hex ID, and we can't predict what the other side will do. - Catch and ignore SIGXFSZ signals when log files exceed 2GB; our write() call will fail and we handle it there. - Add a FAST_SMARTLIST define to optionally inline smartlist_get and smartlist_len, which are two major profiling offenders. o Bugfixes on 0.0.9pre5: - Fix a bug in read_all that was corrupting config files on windows. - When we're raising the max number of open file descriptors to 'unlimited', don't log that we just raised it to '-1'. - Include event code with events, as required by control-spec.txt. - Don't give a fingerprint when clients do --list-fingerprint: it's misleading, because it will never be the same again. - Stop using strlcpy in tor_strndup, since it was slowing us down a lot. - Remove warn on startup about missing cached-directory file. - Make kill -USR1 work again. - Hibernate if we start tor during the "wait for wakeup-time" phase of an accounting interval. Log our hibernation plans better. - Authoritative dirservers now also cache their directory, so they have it on start-up. o Features: - Fetch running-routers; cache running-routers; compress running-routers; serve compressed running-routers.z - Add NSI installer script contributed by J Doe. - Commit VC6 and VC7 workspace/project files. - Commit a tor.spec for making RPM files, with help from jbash. - Add contrib/torctl.in contributed by Glenn Fink. - Implement the control-spec's SAVECONF command, to write your configuration to torrc. - Get cookie authentication for the controller closer to working. - Include control-spec.txt in the tarball. - When set_conf changes our server descriptor, upload a new copy. But don't upload it too often if there are frequent changes. - Document authentication config in man page, and document signals we catch. - Clean up confusing parts of man page and torrc.sample. - Make expand_filename handle ~ and ~username. - Use autoconf to enable largefile support where necessary. Use ftello where available, since ftell can fail at 2GB. - Distinguish between TOR_TLS_CLOSE and TOR_TLS_ERROR, so we can log more informatively. - Give a slightly more useful output for "tor -h". - Refuse application socks connections to port 0. - Check clock skew for verified servers, but allow unverified servers and clients to have any clock skew. - Break DirFetchPostPeriod into: - DirFetchPeriod for fetching full directory, - StatusFetchPeriod for fetching running-routers, - DirPostPeriod for posting server descriptor, - RendPostPeriod for posting hidden service descriptors. - Make sure the hidden service descriptors are at a random offset from each other, to hinder linkability. Changes in version 0.0.9pre5 - 2004-11-09 o Bugfixes on 0.0.9pre4: - Fix a seg fault in unit tests (doesn't affect main program). - Fix an assert bug where a hidden service provider would fail if the first hop of his rendezvous circuit was down. - Hidden service operators now correctly handle version 1 style INTRODUCE1 cells (nobody generates them still, so not a critical bug). - If do_hup fails, actually notice. - Handle more errnos from accept() without closing the listener. Some OpenBSD machines were closing their listeners because they ran out of file descriptors. - Send resolve cells to exit routers that are running a new enough version of the resolve code to work right. - Better handling of winsock includes on non-MSV win32 compilers. - Some people had wrapped their tor client/server in a script that would restart it whenever it died. This did not play well with our "shut down if your version is obsolete" code. Now people don't fetch a new directory if their local cached version is recent enough. - Make our autogen.sh work on ksh as well as bash. o Major Features: - Hibernation: New config option "AccountingMaxKB" lets you set how many KBytes per month you want to allow your server to consume. Rather than spreading those bytes out evenly over the month, we instead hibernate for some of the month and pop up at a deterministic time, work until the bytes are consumed, then hibernate again. Config option "MonthlyAccountingStart" lets you specify which day of the month your billing cycle starts on. - Control interface: a separate program can now talk to your client/server over a socket, and get/set config options, receive notifications of circuits and streams starting/finishing/dying, bandwidth used, etc. The next step is to get some GUIs working. Let us know if you want to help out. See doc/control-spec.txt . - Ship a contrib/tor-control.py as an example script to interact with the control port. - "tor --hash-password zzyxz" will output a salted password for use in authenticating to the control interface. - New log format in config: "Log minsev[-maxsev] stdout|stderr|syslog" or "Log minsev[-maxsev] file /var/foo" o Minor Features: - DirPolicy config option, to let people reject incoming addresses from their dirserver. - "tor --list-fingerprint" will list your identity key fingerprint and then exit. - Add "pass" target for RedirectExit, to make it easier to break out of a sequence of RedirectExit rules. - Clients now generate a TLS cert too, in preparation for having them act more like real nodes. - Ship src/win32/ in the tarball, so people can use it to build. - Make old win32 fall back to CWD if SHGetSpecialFolderLocation is broken. - New "router-status" line in directory, to better bind each verified nickname to its identity key. - Deprecate unofficial config option abbreviations, and abbreviations not on the command line. - Add a pure-C tor-resolve implementation. - Use getrlimit and friends to ensure we can reach MaxConn (currently 1024) file descriptors. o Code security improvements, inspired by Ilja: - Replace sprintf with snprintf. (I think they were all safe, but hey.) - Replace strcpy/strncpy with strlcpy in more places. - Avoid strcat; use snprintf or strlcat instead. - snprintf wrapper with consistent (though not C99) overflow behavior. Changes in version 0.0.9pre4 - 2004-10-17 o Bugfixes on 0.0.9pre3: - If the server doesn't specify an exit policy, use the real default exit policy, not reject *:*. - Ignore fascistfirewall when uploading/downloading hidden service descriptors, since we go through Tor for those; and when using an HttpProxy, since we assume it can reach them all. - When looking for an authoritative dirserver, use only the ones configured at boot. Don't bother looking in the directory. - The rest of the fix for get_default_conf_file() on older win32. - Make 'Routerfile' config option obsolete. o Features: - New 'MyFamily nick1,...' config option for a server to specify other servers that shouldn't be used in the same circuit with it. Only believed if nick1 also specifies us. - New 'NodeFamily nick1,nick2,...' config option for a client to specify nodes that it doesn't want to use in the same circuit. - New 'Redirectexit pattern address:port' config option for a server to redirect exit connections, e.g. to a local squid. Changes in version 0.0.9pre3 - 2004-10-13 o Bugfixes on 0.0.8.1: - Better torrc example lines for dirbindaddress and orbindaddress. - Improved bounds checking on parsed ints (e.g. config options and the ones we find in directories.) - Better handling of size_t vs int, so we're more robust on 64 bit platforms. - Fix the rest of the bug where a newly started OR would appear as unverified even after we've added his fingerprint and hupped the dirserver. - Fix a bug from 0.0.7: when read() failed on a stream, we would close it without sending back an end. So 'connection refused' would simply be ignored and the user would get no response. o Bugfixes on 0.0.9pre2: - Serving the cached-on-disk directory to people is bad. We now provide no directory until we've fetched a fresh one. - Workaround for bug on windows where cached-directories get crlf corruption. - Make get_default_conf_file() work on older windows too. - If we write a *:* exit policy line in the descriptor, don't write any more exit policy lines. o Features: - Use only 0.0.9pre1 and later servers for resolve cells. - Make the dirservers file obsolete. - Include a dir-signing-key token in directories to tell the parsing entity which key is being used to sign. - Remove the built-in bulky default dirservers string. - New config option "Dirserver %s:%d [fingerprint]", which can be repeated as many times as needed. If no dirservers specified, default to moria1,moria2,tor26. - Make moria2 advertise a dirport of 80, so people behind firewalls will be able to get a directory. - Http proxy support - Dirservers translate requests for http://%s:%d/x to /x - You can specify "HttpProxy %s[:%d]" and all dir fetches will be routed through this host. - Clients ask for /tor/x rather than /x for new enough dirservers. This way we can one day coexist peacefully with apache. - Clients specify a "Host: %s%d" http header, to be compatible with more proxies, and so running squid on an exit node can work. Changes in version 0.0.8.1 - 2004-10-13 o Bugfixes: - Fix a seg fault that can be triggered remotely for Tor clients/servers with an open dirport. - Fix a rare assert trigger, where routerinfos for entries in our cpath would expire while we're building the path. - Fix a bug in OutboundBindAddress so it (hopefully) works. - Fix a rare seg fault for people running hidden services on intermittent connections. - Fix a bug in parsing opt keywords with objects. - Fix a stale pointer assert bug when a stream detaches and reattaches. - Fix a string format vulnerability (probably not exploitable) in reporting stats locally. - Fix an assert trigger: sometimes launching circuits can fail immediately, e.g. because too many circuits have failed recently. - Fix a compile warning on 64 bit platforms. Changes in version 0.0.9pre2 - 2004-10-03 o Bugfixes: - Make fetching a cached directory work for 64-bit platforms too. - Make zlib.h a required header, not an optional header. Changes in version 0.0.9pre1 - 2004-10-01 o Bugfixes: - Stop using separate defaults for no-config-file and empty-config-file. Now you have to explicitly turn off SocksPort, if you don't want it open. - Fix a bug in OutboundBindAddress so it (hopefully) works. - Improve man page to mention more of the 0.0.8 features. - Fix a rare seg fault for people running hidden services on intermittent connections. - Change our file IO stuff (especially wrt OpenSSL) so win32 is happier. - Fix more dns related bugs: send back resolve_failed and end cells more reliably when the resolve fails, rather than closing the circuit and then trying to send the cell. Also attach dummy resolve connections to a circuit *before* calling dns_resolve(), to fix a bug where cached answers would never be sent in RESOLVED cells. - When we run out of disk space, or other log writing error, don't crash. Just stop logging to that log and continue. - We were starting to daemonize before we opened our logs, so if there were any problems opening logs, we would complain to stderr, which wouldn't work, and then mysteriously exit. - Fix a rare bug where sometimes a verified OR would connect to us before he'd uploaded his descriptor, which would cause us to assign conn->nickname as though he's unverified. Now we look through the fingerprint list to see if he's there. - Fix a rare assert trigger, where routerinfos for entries in our cpath would expire while we're building the path. o Features: - Clients can ask dirservers for /dir.z to get a compressed version of the directory. Only works for servers running 0.0.9, of course. - Make clients cache directories and use them to seed their router lists at startup. This means clients have a datadir again. - Configuration infrastructure support for warning on obsolete options. - Respond to content-encoding headers by trying to uncompress as appropriate. - Reply with a deflated directory when a client asks for "dir.z". We could use allow-encodings instead, but allow-encodings isn't specified in HTTP 1.0. - Raise the max dns workers from 50 to 100. - Discourage people from setting their dirfetchpostperiod more often than once per minute. - Protect dirservers from overzealous descriptor uploading -- wait 10 seconds after directory gets dirty, before regenerating. Changes in version 0.0.8 - 2004-08-25 o Port it to SunOS 5.9 / Athena Changes in version 0.0.8rc2 - 2004-08-20 o Make it compile on cygwin again. o When picking unverified routers, skip those with low uptime and/or low bandwidth, depending on what properties you care about. Changes in version 0.0.8rc1 - 2004-08-18 o Changes from 0.0.7.3: - Bugfixes: - Fix assert triggers: if the other side returns an address 0.0.0.0, don't put it into the client dns cache. - If a begin failed due to exit policy, but we believe the IP address should have been allowed, switch that router to exitpolicy reject *:* until we get our next directory. - Features: - Clients choose nodes proportional to advertised bandwidth. - Avoid using nodes with low uptime as introduction points. - Handle servers with dynamic IP addresses: don't replace options->Address with the resolved one at startup, and detect our address right before we make a routerinfo each time. - 'FascistFirewall' option to pick dirservers and ORs on specific ports; plus 'FirewallPorts' config option to tell FascistFirewall which ports are open. (Defaults to 80,443) - Be more aggressive about trying to make circuits when the network has changed (e.g. when you unsuspend your laptop). - Check for time skew on http headers; report date in response to "GET /". - If the entrynode config line has only one node, don't pick it as an exitnode. - Add strict{entry|exit}nodes config options. If set to 1, then we refuse to build circuits that don't include the specified entry or exit nodes. - OutboundBindAddress config option, to bind to a specific IP address for outgoing connect()s. - End truncated log entries (e.g. directories) with "[truncated]". o Patches to 0.0.8preX: - Bugfixes: - Patches to compile and run on win32 again (maybe)? - Fix crash when looking for ~/.torrc with no $HOME set. - Fix a race bug in the unit tests. - Handle verified/unverified name collisions better when new routerinfo's arrive in a directory. - Sometimes routers were getting entered into the stats before we'd assigned their identity_digest. Oops. - Only pick and establish intro points after we've gotten a directory. - Features: - AllowUnverifiedNodes config option to let circuits choose no-name routers in entry,middle,exit,introduction,rendezvous positions. Allow middle and rendezvous positions by default. - Add a man page for tor-resolve. Changes in version 0.0.7.3 - 2004-08-12 o Stop dnsworkers from triggering an assert failure when you ask them to resolve the host "". Changes in version 0.0.8pre3 - 2004-08-09 o Changes from 0.0.7.2: - Allow multiple ORs with same nickname in routerlist -- now when people give us one identity key for a nickname, then later another, we don't constantly complain until the first expires. - Remember used bandwidth (both in and out), and publish 15-minute snapshots for the past day into our descriptor. - You can now fetch $DIRURL/running-routers to get just the running-routers line, not the whole descriptor list. (But clients don't use this yet.) - When people mistakenly use Tor as an http proxy, point them at the tor-doc.html rather than the INSTALL. - Remove our mostly unused -- and broken -- hex_encode() function. Use base16_encode() instead. (Thanks to Timo Lindfors for pointing out this bug.) - Rotate onion keys every 12 hours, not every 2 hours, so we have fewer problems with people using the wrong key. - Change the default exit policy to reject the default edonkey, kazaa, gnutella ports. - Add replace_file() to util.[ch] to handle win32's rename(). o Changes from 0.0.8preX: - Fix two bugs in saving onion keys to disk when rotating, so hopefully we'll get fewer people using old onion keys. - Fix an assert error that was making SocksPolicy not work. - Be willing to expire routers that have an open dirport -- it's just the authoritative dirservers we want to not forget. - Reject tor-resolve requests for .onion addresses early, so we don't build a whole rendezvous circuit and then fail. - When you're warning a server that he's unverified, don't cry wolf unpredictably. - Fix a race condition: don't try to extend onto a connection that's still handshaking. - For servers in clique mode, require the conn to be open before you'll choose it for your path. - Fix some cosmetic bugs about duplicate mark-for-close, lack of end relay cell, etc. - Measure bandwidth capacity over the last 24 hours, not just 12 - Bugfix: authoritative dirservers were making and signing a new directory for each client, rather than reusing the cached one. Changes in version 0.0.8pre2 - 2004-08-04 o Changes from 0.0.7.2: - Security fixes: - Check directory signature _before_ you decide whether you're you're running an obsolete version and should exit. - Check directory signature _before_ you parse the running-routers list to decide who's running or verified. - Bugfixes and features: - Check return value of fclose while writing to disk, so we don't end up with broken files when servers run out of disk space. - Log a warning if the user uses an unsafe socks variant, so people are more likely to learn about privoxy or socat. - Dirservers now include RFC1123-style dates in the HTTP headers, which one day we will use to better detect clock skew. o Changes from 0.0.8pre1: - Make it compile without warnings again on win32. - Log a warning if you're running an unverified server, to let you know you might want to get it verified. - Only pick a default nickname if you plan to be a server. Changes in version 0.0.8pre1 - 2004-07-23 o Bugfixes: - Made our unit tests compile again on OpenBSD 3.5, and tor itself compile again on OpenBSD on a sparc64. - We were neglecting milliseconds when logging on win32, so everything appeared to happen at the beginning of each second. o Protocol changes: - 'Extend' relay cell payloads now include the digest of the intended next hop's identity key. Now we can verify that we're extending to the right router, and also extend to routers we hadn't heard of before. o Features: - Tor nodes can now act as relays (with an advertised ORPort) without being manually verified by the dirserver operators. - Uploaded descriptors of unverified routers are now accepted by the dirservers, and included in the directory. - Verified routers are listed by nickname in the running-routers list; unverified routers are listed as "$". - We now use hash-of-identity-key in most places rather than nickname or addr:port, for improved security/flexibility. - To avoid Sybil attacks, paths still use only verified servers. But now we have a chance to play around with hybrid approaches. - Nodes track bandwidth usage to estimate capacity (not used yet). - ClientOnly option for nodes that never want to become servers. - Directory caching. - "AuthoritativeDir 1" option for the official dirservers. - Now other nodes (clients and servers) will cache the latest directory they've pulled down. - They can enable their DirPort to serve it to others. - Clients will pull down a directory from any node with an open DirPort, and check the signature/timestamp correctly. - Authoritative dirservers now fetch directories from other authdirservers, to stay better synced. - Running-routers list tells who's down also, along with noting if they're verified (listed by nickname) or unverified (listed by hash-of-key). - Allow dirservers to serve running-router list separately. This isn't used yet. - ORs connect-on-demand to other ORs - If you get an extend cell to an OR you're not connected to, connect, handshake, and forward the create cell. - The authoritative dirservers stay connected to everybody, and everybody stays connected to 0.0.7 servers, but otherwise clients/servers expire unused connections after 5 minutes. - When servers get a sigint, they delay 30 seconds (refusing new connections) then exit. A second sigint causes immediate exit. - File and name management: - Look for .torrc if no CONFDIR "torrc" is found. - If no datadir is defined, then choose, make, and secure ~/.tor as datadir. - If torrc not found, exitpolicy reject *:*. - Expands ~/ in filenames to $HOME/ (but doesn't yet expand ~arma). - If no nickname is defined, derive default from hostname. - Rename secret key files, e.g. identity.key -> secret_id_key, to discourage people from mailing their identity key to tor-ops. - Refuse to build a circuit before the directory has arrived -- it won't work anyway, since you won't know the right onion keys to use. - Try other dirservers immediately if the one you try is down. This should tolerate down dirservers better now. - Parse tor version numbers so we can do an is-newer-than check rather than an is-in-the-list check. - New socks command 'resolve', to let us shim gethostbyname() locally. - A 'tor_resolve' script to access the socks resolve functionality. - A new socks-extensions.txt doc file to describe our interpretation and extensions to the socks protocols. - Add a ContactInfo option, which gets published in descriptor. - Publish OR uptime in descriptor (and thus in directory) too. - Write tor version at the top of each log file - New docs in the tarball: - tor-doc.html. - Document that you should proxy your SSL traffic too. Changes in version 0.0.7.2 - 2004-07-07 o A better fix for the 0.0.0.0 problem, that will hopefully eliminate the remaining related assertion failures. Changes in version 0.0.7.1 - 2004-07-04 o When an address resolves to 0.0.0.0, treat it as a failed resolve, since internally we use 0.0.0.0 to signify "not yet resolved". Changes in version 0.0.7 - 2004-06-07 o Updated the man page to reflect the new features. Changes in version 0.0.7rc2 - 2004-06-06 o Changes from 0.0.7rc1: - Make it build on Win32 again. o Changes from 0.0.6.2: - Rotate dnsworkers and cpuworkers on SIGHUP, so they get new config settings too. Changes in version 0.0.7rc1 - 2004-06-02 o Bugfixes: - On sighup, we were adding another log without removing the first one. So log messages would get duplicated n times for n sighups. - Several cases of using a connection after we'd freed it. The problem was that connections that are pending resolve are in both the pending_resolve tree, and also the circuit's resolving_streams list. When you want to remove one, you must remove it from both. - Fix a double-mark-for-close where an end cell arrived for a resolving stream, and then the resolve failed. - Check directory signatures based on name of signer, not on whom we got the directory from. This will let us cache directories more easily. o Features: - Crank up some of our constants to handle more users. Changes in version 0.0.7pre1 - 2004-06-02 o Fixes for crashes and other obnoxious bugs: - Fix an epipe bug: sometimes when directory connections failed to connect, we would give them a chance to flush before closing them. - When we detached from a circuit because of resolvefailed, we would immediately try the same circuit twice more, and then give up on the resolve thinking we'd tried three different exit nodes. - Limit the number of intro circuits we'll attempt to build for a hidden service per 15-minute period. - Check recommended-software string *early*, before actually parsing the directory. Thus we can detect an obsolete version and exit, even if the new directory format doesn't parse. o Fixes for security bugs: - Remember which nodes are dirservers when you startup, and if a random OR enables his dirport, don't automatically assume he's a trusted dirserver. o Other bugfixes: - Directory connections were asking the wrong poll socket to start writing, and not asking themselves to start writing. - When we detached from a circuit because we sent a begin but didn't get a connected, we would use it again the first time; but after that we would correctly switch to a different one. - Stop warning when the first onion decrypt attempt fails; they will sometimes legitimately fail now that we rotate keys. - Override unaligned-access-ok check when $host_cpu is ia64 or arm. Apparently they allow it but the kernel whines. - Dirservers try to reconnect periodically too, in case connections have failed. - Fix some memory leaks in directory servers. - Allow backslash in Win32 filenames. - Made Tor build complain-free on FreeBSD, hopefully without breaking other BSD builds. We'll see. o Features: - Doxygen markup on all functions and global variables. - Make directory functions update routerlist, not replace it. So now directory disagreements are not so critical a problem. - Remove the upper limit on number of descriptors in a dirserver's directory (not that we were anywhere close). - Allow multiple logfiles at different severity ranges. - Allow *BindAddress to specify ":port" rather than setting *Port separately. Allow multiple instances of each BindAddress config option, so you can bind to multiple interfaces if you want. - Allow multiple exit policy lines, which are processed in order. Now we don't need that huge line with all the commas in it. - Enable accept/reject policies on SOCKS connections, so you can bind to 0.0.0.0 but still control who can use your OP. Changes in version 0.0.6.2 - 2004-05-16 o Our integrity-checking digest was checking only the most recent cell, not the previous cells like we'd thought. Thanks to Stefan Mark for finding the flaw! Changes in version 0.0.6.1 - 2004-05-06 o Fix two bugs in our AES counter-mode implementation (this affected onion-level stream encryption, but not TLS-level). It turns out we were doing something much more akin to a 16-character polyalphabetic cipher. Oops. Thanks to Stefan Mark for finding the flaw! o Retire moria3 as a directory server, and add tor26 as a directory server. Changes in version 0.0.6 - 2004-05-02 [version bump only] Changes in version 0.0.6rc4 - 2004-05-01 o Update the built-in dirservers list to use the new directory format o Fix a rare seg fault: if a node offering a hidden service attempts to build a circuit to Alice's rendezvous point and fails before it reaches the last hop, it retries with a different circuit, but then dies. o Handle windows socket errors correctly. Changes in version 0.0.6rc3 - 2004-04-28 o Don't expire non-general excess circuits (if we had enough circuits open, we were expiring rendezvous circuits -- even when they had a stream attached. oops.) o Fetch randomness from /dev/urandom better (not via fopen/fread) o Better debugging for tls errors o Some versions of openssl have an SSL_pending function that erroneously returns bytes when there is a non-application record pending. o Set Content-Type on the directory and hidserv descriptor. o Remove IVs from cipher code, since AES-ctr has none. o Win32 fixes. Tor now compiles on win32 with no warnings/errors. o We were using an array of length zero in a few places. o win32's gethostbyname can't resolve an IP to an IP. o win32's close can't close a socket. Changes in version 0.0.6rc2 - 2004-04-26 o Fix a bug where we were closing tls connections intermittently. It turns out openssl keeps its errors around -- so if an error happens, and you don't ask about it, and then another openssl operation happens and succeeds, and you ask if there was an error, it tells you about the first error. Fun fun. o Fix a bug that's been lurking since 27 may 03 (!) When passing back a destroy cell, we would use the wrong circ id. 'Mostly harmless', but still worth fixing. o Since we don't support truncateds much, don't bother sending them; just close the circ. o check for so we build on NetBSD again (I hope). o don't crash if a conn that sent a begin has suddenly lost its circuit (this was quite rare). Changes in version 0.0.6rc1 - 2004-04-25 o We now rotate link (tls context) keys and onion keys. o CREATE cells now include oaep padding, so you can tell if you decrypted them correctly. o Add bandwidthburst to server descriptor. o Directories now say which dirserver signed them. o Use a tor_assert macro that logs failed assertions too. Changes in version 0.0.6pre5 - 2004-04-18 o changes from 0.0.6pre4: - make tor build on broken freebsd 5.2 installs - fix a failed assert when you try an intro point, get a nack, and try a second one and it works. - when alice uses a port that the hidden service doesn't accept, it now sends back an end cell (denied by exit policy). otherwise alice would just have to wait to time out. - fix another rare bug: when we had tried all the intro points for a hidden service, we fetched the descriptor again, but we left our introcirc thinking it had already sent an intro, so it kept waiting for a response... - bugfix: when you sleep your hidden-service laptop, as soon as it wakes up it tries to upload a service descriptor, but socketpair fails for some reason (localhost not up yet?). now we simply give up on that upload, and we'll try again later. i'd still like to find the bug though. - if an intro circ waiting for an ack dies before getting one, then count it as a nack - we were reusing stale service descriptors and refetching usable ones. oops. Changes in version 0.0.6pre4 - 2004-04-14 o changes from 0.0.6pre3: - when bob fails to connect to the rendezvous point, and his circ didn't fail because of the rendezvous point itself, then he retries a couple of times - we expire introduction and rendezvous circs more thoroughly (sometimes they were hanging around forever) - we expire unattached rendezvous streams that have been around too long (they were sticking around forever). - fix a measly fencepost error that was crashing everybody with a strict glibc. Changes in version 0.0.6pre3 - 2004-04-14 o changes from 0.0.6pre2: - make hup work again - fix some memory leaks for dirservers - allow more skew in rendezvous descriptor timestamps, to help handle people like blanu who don't know what time it is - normal circs are 3 hops, but some rend/intro circs are 4, if the initiator doesn't get to choose the last hop - send acks for introductions, so alice can know whether to try again - bob publishes intro points more correctly o changes from 0.0.5: - fix an assert trigger that's been plaguing us since the days of 0.0.2prexx (thanks weasel!) - retry stream correctly when we fail to connect because of exit-policy-reject (should try another) or can't-resolve-address (also should try another, because dns on random internet servers is flaky). - when we hup a dirserver and we've *removed* a server from the approved-routers list, now we remove that server from the in-memory directories too Changes in version 0.0.6pre2 - 2004-04-08 o We fixed our base32 implementation. Now it works on all architectures. Changes in version 0.0.6pre1 - 2004-04-08 o Features: - Hidden services and rendezvous points are implemented. Go to http://6sxoyfb3h2nvok2d.onion/ for an index of currently available hidden services. (This only works via a socks4a proxy such as Privoxy, and currently it's quite slow.) Changes in version 0.0.5 - 2004-03-30 [version bump only] Changes in version 0.0.5rc3 - 2004-03-29 o Install torrc as torrc.sample -- we no longer clobber your torrc. (Woo!) o Re-enable recommendedversion checking (we broke it in rc2, oops) o Add in a 'notice' log level for things the operator should hear but that aren't warnings Changes in version 0.0.5rc2 - 2004-03-29 o Hold socks connection open until reply is flushed (if possible) o Make exit nodes resolve IPs to IPs immediately, rather than asking the dns farm to do it. o Fix c99 aliasing warnings in rephist.c o Don't include server descriptors that are older than 24 hours in the directory. o Give socks 'reject' replies their whole 15s to attempt to flush, rather than seeing the 60s timeout and assuming the flush had failed. o Clean automake droppings from the cvs repository Changes in version 0.0.5rc1 - 2004-03-28 o Fix mangled-state bug in directory fetching (was causing sigpipes). o Only build circuits after we've fetched the directory: clients were using only the directory servers before they'd fetched a directory. This also means longer startup time; so it goes. o Fix an assert trigger where an OP would fail to handshake, and we'd expect it to have a nickname. o Work around a tsocks bug: do a socks reject when AP connection dies early, else tsocks goes into an infinite loop. Changes in version 0.0.4 - 2004-03-26 o When connecting to a dirserver or OR and the network is down, we would crash. Changes in version 0.0.3 - 2004-03-26 o Warn and fail if server chose a nickname with illegal characters o Port to Solaris and Sparc: - include missing header fcntl.h - have autoconf find -lsocket -lnsl automatically - deal with hardware word alignment - make uname() work (solaris has a different return convention) - switch from using signal() to sigaction() o Preliminary work on reputation system: - Keep statistics on success/fail of connect attempts; they're published by kill -USR1 currently. - Add a RunTesting option to try to learn link state by creating test circuits, even when SocksPort is off. - Remove unused open circuits when there are too many. Changes in version 0.0.2 - 2004-03-19 - Include strlcpy and strlcat for safer string ops - define INADDR_NONE so we compile (but still not run) on solaris Changes in version 0.0.2pre27 - 2004-03-14 o Bugfixes: - Allow internal tor networks (we were rejecting internal IPs, now we allow them if they're set explicitly). - And fix a few endian issues. Changes in version 0.0.2pre26 - 2004-03-14 o New features: - If a stream times out after 15s without a connected cell, don't try that circuit again: try a new one. - Retry streams at most 4 times. Then give up. - When a dirserver gets a descriptor from an unknown router, it logs its fingerprint (so the dirserver operator can choose to accept it even without mail from the server operator). - Inform unapproved servers when we reject their descriptors. - Make tor build on Windows again. It works as a client, who knows about as a server. - Clearer instructions in the torrc for how to set up a server. - Be more efficient about reading fd's when our global token bucket (used for rate limiting) becomes empty. o Bugfixes: - Stop asserting that computers always go forward in time. It's simply not true. - When we sent a cell (e.g. destroy) and then marked an OR connection expired, we might close it before finishing a flush if the other side isn't reading right then. - Don't allow dirservers to start if they haven't defined RecommendedVersions - We were caching transient dns failures. Oops. - Prevent servers from publishing an internal IP as their address. - Address a strcat vulnerability in circuit.c Changes in version 0.0.2pre25 - 2004-03-04 o New features: - Put the OR's IP in its router descriptor, not its fqdn. That way we'll stop being stalled by gethostbyname for nodes with flaky dns, e.g. poblano. o Bugfixes: - If the user typed in an address that didn't resolve, the server crashed. Changes in version 0.0.2pre24 - 2004-03-03 o Bugfixes: - Fix an assertion failure in dns.c, where we were trying to dequeue a pending dns resolve even if it wasn't pending - Fix a spurious socks5 warning about still trying to write after the connection is finished. - Hold certain marked_for_close connections open until they're finished flushing, rather than losing bytes by closing them too early. - Correctly report the reason for ending a stream - Remove some duplicate calls to connection_mark_for_close - Put switch_id and start_daemon earlier in the boot sequence, so it will actually try to chdir() to options.DataDirectory - Make 'make test' exit(1) if a test fails; fix some unit tests - Make tor fail when you use a config option it doesn't know about, rather than warn and continue. - Make --version work - Bugfixes on the rpm spec file and tor.sh, so it's more up to date Changes in version 0.0.2pre23 - 2004-02-29 o New features: - Print a statement when the first circ is finished, so the user knows it's working. - If a relay cell is unrecognized at the end of the circuit, send back a destroy. (So attacks to mutate cells are more clearly thwarted.) - New config option 'excludenodes' to avoid certain nodes for circuits. - When it daemonizes, it chdir's to the DataDirectory rather than "/", so you can collect coredumps there. o Bugfixes: - Fix a bug in tls flushing where sometimes data got wedged and didn't flush until more data got sent. Hopefully this bug was a big factor in the random delays we were seeing. - Make 'connected' cells include the resolved IP, so the client dns cache actually gets populated. - Disallow changing from ORPort=0 to ORPort>0 on hup. - When we time-out on a stream and detach from the circuit, send an end cell down it first. - Only warn about an unknown router (in exitnodes, entrynodes, excludenodes) after we've fetched a directory. Changes in version 0.0.2pre22 - 2004-02-26 o New features: - Servers publish less revealing uname information in descriptors. - More memory tracking and assertions, to crash more usefully when errors happen. - If the default torrc isn't there, just use some default defaults. Plus provide an internal dirservers file if they don't have one. - When the user tries to use Tor as an http proxy, give them an http 501 failure explaining that we're a socks proxy. - Dump a new router.desc on hup, to help confused people who change their exit policies and then wonder why router.desc doesn't reflect it. - Clean up the generic tor.sh init script that we ship with. o Bugfixes: - If the exit stream is pending on the resolve, and a destroy arrives, then the stream wasn't getting removed from the pending list. I think this was the one causing recent server crashes. - Use a more robust poll on OSX 10.3, since their poll is flaky. - When it couldn't resolve any dirservers, it was useless from then on. Now it reloads the RouterFile (or default dirservers) if it has no dirservers. - Move the 'tor' binary back to /usr/local/bin/ -- it turns out many users don't even *have* a /usr/local/sbin/. Changes in version 0.0.2pre21 - 2004-02-18 o New features: - There's a ChangeLog file that actually reflects the changelog. - There's a 'torify' wrapper script, with an accompanying tor-tsocks.conf, that simplifies the process of using tsocks for tor. It even has a man page. - The tor binary gets installed to sbin rather than bin now. - Retry streams where the connected cell hasn't arrived in 15 seconds - Clean up exit policy handling -- get the default out of the torrc, so we can update it without forcing each server operator to fix his/her torrc. - Allow imaps and pop3s in default exit policy o Bugfixes: - Prevent picking middleman nodes as the last node in the circuit Changes in version 0.0.2pre20 - 2004-01-30 o New features: - We now have a deb package, and it's in debian unstable. Go to it, apt-getters. :) - I've split the TotalBandwidth option into BandwidthRate (how many bytes per second you want to allow, long-term) and BandwidthBurst (how many bytes you will allow at once before the cap kicks in). This better token bucket approach lets you, say, set BandwidthRate to 10KB/s and BandwidthBurst to 10MB, allowing good performance while not exceeding your monthly bandwidth quota. - Push out a tls record's worth of data once you've got it, rather than waiting until you've read everything waiting to be read. This may improve performance by pipelining better. We'll see. - Add an AP_CONN_STATE_CONNECTING state, to allow streams to detach from failed circuits (if they haven't been connected yet) and attach to new ones. - Expire old streams that haven't managed to connect. Some day we'll have them reattach to new circuits instead. o Bugfixes: - Fix several memory leaks that were causing servers to become bloated after a while. - Fix a few very rare assert triggers. A few more remain. - Setuid to User _before_ complaining about running as root. Changes in version 0.0.2pre19 - 2004-01-07 o Bugfixes: - Fix deadlock condition in dns farm. We were telling a child to die by closing the parent's file descriptor to him. But newer children were inheriting the open file descriptor from the parent, and since they weren't closing it, the socket never closed, so the child never read eof, so he never knew to exit. Similarly, dns workers were holding open other sockets, leading to all sorts of chaos. - New cleaner daemon() code for forking and backgrounding. - If you log to a file, it now prints an entry at the top of the logfile so you know it's working. - The onionskin challenge length was 30 bytes longer than necessary. - Started to patch up the spec so it's not quite so out of date. Changes in version 0.0.2pre18 - 2004-01-02 o Bugfixes: - Fix endian issues with the 'integrity' field in the relay header. - Fix a potential bug where connections in state AP_CONN_STATE_CIRCUIT_WAIT might unexpectedly ask to write. Changes in version 0.0.2pre17 - 2003-12-30 o Bugfixes: - Made --debuglogfile (or any second log file, actually) work. - Resolved an edge case in get_unique_circ_id_by_conn where a smart adversary could force us into an infinite loop. o Features: - Each onionskin handshake now includes a hash of the computed key, to prove the server's identity and help perfect forward secrecy. - Changed cell size from 256 to 512 bytes (working toward compatibility with MorphMix). - Changed cell length to 2 bytes, and moved it to the relay header. - Implemented end-to-end integrity checking for the payloads of relay cells. - Separated streamid from 'recognized' (otherwise circuits will get messed up when we try to have streams exit from the middle). We use the integrity-checking to confirm that a cell is addressed to this hop. - Randomize the initial circid and streamid values, so an adversary who breaks into a node can't learn how many circuits or streams have been made so far. Changes in version 0.0.2pre16 - 2003-12-14 o Bugfixes: - Fixed a bug that made HUP trigger an assert - Fixed a bug where a circuit that immediately failed wasn't being counted as a failed circuit in counting retries. o Features: - Now we close the circuit when we get a truncated cell: otherwise we're open to an anonymity attack where a bad node in the path truncates the circuit and then we open streams at him. - Add port ranges to exit policies - Add a conservative default exit policy - Warn if you're running tor as root - on HUP, retry OR connections and close/rebind listeners - options.EntryNodes: try these nodes first when picking the first node - options.ExitNodes: if your best choices happen to include any of your preferred exit nodes, you choose among just those preferred exit nodes. - options.ExcludedNodes: nodes that are never picked in path building Changes in version 0.0.2pre15 - 2003-12-03 o Robustness and bugfixes: - Sometimes clients would cache incorrect DNS resolves, which would really screw things up. - An OP that goes offline would slowly leak all its sockets and stop working. - A wide variety of bugfixes in exit node selection, exit policy handling, and processing pending streams when a new circuit is established. - Pick nodes for a path only from those the directory says are up - Choose randomly from all running dirservers, not always the first one - Increase allowed http header size for directory fetch. - Stop writing to stderr (if we're daemonized it will be closed). - Enable -g always, so cores will be more useful to me. - Switch "-lcrypto -lssl" to "-lssl -lcrypto" for broken distributions. o Documentation: - Wrote a man page. It lists commonly used options. o Configuration: - Change default loglevel to warn. - Make PidFile default to null rather than littering in your CWD. - OnionRouter config option is now obsolete. Instead it just checks ORPort>0. - Moved to a single unified torrc file for both clients and servers. Changes in version 0.0.2pre14 - 2003-11-29 o Robustness and bugfixes: - Force the admin to make the DataDirectory himself - to get ownership/permissions right - so clients no longer make a DataDirectory and then never use it - fix bug where a client who was offline for 45 minutes would never pull down a directory again - fix (or at least hide really well) the dns assert bug that was causing server crashes - warnings and improved robustness wrt clockskew for certs - use the native daemon(3) to daemonize, when available - exit if bind() fails - exit if neither socksport nor orport is defined - include our own tor_timegm (Win32 doesn't have its own) - bugfix for win32 with lots of connections - fix minor bias in PRNG - make dirserver more robust to corrupt cached directory o Documentation: - Wrote the design document (woo) o Circuit building and exit policies: - Circuits no longer try to use nodes that the directory has told them are down. - Exit policies now support bitmasks (18.0.0.0/255.0.0.0) and bitcounts (18.0.0.0/8). - Make AP connections standby for a circuit if no suitable circuit exists, rather than failing - Circuits choose exit node based on addr/port, exit policies, and which AP connections are standing by - Bump min pathlen from 2 to 3 - Relay end cells have a payload to describe why the stream ended. - If the stream failed because of exit policy, try again with a new circuit. - Clients have a dns cache to remember resolved addresses. - Notice more quickly when we have no working circuits o Configuration: - APPort is now called SocksPort - SocksBindAddress, ORBindAddress, DirBindAddress let you configure where to bind - RecommendedVersions is now a config variable rather than hardcoded (for dirservers) - Reloads config on HUP - Usage info on -h or --help - If you set User and Group config vars, it'll setu/gid to them. Changes in version 0.0.2pre13 - 2003-10-19 o General stability: - SSL_write no longer fails when it returns WANTWRITE and the number of bytes in the buf has changed by the next SSL_write call. - Fix segfault fetching directory when network is down - Fix a variety of minor memory leaks - Dirservers reload the fingerprints file on HUP, so I don't have to take down the network when I approve a new router - Default server config file has explicit Address line to specify fqdn o Buffers: - Buffers grow and shrink as needed (Cut process size from 20M to 2M) - Make listener connections not ever alloc bufs o Autoconf improvements: - don't clobber an external CFLAGS in ./configure - Make install now works - create var/lib/tor on make install - autocreate a tor.sh initscript to help distribs - autocreate the torrc and sample-server-torrc with correct paths o Log files and Daemonizing now work: - If --DebugLogFile is specified, log to it at -l debug - If --LogFile is specified, use it instead of commandline - If --RunAsDaemon is set, tor forks and backgrounds on startup tor-0.2.4.20/doc/0000755000175000017500000000000012255753765010330 500000000000000tor-0.2.4.20/doc/include.am0000644000175000017500000000542312255745673012215 00000000000000# We use a two-step process to generate documentation from asciidoc files. # # First, we use asciidoc/a2x to process the asciidoc files into .1.in and # .html.in files (see the asciidoc-helper.sh script). These are the same as # the regular .1 and .html files, except that they still have some autoconf # variables set in them. # # Second, we use config.status to turn .1.in files into .1 files and # .html.in files into .html files. # # We do the steps in this order so that we can ship the .*.in files as # part of the source distribution, so that people without asciidoc can # just use the .1 and .html files. regular_mans = doc/tor doc/tor-gencert doc/tor-resolve doc/torify all_mans = $(regular_mans) doc/tor-fw-helper if USE_ASCIIDOC if USE_FW_HELPER nodist_man1_MANS = $(all_mans:=.1) doc_DATA = $(all_mans:=.html) else nodist_man1_MANS = $(regular_mans:=.1) doc_DATA = $(regular_mans:=.html) endif html_in = $(all_mans:=.html.in) man_in = $(all_mans:=.1.in) txt_in = $(all_mans:=.1.txt) else html_in = man_in = txt_in = nodist_man1_MANS = doc_DATA = endif EXTRA_DIST+= doc/HACKING doc/asciidoc-helper.sh \ $(html_in) $(man_in) $(txt_in) \ doc/state-contents.txt docdir = @docdir@ asciidoc_product = $(nodist_man1_MANS) $(doc_DATA) # Generate the html documentation from asciidoc, but don't do # machine-specific replacements yet $(html_in) : $(AM_V_GEN)$(top_srcdir)/doc/asciidoc-helper.sh html @ASCIIDOC@ $(top_srcdir)/$@ # Generate the manpage from asciidoc, but don't do # machine-specific replacements yet $(man_in) : $(AM_V_GEN)$(top_srcdir)/doc/asciidoc-helper.sh man @A2X@ $(top_srcdir)/$@ doc/tor.1.in: doc/tor.1.txt doc/tor-gencert.1.in: doc/tor-gencert.1.txt doc/tor-resolve.1.in: doc/tor-resolve.1.txt doc/torify.1.in: doc/torify.1.txt doc/tor-fw-helper.1.in: doc/tor-fw-helper.1.txt doc/tor.html.in: doc/tor.1.txt doc/tor-gencert.html.in: doc/tor-gencert.1.txt doc/tor-resolve.html.in: doc/tor-resolve.1.txt doc/torify.html.in: doc/torify.1.txt doc/tor-fw-helper.html.in: doc/tor-fw-helper.1.txt # use ../config.status to swap all machine-specific magic strings # in the asciidoc with their replacements. $(asciidoc_product) : $(AM_V_GEN)$(MKDIR_P) $(@D) $(AM_V_at)if test -e $(top_srcdir)/$@.in && ! test -e $@.in ; then \ cp $(top_srcdir)/$@.in $@; \ fi $(AM_V_at)./config.status -q --file=$@; doc/tor.html: doc/tor.html.in doc/tor-gencert.html: doc/tor-gencert.html.in doc/tor-resolve.html: doc/tor-resolve.html.in doc/torify.html: doc/torify.html.in doc/tor-fw-helper.html: doc/tor-fw-helper.html.in doc/tor.1: doc/tor.1.in doc/tor-gencert.1: doc/tor-gencert.1.in doc/tor-resolve.1: doc/tor-resolve.1.in doc/torify.1: doc/torify.1.in doc/tor-fw-helper.1: doc/tor-fw-helper.1.in CLEANFILES+= $(asciidoc_product) config.log DISTCLEANFILES+= $(html_in) $(man_in) tor-0.2.4.20/doc/tor-fw-helper.1.txt0000644000175000017500000000337612166112776013644 00000000000000// Copyright (c) The Tor Project, Inc. // See LICENSE for licensing information // This is an asciidoc file used to generate the manpage/html reference. // Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html :man source: Tor :man manual: Tor Manual tor-fw-helper(1) ================ Jacob Appelbaum NAME ---- tor-fw-helper - Manage upstream firewall/NAT devices SYNOPSIS -------- **tor-fw-helper** [-h|--help] [-T|--test-commandline] [-v|--verbose] [-g|--fetch-public-ip] [-p __external port__:__internal_port__] DESCRIPTION ----------- **tor-fw-helper** currently supports Apple's NAT-PMP protocol and the UPnP standard for TCP port mapping. It is written as the reference implementation of tor-fw-helper-spec.txt and conforms to that loose plugin API. If your network supports either NAT-PMP or UPnP, tor-fw-helper will attempt to automatically map the required TCP ports for Tor's Or and Dir ports. + OPTIONS ------- **-h** or **--help**:: Display help text and exit. **-v** or **--verbose**:: Display verbose output. **-T** or **--test-commandline**:: Display test information and print the test information in tor-fw-helper.log **-g** or **--fetch-public-ip**:: Fetch the the public ip address for each supported NAT helper method. **-p** or **--port** __external_port__:__internal_port__:: Forward external_port to internal_port. This option can appear more than once. BUGS ---- This probably doesn't run on Windows. That's not a big issue, since we don't really want to deal with Windows before October 2010 anyway. SEE ALSO -------- **tor**(1) + See also the "tor-fw-helper-spec.txt" file, distributed with Tor. AUTHORS ------- Jacob Appelbaum , Steven J. Murdoch tor-0.2.4.20/doc/asciidoc-helper.sh0000755000175000017500000000360012166112776013631 00000000000000#!/bin/sh # Copyright (c) The Tor Project, Inc. # See LICENSE for licensing information # Run this to generate .html.in or .1.in files from asciidoc files. # Arguments: # html|man asciidocpath outputfile set -e if [ $# != 3 ]; then exit 1; fi output=$3 if [ "$1" = "html" ]; then input=${output%%.html.in}.1.txt base=${output%%.html.in} if [ "$2" != none ]; then "$2" -d manpage -o $output $input; else echo "=================================="; echo; echo "You need asciidoc installed to be able to build the manpage."; echo "To build without manpages, use the --disable-asciidoc argument"; echo "when calling configure."; echo; echo "=================================="; exit 1; fi elif [ "$1" = "man" ]; then input=${output%%.1.in}.1.txt base=${output%%.1.in} if test "$2" = none; then echo "=================================="; echo; echo "You need asciidoc installed to be able to build the manpage."; echo "To build without manpages, use the --disable-asciidoc argument"; echo "when calling configure."; echo; echo "=================================="; exit 1; fi if "$2" -f manpage $input; then mv $base.1 $output; else cat< .\" Date: 07/01/2013 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" .TH "TOR\-RESOLVE" "1" "07/01/2013" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" tor-resolve \- resolve a hostname to an IP address via tor .SH "SYNOPSIS" .sp \fBtor\-resolve\fR [\-4|\-5] [\-v] [\-x] \fIhostname\fR [\fIsockshost\fR[:\fIsocksport\fR]] .SH "DESCRIPTION" .sp \fBtor\-resolve\fR is a simple script to connect to a SOCKS proxy that knows about the SOCKS RESOLVE command, hand it a hostname, and return an IP address\&. .sp By default, \fBtor\-resolve\fR uses the Tor server running on 127\&.0\&.0\&.1 on SOCKS port 9050\&. If this isn\(cqt what you want, you should specify an explicit \fIsockshost\fR and/or \fIsocksport\fR on the command line\&. .SH "OPTIONS" .PP \fB\-v\fR .RS 4 Display verbose output\&. .RE .PP \fB\-x\fR .RS 4 Perform a reverse lookup: get the PTR record for an IPv4 address\&. .RE .PP \fB\-5\fR .RS 4 Use the SOCKS5 protocol\&. (Default) .RE .PP \fB\-4\fR .RS 4 Use the SOCKS4a protocol rather than the default SOCKS5 protocol\&. Doesn\(cqt support reverse DNS\&. .RE .SH "SEE ALSO" .sp \fBtor\fR(1), \fBtorify\fR(1)\&. .sp See doc/socks\-extensions\&.txt in the Tor package for protocol details\&. .SH "AUTHORS" .sp Roger Dingledine , Nick Mathewson \&. .SH "AUTHOR" .PP \fBPeter Palfrader\fR .RS 4 Author. .RE tor-0.2.4.20/doc/state-contents.txt0000644000175000017500000000740512144600040013740 00000000000000 Contents of the Tor state file ============================== The state file is structured with more or less the same rules as torrc. Recognized fields are: TorVersion The version of Tor that wrote this file LastWritten Time when this state file was written. Given in ISO format (YYYY-MM-DD HH:MM:SS) AccountingBytesReadInInterval (memory unit) AccountingBytesWrittenInInterval (memory unit) AccountingExpectedUsage (memory unit) AccountingIntervalStart (ISO time) AccountingSecondsActive (time interval) AccountingSecondsToReachSoftLimit (time interval) AccountingSoftLimitHitAt (ISO time) AccountingBytesAtSoftLimit (memory unit) These fields describe the state of the accounting subsystem. The IntervalStart is the time at which the current accounting interval began. We were expecting to use ExpectedUsage over the course of the interval. BytesRead/BytesWritten are the total number of bytes transferred over the whole interval. If Tor has been active during the interval, then AccountingSecondsActive is the amount of time for which it has been active. We were expecting to hit the bandwidth soft limit in SecondsToReachSoftLimit after we became active. When we hit the soft limit, we record BytesAtSoftLimit. If we hit the soft limit already, we did so at SoftLimitHitAt. EntryGuard EntryGuardDownSince EntryGuardUnlistedSince EntryGuardAddedBy These lines form sections related to entry guards. Each section starts with a single EntryGuard line, and is then followed by information on the state of the Entry guard. The EntryGuard line contains a nickname, then an identity digest, of the guard. The EntryGuardDownSince and EntryGuardUnlistedSince lines are present if the entry guard is believed to be non-running or non-listed. If present, they contain a line in ISO format (YYYY-MM-DD HH:MM:SS). The EntryGuardAddedBy line is optional. It contains three space-separated fields: the identity of the entry guard, the version of Tor that added it, and the ISO time at which it was added. TransportProxy One or more of these may be present. The format is "transportname addr:port", to remember the address at which a pluggable transport was listening. Tor bridges use this information to spawn pluggable transport listeners in the same IP address and TCP port even after tor client restarts. BWHistoryReadEnds (ISO time) BWHistoryReadInterval (integer, number of seconds) BWHistoryReadValues (comma-separated list of integer) BWHistoryReadMaxima (comma-separated list of integer) BWHistoryWriteEnds BWHistoryWriteInterval BWHistoryWriteValues BWHistoryWriteMaxima BWHistoryDirReadEnds BWHistoryDirReadInterval BWHistoryDirReadValues BWHistoryDirReadMaxima BWHistoryDirWriteEnds BWHistoryDirWriteInterval BWHistoryDirWriteValues BWHistoryDirWriteMaxima These values record bandwidth history. The "Values" fields are a list, for some number of "Intervals", of the total amount read/written during that integer. The "Maxima" are the highest burst for each interval. Interval duration is set by the "Interval" field, in seconds. The "Ends" field is the ending time of the last interval in each list. The *Read* and *Write* fields are the total amount read and written; the *DirRead* and *DirWrite* variants are for directory traffic only. LastRotatedOnionKey The last time that we changed our onion key for a new one. Given in ISO format (YYYY-MM-DD HH:MM:SS) TotalBuildTimes CircuitBuildAbandonedCount CircuitBuildTimeBin XXXX writeme. tor-0.2.4.20/doc/tor-resolve.1.txt0000644000175000017500000000253012153762274013421 00000000000000// Copyright (c) The Tor Project, Inc. // See LICENSE for licensing information // This is an asciidoc file used to generate the manpage/html reference. // Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html :man source: Tor :man manual: Tor Manual tor-resolve(1) ============== Peter Palfrader NAME ---- tor-resolve - resolve a hostname to an IP address via tor SYNOPSIS -------- **tor-resolve** [-4|-5] [-v] [-x] __hostname__ [__sockshost__[:__socksport__]] DESCRIPTION ----------- **tor-resolve** is a simple script to connect to a SOCKS proxy that knows about the SOCKS RESOLVE command, hand it a hostname, and return an IP address. By default, **tor-resolve** uses the Tor server running on 127.0.0.1 on SOCKS port 9050. If this isn't what you want, you should specify an explicit __sockshost__ and/or __socksport__ on the command line. OPTIONS ------- **-v**:: Display verbose output. **-x**:: Perform a reverse lookup: get the PTR record for an IPv4 address. **-5**:: Use the SOCKS5 protocol. (Default) **-4**:: Use the SOCKS4a protocol rather than the default SOCKS5 protocol. Doesn't support reverse DNS. SEE ALSO -------- **tor**(1), **torify**(1). + See doc/socks-extensions.txt in the Tor package for protocol details. AUTHORS ------- Roger Dingledine , Nick Mathewson . tor-0.2.4.20/doc/torify.1.txt0000644000175000017500000000211612166112776012454 00000000000000// Copyright (c) The Tor Project, Inc. // See LICENSE for licensing information // This is an asciidoc file used to generate the manpage/html reference. // Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html :man source: Tor :man manual: Tor Manual torify(1) ========= NAME ---- torify - wrapper for torsocks and tor SYNOPSIS -------- **torify** __application__ [__application's__ __arguments__] DESCRIPTION ----------- **torify** is a simple wrapper that attempts to find the best underlying Tor wrapper available on a system. It calls torsocks with a tor specific configuration file. + torsocks is an improved wrapper that explicitly rejects UDP, safely resolves DNS lookups and properly socksifies your TCP connections. + Please note that since both method use LD_PRELOAD, torify cannot be applied to suid binaries. WARNING ------- When used with torsocks, torify should not leak DNS requests or UDP data. + Both will leak ICMP data. SEE ALSO -------- **tor**(1), **tor-resolve**(1), **torsocks**(1) AUTHORS ------- Peter Palfrader and Jacob Appelbaum wrote this manual. tor-0.2.4.20/doc/tor-resolve.html.in0000644000175000017500000004453312164363326014022 00000000000000 tor-resolve(1)

SYNOPSIS

tor-resolve [-4|-5] [-v] [-x] hostname [sockshost[:socksport]]

DESCRIPTION

tor-resolve is a simple script to connect to a SOCKS proxy that knows about the SOCKS RESOLVE command, hand it a hostname, and return an IP address.

By default, tor-resolve uses the Tor server running on 127.0.0.1 on SOCKS port 9050. If this isn’t what you want, you should specify an explicit sockshost and/or socksport on the command line.

OPTIONS

-v

Display verbose output.

-x

Perform a reverse lookup: get the PTR record for an IPv4 address.

-5

Use the SOCKS5 protocol. (Default)

-4

Use the SOCKS4a protocol rather than the default SOCKS5 protocol. Doesn’t support reverse DNS.

SEE ALSO

tor(1), torify(1).

See doc/socks-extensions.txt in the Tor package for protocol details.

AUTHORS

Roger Dingledine <arma@mit.edu>, Nick Mathewson <nickm@alum.mit.edu>.


tor-0.2.4.20/doc/torify.1.in0000644000175000017500000000376212166116244012245 00000000000000'\" t .\" Title: torify .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.76.1 .\" Date: 07/06/2013 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" .TH "TORIFY" "1" "07/06/2013" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" torify \- wrapper for torsocks and tor .SH "SYNOPSIS" .sp \fBtorify\fR \fIapplication\fR [\fIapplication\(cqs\fR \fIarguments\fR] .SH "DESCRIPTION" .sp \fBtorify\fR is a simple wrapper that attempts to find the best underlying Tor wrapper available on a system\&. It calls torsocks with a tor specific configuration file\&. .sp torsocks is an improved wrapper that explicitly rejects UDP, safely resolves DNS lookups and properly socksifies your TCP connections\&. .sp Please note that since both method use LD_PRELOAD, torify cannot be applied to suid binaries\&. .SH "WARNING" .sp When used with torsocks, torify should not leak DNS requests or UDP data\&. .sp Both will leak ICMP data\&. .SH "SEE ALSO" .sp \fBtor\fR(1), \fBtor\-resolve\fR(1), \fBtorsocks\fR(1) .SH "AUTHORS" .sp Peter Palfrader and Jacob Appelbaum wrote this manual\&. tor-0.2.4.20/doc/HACKING0000644000175000017500000004520212255745673011241 00000000000000Hacking Tor: An Incomplete Guide ================================ Getting started --------------- For full information on how Tor is supposed to work, look at the files in https://gitweb.torproject.org/torspec.git/tree For an explanation of how to change Tor's design to work differently, look at https://gitweb.torproject.org/torspec.git/blob_plain/HEAD:/proposals/001-process.txt For the latest version of the code, get a copy of git, and git clone https://git.torproject.org/git/tor We talk about Tor on the tor-talk mailing list. Design proposals and discussion belong on the tor-dev mailing list. We hang around on irc.oftc.net, with general discussion happening on #tor and development happening on #tor-dev. How we use Git branches ----------------------- Each main development series (like 0.2.1, 0.2.2, etc) has its main work applied to a single branch. At most one series can be the development series at a time; all other series are maintenance series that get bug-fixes only. The development series is built in a git branch called "master"; the maintenance series are built in branches called "maint-0.2.0", "maint-0.2.1", and so on. We regularly merge the active maint branches forward. For all series except the development series, we also have a "release" branch (as in "release-0.2.1"). The release series is based on the corresponding maintenance series, except that it deliberately lags the maint series for most of its patches, so that bugfix patches are not typically included in a maintenance release until they've been tested for a while in a development release. Occasionally, we'll merge an urgent bugfix into the release branch before it gets merged into maint, but that's rare. If you're working on a bugfix for a bug that occurs in a particular version, base your bugfix branch on the "maint" branch for the first supported series that has that bug. (As of June 2013, we're supporting 0.2.3 and later.) If you're working on a new feature, base it on the master branch. How we log changes ------------------ When you do a commit that needs a ChangeLog entry, add a new file to the "changes" toplevel subdirectory. It should have the format of a one-entry changelog section from the current ChangeLog file, as in o Major bugfixes: - Fix a potential buffer overflow. Fixes bug 99999; bugfix on 0.3.1.4-beta. To write a changes file, first categorize the change. Some common categories are: Minor bugfixes, Major bugfixes, Minor features, Major features, Code simplifications and refactoring. Then say what the change does. If it's a bugfix, mention what bug it fixes and when the bug was introduced. To find out which Git tag the change was introduced in, you can use "git describe --contains ". If at all possible, try to create this file in the same commit where you are making the change. Please give it a distinctive name that no other branch will use for the lifetime of your change. When we go to make a release, we will concatenate all the entries in changes to make a draft changelog, and clear the directory. We'll then edit the draft changelog into a nice readable format. What needs a changes file?:: A not-exhaustive list: Anything that might change user-visible behavior. Anything that changes internals, documentation, or the build system enough that somebody could notice. Big or interesting code rewrites. Anything about which somebody might plausibly wonder "when did that happen, and/or why did we do that" 6 months down the line. Why use changes files instead of Git commit messages?:: Git commit messages are written for developers, not users, and they are nigh-impossible to revise after the fact. Why use changes files instead of entries in the ChangeLog?:: Having every single commit touch the ChangeLog file tended to create zillions of merge conflicts. Useful tools ------------ These aren't strictly necessary for hacking on Tor, but they can help track down bugs. Jenkins ~~~~~~~ http://jenkins.torproject.org Dmalloc ~~~~~~~ The dmalloc library will keep track of memory allocation, so you can find out if we're leaking memory, doing any double-frees, or so on. dmalloc -l ~/dmalloc.log (run the commands it tells you) ./configure --with-dmalloc Valgrind ~~~~~~~~ valgrind --leak-check=yes --error-limit=no --show-reachable=yes src/or/tor (Note that if you get a zillion openssl warnings, you will also need to pass --undef-value-errors=no to valgrind, or rebuild your openssl with -DPURIFY.) Running gcov for unit test coverage ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ----- make clean make CFLAGS='-g -fprofile-arcs -ftest-coverage' ./src/test/test gcov -o src/common src/common/*.[ch] gcov -o src/or src/or/*.[ch] cd ../or; gcov *.[ch] ----- Then, look at the .gcov files. '-' before a line means that the compiler generated no code for that line. '######' means that the line was never reached. Lines with numbers were called that number of times. If that doesn't work: * Try configuring Tor with --disable-gcc-hardening * On recent OSX versions, you might need to add CC=clang to your build line, as in: make CFLAGS='-g -fprofile-arcs -ftest-coverage' CC=clang Their llvm-gcc doesn't work so great for me. Profiling Tor with oprofile ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The oprofile tool runs (on Linux only!) to tell you what functions Tor is spending its CPU time in, so we can identify berformance pottlenecks. Here are some basic instructions - Build tor with debugging symbols (you probably already have, unless you messed with CFLAGS during the build process). - Build all the libraries you care about with debugging symbols (probably you only care about libssl, maybe zlib and Libevent). - Copy this tor to a new directory - Copy all the libraries it uses to that dir too (ldd ./tor will tell you) - Set LD_LIBRARY_PATH to include that dir. ldd ./tor should now show you it's using the libs in that dir - Run that tor - Reset oprofiles counters/start it * "opcontrol --reset; opcontrol --start", if Nick remembers right. - After a while, have it dump the stats on tor and all the libs in that dir you created. * "opcontrol --dump;" * "opreport -l that_dir/*" - Profit Coding conventions ------------------ Patch checklist ~~~~~~~~~~~~~~~ If possible, send your patch as one of these (in descending order of preference) - A git branch we can pull from - Patches generated by git format-patch - A unified diff Did you remember... - To build your code while configured with --enable-gcc-warnings? - To run "make check-spaces" on your code? - To run "make check-docs" to see whether all new options are on the manpage? - To write unit tests, as possible? - To base your code on the appropriate branch? - To include a file in the "changes" directory as appropriate? Whitespace and C conformance ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Invoke "make check-spaces" from time to time, so it can tell you about deviations from our C whitespace style. Generally, we use: - Unix-style line endings - K&R-style indentation - No space before newlines - A blank line at the end of each file - Never more than one blank line in a row - Always spaces, never tabs - No more than 79-columns per line. - Two spaces per indent. - A space between control keywords and their corresponding paren "if (x)", "while (x)", and "switch (x)", never "if(x)", "while(x)", or "switch(x)". - A space between anything and an open brace. - No space between a function name and an opening paren. "puts(x)", not "puts (x)". - Function declarations at the start of the line. We try hard to build without warnings everywhere. In particular, if you're using gcc, you should invoke the configure script with the option "--enable-gcc-warnings". This will give a bunch of extra warning flags to the compiler, and help us find divergences from our preferred C style. Getting emacs to edit Tor source properly ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nick likes to put the following snippet in his .emacs file: ----- (add-hook 'c-mode-hook (lambda () (font-lock-mode 1) (set-variable 'show-trailing-whitespace t) (let ((fname (expand-file-name (buffer-file-name)))) (cond ((string-match "^/home/nickm/src/libevent" fname) (set-variable 'indent-tabs-mode t) (set-variable 'c-basic-offset 4) (set-variable 'tab-width 4)) ((string-match "^/home/nickm/src/tor" fname) (set-variable 'indent-tabs-mode nil) (set-variable 'c-basic-offset 2)) ((string-match "^/home/nickm/src/openssl" fname) (set-variable 'indent-tabs-mode t) (set-variable 'c-basic-offset 8) (set-variable 'tab-width 8)) )))) ----- You'll note that it defaults to showing all trailing whitespace. The "cond" test detects whether the file is one of a few C free software projects that I often edit, and sets up the indentation level and tab preferences to match what they want. If you want to try this out, you'll need to change the filename regex patterns to match where you keep your Tor files. If you use emacs for editing Tor and nothing else, you could always just say: ----- (add-hook 'c-mode-hook (lambda () (font-lock-mode 1) (set-variable 'show-trailing-whitespace t) (set-variable 'indent-tabs-mode nil) (set-variable 'c-basic-offset 2))) ----- There is probably a better way to do this. No, we are probably not going to clutter the files with emacs stuff. Functions to use ~~~~~~~~~~~~~~~~ We have some wrapper functions like tor_malloc, tor_free, tor_strdup, and tor_gettimeofday; use them instead of their generic equivalents. (They always succeed or exit.) You can get a full list of the compatibility functions that Tor provides by looking through src/common/util.h and src/common/compat.h. You can see the available containers in src/common/containers.h. You should probably familiarize yourself with these modules before you write too much code, or else you'll wind up reinventing the wheel. Use 'INLINE' instead of 'inline', so that we work properly on Windows. Calling and naming conventions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Whenever possible, functions should return -1 on error and 0 on success. For multi-word identifiers, use lowercase words combined with underscores. (e.g., "multi_word_identifier"). Use ALL_CAPS for macros and constants. Typenames should end with "_t". Function names should be prefixed with a module name or object name. (In general, code to manipulate an object should be a module with the same name as the object, so it's hard to tell which convention is used.) Functions that do things should have imperative-verb names (e.g. buffer_clear, buffer_resize); functions that return booleans should have predicate names (e.g. buffer_is_empty, buffer_needs_resizing). If you find that you have four or more possible return code values, it's probably time to create an enum. If you find that you are passing three or more flags to a function, it's probably time to create a flags argument that takes a bitfield. What To Optimize ~~~~~~~~~~~~~~~~ Don't optimize anything if it's not in the critical path. Right now, the critical path seems to be AES, logging, and the network itself. Feel free to do your own profiling to determine otherwise. Log conventions ~~~~~~~~~~~~~~~ https://trac.torproject.org/projects/tor/wiki/doc/TorFAQ#loglevel No error or warning messages should be expected during normal OR or OP operation. If a library function is currently called such that failure always means ERR, then the library function should log WARN and let the caller log ERR. Every message of severity INFO or higher should either (A) be intelligible to end-users who don't know the Tor source; or (B) somehow inform the end-users that they aren't expected to understand the message (perhaps with a string like "internal error"). Option (A) is to be preferred to option (B). Doxygen ~~~~~~~~ We use the 'doxygen' utility to generate documentation from our source code. Here's how to use it: 1. Begin every file that should be documented with /** * \file filename.c * \brief Short description of the file. **/ (Doxygen will recognize any comment beginning with /** as special.) 2. Before any function, structure, #define, or variable you want to document, add a comment of the form: /** Describe the function's actions in imperative sentences. * * Use blank lines for paragraph breaks * - and * - hyphens * - for * - lists. * * Write argument_names in boldface. * * \code * place_example_code(); * between_code_and_endcode_commands(); * \endcode */ 3. Make sure to escape the characters "<", ">", "\", "%" and "#" as "\<", "\>", "\\", "\%", and "\#". 4. To document structure members, you can use two forms: struct foo { /** You can put the comment before an element; */ int a; int b; /**< Or use the less-than symbol to put the comment * after the element. */ }; 5. To generate documentation from the Tor source code, type: $ doxygen -g To generate a file called 'Doxyfile'. Edit that file and run 'doxygen' to generate the API documentation. 6. See the Doxygen manual for more information; this summary just scratches the surface. Doxygen comment conventions ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Say what functions do as a series of one or more imperative sentences, as though you were telling somebody how to be the function. In other words, DO NOT say: /** The strtol function parses a number. * * nptr -- the string to parse. It can include whitespace. * endptr -- a string pointer to hold the first thing that is not part * of the number, if present. * base -- the numeric base. * returns: the resulting number. */ long strtol(const char *nptr, char **nptr, int base); Instead, please DO say: /** Parse a number in radix base from the string nptr, * and return the result. Skip all leading whitespace. If * endptr is not NULL, set *endptr to the first character * after the number parsed. **/ long strtol(const char *nptr, char **nptr, int base); Doxygen comments are the contract in our abstraction-by-contract world: if the functions that call your function rely on it doing something, then your function should mention that it does that something in the documentation. If you rely on a function doing something beyond what is in its documentation, then you should watch out, or it might do something else later. Putting out a new release ------------------------- Here are the steps Roger takes when putting out a new Tor release: 1) Use it for a while, as a client, as a relay, as a hidden service, and as a directory authority. See if it has any obvious bugs, and resolve those. 1.5) As applicable, merge the maint-X branch into the release-X branch. 2) Gather the changes/* files into a changelog entry, rewriting many of them and reordering to focus on what users and funders would find interesting and understandable. 2.1) Make sure that everything that wants a bug number has one. 2.2) Concatenate them. 2.3) Sort them by section. Within each section, try to make the first entry or two and the last entry most interesting: they're the ones that skimmers tend to read. 2.4) Clean them up: Standard idioms: "Fixes bug 9999; bugfix on 0.3.3.3-alpha." One period after a space. Make stuff very terse Make sure each section name ends with a colon Describe the user-visible problem right away Mention relevant config options by name. If they're rare or unusual, remind people what they're for Avoid starting lines with open-paren Present and imperative tense: not past. Try not to let any given section be longer than about a page. Break up long sections into subsections by some sort of common subtopic. This guideline is especially important when organizing Release Notes for new stable releases. If a given changes stanza showed up in a different release (e.g. maint-0.2.1), be sure to make the stanzas identical (so people can distinguish if these are the same change). 2.5) Merge them in. 2.6) Clean everything one last time. 2.7) Run it through fmt to make it pretty. 3) Compose a short release blurb to highlight the user-facing changes. Insert said release blurb into the ChangeLog stanza. If it's a stable release, add it to the ReleaseNotes file too. If we're adding to a release-0.2.x branch, manually commit the changelogs to the later git branches too. 4) Bump the version number in configure.ac and rebuild. 5) Make dist, put the tarball up somewhere, and tell #tor about it. Wait a while to see if anybody has problems building it. Try to get Sebastian or somebody to try building it on Windows. 6) Get at least two of weasel/arma/sebastian to put the new version number in their approved versions list. 7) Sign the tarball, then sign and push the git tag: gpg -ba git tag -u tor-0.2.x.y-status git push origin tag tor-0.2.x.y-status 8) scp the tarball and its sig to the website in the dist/ directory (i.e. /srv/www-master.torproject.org/htdocs/dist/ on vescum). Edit include/versions.wmi to note the new version. From your website checkout, run ./publish to build and publish the website. Try not to delay too much between scp'ing the tarball and running ./publish -- the website has multiple A records and your scp only sent it to one of them. 9) Email Erinn and weasel (cc'ing tor-assistants) that a new tarball is up. This step should probably change to mailing more packagers. 10) Add the version number to Trac. To do this, go to Trac, log in, select "Admin" near the top of the screen, then select "Versions" from the menu on the left. At the right, there will be an "Add version" box. By convention, we enter the version in the form "Tor: 0.2.2.23-alpha" (or whatever the version is), and we select the date as the date in the ChangeLog. 11) Forward-port the ChangeLog. 12) Update the topic in #tor to reflect the new version. 12) Wait up to a day or two (for a development release), or until most packages are up (for a stable release), and mail the release blurb and changelog to tor-talk or tor-announce. (We might be moving to faster announcements, but don't announce until the website is at least updated.) tor-0.2.4.20/doc/tor.1.in0000644000175000017500000034242312255753435011545 00000000000000'\" t .\" Title: tor .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.76.1 .\" Date: 12/23/2013 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" .TH "TOR" "1" "12/23/2013" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" tor \- The second\-generation onion router .SH "SYNOPSIS" .sp \fBtor\fR [\fIOPTION\fR \fIvalue\fR]\&... .SH "DESCRIPTION" .sp \fItor\fR is a connection\-oriented anonymizing communication service\&. Users choose a source\-routed path through a set of nodes, and negotiate a "virtual circuit" through the network, in which each node knows its predecessor and successor, but no others\&. Traffic flowing down the circuit is unwrapped by a symmetric key at each node, which reveals the downstream node\&. .sp Basically \fItor\fR provides a distributed network of servers ("onion routers")\&. Users bounce their TCP streams \(em web traffic, ftp, ssh, etc \(em around the routers, and recipients, observers, and even the routers themselves have difficulty tracking the source of the stream\&. .SH "COMMAND-LINE OPTIONS" .PP \fB\-h\fR, \fB\-help\fR .RS 4 Display a short help message and exit\&. .RE .PP \fB\-f\fR \fIFILE\fR .RS 4 Specify a new configuration file to contain further Tor configuration options\&. (Default: $HOME/\&.torrc, or @CONFDIR@/torrc if that file is not found) .RE .PP \fB\-\-defaults\-torrc\fR \fIFILE\fR .RS 4 Specify a file in which to find default values for Tor options\&. The contents of this file are overridden by those in the regular configuration file, and by those on the command line\&. (Default: @CONFDIR@/torrc\-defaults\&.) .RE .PP \fB\-\-hash\-password\fR .RS 4 Generates a hashed password for control port access\&. .RE .PP \fB\-\-list\-fingerprint\fR .RS 4 Generate your keys and output your nickname and fingerprint\&. .RE .PP \fB\-\-verify\-config\fR .RS 4 Verify the configuration file is valid\&. .RE .PP \fB\-\-service install\fR [\fB\-\-options\fR \fIcommand\-line options\fR] .RS 4 Install an instance of Tor as a Windows service, with the provided command\-line options\&. Current instructions can be found at https://trac\&.torproject\&.org/projects/tor/wiki/doc/TorFAQ#HowdoIrunmyTorrelayasanNTservice .RE .PP \fB\-\-service\fR \fBremove\fR|\fBstart\fR|\fBstop\fR .RS 4 Remove, start, or stop a configured Tor Windows service\&. .RE .PP \fB\-\-nt\-service\fR .RS 4 Used internally to implement a Windows service\&. .RE .PP \fB\-\-list\-torrc\-options\fR .RS 4 List all valid options\&. .RE .PP \fB\-\-version\fR .RS 4 Display Tor version and exit\&. .RE .PP \fB\-\-quiet\fR|\fB\-\-hush\fR .RS 4 Override the default console log\&. By default, Tor starts out logging messages at level "notice" and higher to the console\&. It stops doing so after it parses its configuration, if the configuration tells it to log anywhere else\&. You can override this behavior with the \fB\-\-hush\fR option, which tells Tor to only send warnings and errors to the console, or with the \fB\-\-quiet\fR option, which tells Tor not to log to the console at all\&. .RE .sp Other options can be specified on the command\-line in the format "\-\-option value", in the format "option value", or in a configuration file\&. For instance, you can tell Tor to start listening for SOCKS connections on port 9999 by passing \-\-SOCKSPort 9999 or SOCKSPort 9999 to it on the command line, or by putting "SOCKSPort 9999" in the configuration file\&. You will need to quote options with spaces in them: if you want Tor to log all debugging messages to debug\&.log, you will probably need to say \-\-Log \fIdebug file debug\&.log\fR\&. .sp Options on the command line override those in configuration files\&. See the next section for more information\&. .SH "THE CONFIGURATION FILE FORMAT" .sp All configuration options in a configuration are written on a single line by default\&. They take the form of an option name and a value, or an option name and a quoted value (option value or option "value")\&. Anything after a # character is treated as a comment\&. Options are case\-insensitive\&. C\-style escaped characters are allowed inside quoted values\&. To split one configuration entry into multiple lines, use a single backslash character (\e) before the end of the line\&. Comments can be used in such multiline entries, but they must start at the beginning of a line\&. .sp By default, an option on the command line overrides an option found in the configuration file, and an option in a configuration file overrides one in the defaults file\&. .sp This rule is simple for options that take a single value, but it can become complicated for options that are allowed to occur more than once: if you specify four SOCKSPorts in your configuration file, and one more SOCKSPort on the command line, the option on the command line will replace \fIall\fR of the SOCKSPorts in the configuration file\&. If this isn\(cqt what you want, prefix the option name with a plus sign, and it will be appended to the previous set of options instead\&. .sp Alternatively, you might want to remove every instance of an option in the configuration file, and not replace it at all: you might want to say on the command line that you want no SOCKSPorts at all\&. To do that, prefix the option name with a forward slash\&. .SH "GENERAL OPTIONS" .PP \fBBandwidthRate\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 A token bucket limits the average incoming bandwidth usage on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value\&. If you want to run a relay in the public network, this needs to be \fIat the very least\fR 30 KBytes (that is, 30720 bytes)\&. (Default: 1 GByte) .RE .PP \fBBandwidthBurst\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 Limit the maximum token bucket size (also known as the burst) to the given number of bytes in each direction\&. (Default: 1 GByte) .RE .PP \fBMaxAdvertisedBandwidth\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 If set, we will not advertise more than this amount of bandwidth for our BandwidthRate\&. Server operators who want to reduce the number of clients who ask to build circuits through them (since this is proportional to advertised bandwidth rate) can thus reduce the CPU demands on their server without impacting network performance\&. .RE .PP \fBRelayBandwidthRate\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 If not 0, a separate token bucket limits the average incoming bandwidth usage for _relayed traffic_ on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value\&. Relayed traffic currently is calculated to include answers to directory requests, but that may change in future versions\&. (Default: 0) .RE .PP \fBRelayBandwidthBurst\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 If not 0, limit the maximum token bucket size (also known as the burst) for _relayed traffic_ to the given number of bytes in each direction\&. (Default: 0) .RE .PP \fBPerConnBWRate\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 If set, do separate rate limiting for each connection from a non\-relay\&. You should never need to change this value, since a network\-wide value is published in the consensus and your relay will use that value\&. (Default: 0) .RE .PP \fBPerConnBWBurst\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 If set, do separate rate limiting for each connection from a non\-relay\&. You should never need to change this value, since a network\-wide value is published in the consensus and your relay will use that value\&. (Default: 0) .RE .PP \fBClientTransportPlugin\fR \fItransport\fR socks4|socks5 \fIIP\fR:\fIPORT\fR, \fBClientTransportPlugin\fR \fItransport\fR exec \fIpath\-to\-binary\fR [options] .RS 4 In its first form, when set along with a corresponding Bridge line, the Tor client forwards its traffic to a SOCKS\-speaking proxy on "IP:PORT"\&. It\(cqs the duty of that proxy to properly forward the traffic to the bridge\&. In its second form, when set along with a corresponding Bridge line, the Tor client launches the pluggable transport proxy executable in \fIpath\-to\-binary\fR using \fIoptions\fR as its command\-line options, and forwards its traffic to it\&. It\(cqs the duty of that proxy to properly forward the traffic to the bridge\&. .RE .PP \fBServerTransportPlugin\fR \fItransport\fR exec \fIpath\-to\-binary\fR [options] .RS 4 The Tor relay launches the pluggable transport proxy in \fIpath\-to\-binary\fR using \fIoptions\fR as its command\-line options, and expects to receive proxied client traffic from it\&. .RE .PP \fBServerTransportListenAddr\fR \fItransport\fR \fIIP\fR:\fIPORT\fR .RS 4 When this option is set, Tor will suggest \fIIP\fR:\fIPORT\fR as the listening address of any pluggable transport proxy that tries to launch \fItransport\fR\&. .RE .PP \fBConnLimit\fR \fINUM\fR .RS 4 The minimum number of file descriptors that must be available to the Tor process before it will start\&. Tor will ask the OS for as many file descriptors as the OS will allow (you can find this by "ulimit \-H \-n")\&. If this number is less than ConnLimit, then Tor will refuse to start\&. You probably don\(cqt need to adjust this\&. It has no effect on Windows since that platform lacks getrlimit()\&. (Default: 1000) .RE .PP \fBDisableNetwork\fR \fB0\fR|\fB1\fR .RS 4 When this option is set, we don\(cqt listen for or accept any connections other than controller connections, and we don\(cqt make any outbound connections\&. Controllers sometimes use this option to avoid using the network until Tor is fully configured\&. (Default: 0) .RE .PP \fBConstrainedSockets\fR \fB0\fR|\fB1\fR .RS 4 If set, Tor will tell the kernel to attempt to shrink the buffers for all sockets to the size specified in \fBConstrainedSockSize\fR\&. This is useful for virtual servers and other environments where system level TCP buffers may be limited\&. If you\(cqre on a virtual server, and you encounter the "Error creating network socket: No buffer space available" message, you are likely experiencing this problem\&. The preferred solution is to have the admin increase the buffer pool for the host itself via /proc/sys/net/ipv4/tcp_mem or equivalent facility; this configuration option is a second\-resort\&. The DirPort option should also not be used if TCP buffers are scarce\&. The cached directory requests consume additional sockets which exacerbates the problem\&. You should \fBnot\fR enable this feature unless you encounter the "no buffer space available" issue\&. Reducing the TCP buffers affects window size for the TCP stream and will reduce throughput in proportion to round trip time on long paths\&. (Default: 0) .RE .PP \fBConstrainedSockSize\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR .RS 4 When \fBConstrainedSockets\fR is enabled the receive and transmit buffers for all sockets will be set to this limit\&. Must be a value between 2048 and 262144, in 1024 byte increments\&. Default of 8192 is recommended\&. .RE .PP \fBControlPort\fR \fIPORT\fR|\fBauto\fR .RS 4 If set, Tor will accept connections on this port and allow those connections to control the Tor process using the Tor Control Protocol (described in control\-spec\&.txt)\&. Note: unless you also specify one or more of \fBHashedControlPassword\fR or \fBCookieAuthentication\fR, setting this option will cause Tor to allow any process on the local host to control it\&. (Setting both authentication methods means either method is sufficient to authenticate to Tor\&.) This option is required for many Tor controllers; most use the value of 9051\&. Set it to "auto" to have Tor pick a port for you\&. (Default: 0) .RE .PP \fBControlListenAddress\fR \fIIP\fR[:\fIPORT\fR] .RS 4 Bind the controller listener to this address\&. If you specify a port, bind to this port rather than the one specified in ControlPort\&. We strongly recommend that you leave this alone unless you know what you\(cqre doing, since giving attackers access to your control listener is really dangerous\&. This directive can be specified multiple times to bind to multiple addresses/ports\&. (Default: 127\&.0\&.0\&.1) .RE .PP \fBControlSocket\fR \fIPath\fR .RS 4 Like ControlPort, but listens on a Unix domain socket, rather than a TCP socket\&. (Unix and Unix\-like systems only\&.) .RE .PP \fBControlSocketsGroupWritable\fR \fB0\fR|\fB1\fR .RS 4 If this option is set to 0, don\(cqt allow the filesystem group to read and write unix sockets (e\&.g\&. ControlSocket)\&. If the option is set to 1, make the control socket readable and writable by the default GID\&. (Default: 0) .RE .PP \fBHashedControlPassword\fR \fIhashed_password\fR .RS 4 Allow connections on the control port if they present the password whose one\-way hash is \fIhashed_password\fR\&. You can compute the hash of a password by running "tor \-\-hash\-password \fIpassword\fR"\&. You can provide several acceptable passwords by using more than one HashedControlPassword line\&. .RE .PP \fBCookieAuthentication\fR \fB0\fR|\fB1\fR .RS 4 If this option is set to 1, allow connections on the control port when the connecting process knows the contents of a file named "control_auth_cookie", which Tor will create in its data directory\&. This authentication method should only be used on systems with good filesystem security\&. (Default: 0) .RE .PP \fBCookieAuthFile\fR \fIPath\fR .RS 4 If set, this option overrides the default location and file name for Tor\(cqs cookie file\&. (See CookieAuthentication above\&.) .RE .PP \fBCookieAuthFileGroupReadable\fR \fB0\fR|\fB1\fR|\fIGroupname\fR .RS 4 If this option is set to 0, don\(cqt allow the filesystem group to read the cookie file\&. If the option is set to 1, make the cookie file readable by the default GID\&. [Making the file readable by other groups is not yet implemented; let us know if you need this for some reason\&.] (Default: 0) .RE .PP \fBControlPortWriteToFile\fR \fIPath\fR .RS 4 If set, Tor writes the address and port of any control port it opens to this address\&. Usable by controllers to learn the actual control port when ControlPort is set to "auto"\&. .RE .PP \fBControlPortFileGroupReadable\fR \fB0\fR|\fB1\fR .RS 4 If this option is set to 0, don\(cqt allow the filesystem group to read the control port file\&. If the option is set to 1, make the control port file readable by the default GID\&. (Default: 0) .RE .PP \fBDataDirectory\fR \fIDIR\fR .RS 4 Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor) .RE .PP \fBFallbackDir\fR \fIaddress\fR:\fIport\fR orport=\fIport\fR id=\fIfingerprint\fR [weight=\fInum\fR] .RS 4 When we\(cqre unable to connect to any directory cache for directory info (usually because we don\(cqt know about any yet) we try a FallbackDir\&. By default, the directory authorities are also FallbackDirs\&. .RE .PP \fBDirAuthority\fR [\fInickname\fR] [\fBflags\fR] \fIaddress\fR:\fIport\fR \fIfingerprint\fR .RS 4 Use a nonstandard authoritative directory server at the provided address and port, with the specified key fingerprint\&. This option can be repeated many times, for multiple authoritative directory servers\&. Flags are separated by spaces, and determine what kind of an authority this directory is\&. By default, every authority is authoritative for current ("v2")\-style directories, unless the "no\-v2" flag is given\&. If the "v1" flags is provided, Tor will use this server as an authority for old\-style (v1) directories as well\&. (Only directory mirrors care about this\&.) Tor will use this server as an authority for hidden service information if the "hs" flag is set, or if the "v1" flag is set and the "no\-hs" flag is \fBnot\fR set\&. Tor will use this authority as a bridge authoritative directory if the "bridge" flag is set\&. If a flag "orport=\fBport\fR" is given, Tor will use the given port when opening encrypted tunnels to the dirserver\&. If a flag "weight=\fBnum\fR" is given, then the directory server is chosen randomly with probability proportional to that weight (default 1\&.0)\&. Lastly, if a flag "v3ident=\fBfp\fR" is given, the dirserver is a v3 directory authority whose v3 long\-term signing key has the fingerprint \fBfp\fR\&. If no \fBDirAuthority\fR line is given, Tor will use the default directory authorities\&. NOTE: this option is intended for setting up a private Tor network with its own directory authorities\&. If you use it, you will be distinguishable from other users, because you won\(cqt believe the same authorities they do\&. .RE .PP \fBDirAuthorityFallbackRate\fR \fINUM\fR .RS 4 When configured to use both directory authorities and fallback directories, the directory authorities also work as fallbacks\&. They are chosen with their regular weights, multiplied by this number, which should be 1\&.0 or less\&. (Default: 1\&.0) .RE .PP \fBDynamicDHGroups\fR \fB0\fR|\fB1\fR .RS 4 If this option is set to 1, when running as a server, generate our own Diffie\-Hellman group instead of using the one from Apache\(cqs mod_ssl\&. This option may help circumvent censorship based on static Diffie\-Hellman parameters\&. (Default: 0) .RE .sp \fBAlternateDirAuthority\fR [\fInickname\fR] [\fBflags\fR] \fIaddress\fR:\fIport\fR \fIfingerprint\fR .sp \fBAlternateHSAuthority\fR [\fInickname\fR] [\fBflags\fR] \fIaddress\fR:\fIport\fR \fIfingerprint\fR .PP \fBAlternateBridgeAuthority\fR [\fInickname\fR] [\fBflags\fR] \fIaddress\fR:\fIport\fR \fI fingerprint\fR .RS 4 These options behave as DirAuthority, but they replace fewer of the default directory authorities\&. Using AlternateDirAuthority replaces the default Tor directory authorities, but leaves the default hidden service authorities and bridge authorities in place\&. Similarly, AlternateHSAuthority replaces the default hidden service authorities, but not the directory or bridge authorities; and AlternateBridgeAuthority replaces the default bridge authority, but leaves the directory and hidden service authorities alone\&. .RE .PP \fBDisableAllSwap\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, Tor will attempt to lock all current and future memory pages, so that memory cannot be paged out\&. Windows, OS X and Solaris are currently not supported\&. We believe that this feature works on modern Gnu/Linux distributions, and that it should work on *BSD systems (untested)\&. This option requires that you start your Tor as root, and you should use the \fBUser\fR option to properly reduce Tor\(cqs privileges\&. (Default: 0) .RE .PP \fBDisableDebuggerAttachment\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, Tor will attempt to prevent basic debugging attachment attempts by other processes\&. This may also keep Tor from generating core files if it crashes\&. It has no impact for users who wish to attach if they have CAP_SYS_PTRACE or if they are root\&. We believe that this feature works on modern Gnu/Linux distributions, and that it may also work on *BSD systems (untested)\&. Some modern Gnu/Linux systems such as Ubuntu have the kernel\&.yama\&.ptrace_scope sysctl and by default enable it as an attempt to limit the PTRACE scope for all user processes by default\&. This feature will attempt to limit the PTRACE scope for Tor specifically \- it will not attempt to alter the system wide ptrace scope as it may not even exist\&. If you wish to attach to Tor with a debugger such as gdb or strace you will want to set this to 0 for the duration of your debugging\&. Normal users should leave it on\&. Disabling this option while Tor is running is prohibited\&. (Default: 1) .RE .PP \fBFetchDirInfoEarly\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, Tor will always fetch directory information like other directory caches, even if you don\(cqt meet the normal criteria for fetching early\&. Normal users should leave it off\&. (Default: 0) .RE .PP \fBFetchDirInfoExtraEarly\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, Tor will fetch directory information before other directory caches\&. It will attempt to download directory information closer to the start of the consensus period\&. Normal users should leave it off\&. (Default: 0) .RE .PP \fBFetchHidServDescriptors\fR \fB0\fR|\fB1\fR .RS 4 If set to 0, Tor will never fetch any hidden service descriptors from the rendezvous directories\&. This option is only useful if you\(cqre using a Tor controller that handles hidden service fetches for you\&. (Default: 1) .RE .PP \fBFetchServerDescriptors\fR \fB0\fR|\fB1\fR .RS 4 If set to 0, Tor will never fetch any network status summaries or server descriptors from the directory servers\&. This option is only useful if you\(cqre using a Tor controller that handles directory fetches for you\&. (Default: 1) .RE .PP \fBFetchUselessDescriptors\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, Tor will fetch every non\-obsolete descriptor from the authorities that it hears about\&. Otherwise, it will avoid fetching useless descriptors, for example for routers that are not running\&. This option is useful if you\(cqre using the contributed "exitlist" script to enumerate Tor nodes that exit to certain addresses\&. (Default: 0) .RE .PP \fBHTTPProxy\fR \fIhost\fR[:\fIport\fR] .RS 4 Tor will make all its directory requests through this host:port (or host:80 if port is not specified), rather than connecting directly to any directory servers\&. .RE .PP \fBHTTPProxyAuthenticator\fR \fIusername:password\fR .RS 4 If defined, Tor will use this username:password for Basic HTTP proxy authentication, as in RFC 2617\&. This is currently the only form of HTTP proxy authentication that Tor supports; feel free to submit a patch if you want it to support others\&. .RE .PP \fBHTTPSProxy\fR \fIhost\fR[:\fIport\fR] .RS 4 Tor will make all its OR (SSL) connections through this host:port (or host:443 if port is not specified), via HTTP CONNECT rather than connecting directly to servers\&. You may want to set \fBFascistFirewall\fR to restrict the set of ports you might try to connect to, if your HTTPS proxy only allows connecting to certain ports\&. .RE .PP \fBHTTPSProxyAuthenticator\fR \fIusername:password\fR .RS 4 If defined, Tor will use this username:password for Basic HTTPS proxy authentication, as in RFC 2617\&. This is currently the only form of HTTPS proxy authentication that Tor supports; feel free to submit a patch if you want it to support others\&. .RE .PP \fBSocks4Proxy\fR \fIhost\fR[:\fIport\fR] .RS 4 Tor will make all OR connections through the SOCKS 4 proxy at host:port (or host:1080 if port is not specified)\&. .RE .PP \fBSocks5Proxy\fR \fIhost\fR[:\fIport\fR] .RS 4 Tor will make all OR connections through the SOCKS 5 proxy at host:port (or host:1080 if port is not specified)\&. .RE .sp \fBSocks5ProxyUsername\fR \fIusername\fR .PP \fBSocks5ProxyPassword\fR \fIpassword\fR .RS 4 If defined, authenticate to the SOCKS 5 server using username and password in accordance to RFC 1929\&. Both username and password must be between 1 and 255 characters\&. .RE .PP \fBKeepalivePeriod\fR \fINUM\fR .RS 4 To keep firewalls from expiring connections, send a padding keepalive cell every NUM seconds on open connections that are in use\&. If the connection has no open circuits, it will instead be closed after NUM seconds of idleness\&. (Default: 5 minutes) .RE .PP \fBLog\fR \fIminSeverity\fR[\-\fImaxSeverity\fR] \fBstderr\fR|\fBstdout\fR|\fBsyslog\fR .RS 4 Send all messages between \fIminSeverity\fR and \fImaxSeverity\fR to the standard output stream, the standard error stream, or to the system log\&. (The "syslog" value is only supported on Unix\&.) Recognized severity levels are debug, info, notice, warn, and err\&. We advise using "notice" in most cases, since anything more verbose may provide sensitive information to an attacker who obtains the logs\&. If only one severity level is given, all messages of that level or higher will be sent to the listed destination\&. .RE .PP \fBLog\fR \fIminSeverity\fR[\-\fImaxSeverity\fR] \fBfile\fR \fIFILENAME\fR .RS 4 As above, but send log messages to the listed filename\&. The "Log" option may appear more than once in a configuration file\&. Messages are sent to all the logs that match their severity level\&. .RE .sp \fBLog\fR \fB[\fR\fIdomain\fR,\&...\fB]\fR\fIminSeverity\fR[\-\fImaxSeverity\fR] \&... \fBfile\fR \fIFILENAME\fR .PP \fBLog\fR \fB[\fR\fIdomain\fR,\&...\fB]\fR\fIminSeverity\fR[\-\fImaxSeverity\fR] \&... \fBstderr\fR|\fBstdout\fR|\fBsyslog\fR .RS 4 As above, but select messages by range of log severity \fIand\fR by a set of "logging domains"\&. Each logging domain corresponds to an area of functionality inside Tor\&. You can specify any number of severity ranges for a single log statement, each of them prefixed by a comma\-separated list of logging domains\&. You can prefix a domain with ~ to indicate negation, and use * to indicate "all domains"\&. If you specify a severity range without a list of domains, it matches all domains\&. This is an advanced feature which is most useful for debugging one or two of Tor\(cqs subsystems at a time\&. The currently recognized domains are: general, crypto, net, config, fs, protocol, mm, http, app, control, circ, rend, bug, dir, dirserv, or, edge, acct, hist, and handshake\&. Domain names are case\-insensitive\&. For example, "Log [handshake]debug [~net,~mm]info notice stdout" sends to stdout: all handshake messages of any severity, all info\-and\-higher messages from domains other than networking and memory management, and all messages of severity notice or higher\&. .RE .PP \fBLogMessageDomains\fR \fB0\fR|\fB1\fR .RS 4 If 1, Tor includes message domains with each log message\&. Every log message currently has at least one domain; most currently have exactly one\&. This doesn\(cqt affect controller log messages\&. (Default: 0) .RE .PP \fBOutboundBindAddress\fR \fIIP\fR .RS 4 Make all outbound connections originate from the IP address specified\&. This is only useful when you have multiple network interfaces, and you want all of Tor\(cqs outgoing connections to use a single one\&. This option may be used twice, once with an IPv4 address and once with an IPv6 address\&. This setting will be ignored for connections to the loopback addresses (127\&.0\&.0\&.0/8 and ::1)\&. .RE .PP \fBPidFile\fR \fIFILE\fR .RS 4 On startup, write our PID to FILE\&. On clean shutdown, remove FILE\&. .RE .PP \fBProtocolWarnings\fR \fB0\fR|\fB1\fR .RS 4 If 1, Tor will log with severity \*(Aqwarn\*(Aq various cases of other parties not following the Tor specification\&. Otherwise, they are logged with severity \*(Aqinfo\*(Aq\&. (Default: 0) .RE .PP \fBRunAsDaemon\fR \fB0\fR|\fB1\fR .RS 4 If 1, Tor forks and daemonizes to the background\&. This option has no effect on Windows; instead you should use the \-\-service command\-line option\&. (Default: 0) .RE .PP \fBLogTimeGranularity\fR \fINUM\fR .RS 4 Set the resolution of timestamps in Tor\(cqs logs to NUM milliseconds\&. NUM must be positive and either a divisor or a multiple of 1 second\&. Note that this option only controls the granularity written by Tor to a file or console log\&. Tor does not (for example) "batch up" log messages to affect times logged by a controller, times attached to syslog messages, or the mtime fields on log files\&. (Default: 1 second) .RE .PP \fBSafeLogging\fR \fB0\fR|\fB1\fR|\fBrelay\fR .RS 4 Tor can scrub potentially sensitive strings from log messages (e\&.g\&. addresses) by replacing them with the string [scrubbed]\&. This way logs can still be useful, but they don\(cqt leave behind personally identifying information about what sites a user might have visited\&. If this option is set to 0, Tor will not perform any scrubbing, if it is set to 1, all potentially sensitive strings are replaced\&. If it is set to relay, all log messages generated when acting as a relay are sanitized, but all messages generated when acting as a client are not\&. (Default: 1) .RE .PP \fBUser\fR \fIUID\fR .RS 4 On startup, setuid to this user and setgid to their primary group\&. .RE .PP \fBHardwareAccel\fR \fB0\fR|\fB1\fR .RS 4 If non\-zero, try to use built\-in (static) crypto hardware acceleration when available\&. (Default: 0) .RE .PP \fBAccelName\fR \fINAME\fR .RS 4 When using OpenSSL hardware crypto acceleration attempt to load the dynamic engine of this name\&. This must be used for any dynamic hardware engine\&. Names can be verified with the openssl engine command\&. .RE .PP \fBAccelDir\fR \fIDIR\fR .RS 4 Specify this option if using dynamic hardware acceleration and the engine implementation library resides somewhere other than the OpenSSL default\&. .RE .PP \fBAvoidDiskWrites\fR \fB0\fR|\fB1\fR .RS 4 If non\-zero, try to write to disk less frequently than we would otherwise\&. This is useful when running on flash memory or other media that support only a limited number of writes\&. (Default: 0) .RE .PP \fBTunnelDirConns\fR \fB0\fR|\fB1\fR .RS 4 If non\-zero, when a directory server we contact supports it, we will build a one\-hop circuit and make an encrypted connection via its ORPort\&. (Default: 1) .RE .PP \fBPreferTunneledDirConns\fR \fB0\fR|\fB1\fR .RS 4 If non\-zero, we will avoid directory servers that don\(cqt support tunneled directory connections, when possible\&. (Default: 1) .RE .PP \fBCircuitPriorityHalflife\fR \fINUM1\fR .RS 4 If this value is set, we override the default algorithm for choosing which circuit\(cqs cell to deliver or relay next\&. When the value is 0, we round\-robin between the active circuits on a connection, delivering one cell from each in turn\&. When the value is positive, we prefer delivering cells from whichever connection has the lowest weighted cell count, where cells are weighted exponentially according to the supplied CircuitPriorityHalflife value (in seconds)\&. If this option is not set at all, we use the behavior recommended in the current consensus networkstatus\&. This is an advanced option; you generally shouldn\(cqt have to mess with it\&. (Default: not set) .RE .PP \fBDisableIOCP\fR \fB0\fR|\fB1\fR .RS 4 If Tor was built to use the Libevent\(cqs "bufferevents" networking code and you\(cqre running on Windows, setting this option to 1 will tell Libevent not to use the Windows IOCP networking API\&. (Default: 1) .RE .PP \fBUserspaceIOCPBuffers\fR \fB0\fR|\fB1\fR .RS 4 If IOCP is enabled (see DisableIOCP above), setting this option to 1 will tell Tor to disable kernel\-space TCP buffers, in order to avoid needless copy operations and try not to run out of non\-paged RAM\&. This feature is experimental; don\(cqt use it yet unless you\(cqre eager to help tracking down bugs\&. (Default: 0) .RE .PP \fB_UseFilteringSSLBufferevents\fR \fB0\fR|\fB1\fR .RS 4 Tells Tor to do its SSL communication using a chain of bufferevents: one for SSL and one for networking\&. This option has no effect if bufferevents are disabled (in which case it can\(cqt turn on), or if IOCP bufferevents are enabled (in which case it can\(cqt turn off)\&. This option is useful for debugging only; most users shouldn\(cqt touch it\&. (Default: 0) .RE .PP \fBCountPrivateBandwidth\fR \fB0\fR|\fB1\fR .RS 4 If this option is set, then Tor\(cqs rate\-limiting applies not only to remote connections, but also to connections to private addresses like 127\&.0\&.0\&.1 or 10\&.0\&.0\&.1\&. This is mostly useful for debugging rate\-limiting\&. (Default: 0) .RE .SH "CLIENT OPTIONS" .sp The following options are useful only for clients (that is, if \fBSocksPort\fR, \fBTransPort\fR, \fBDNSPort\fR, or \fBNATDPort\fR is non\-zero): .PP \fBAllowInvalidNodes\fR \fBentry\fR|\fBexit\fR|\fBmiddle\fR|\fBintroduction\fR|\fBrendezvous\fR|\fB\&...\fR .RS 4 If some Tor servers are obviously not working right, the directory authorities can manually mark them as invalid, meaning that it\(cqs not recommended you use them for entry or exit positions in your circuits\&. You can opt to use them in some circuit positions, though\&. The default is "middle,rendezvous", and other choices are not advised\&. .RE .PP \fBExcludeSingleHopRelays\fR \fB0\fR|\fB1\fR .RS 4 This option controls whether circuits built by Tor will include relays with the AllowSingleHopExits flag set to true\&. If ExcludeSingleHopRelays is set to 0, these relays will be included\&. Note that these relays might be at higher risk of being seized or observed, so they are not normally included\&. Also note that relatively few clients turn off this option, so using these relays might make your client stand out\&. (Default: 1) .RE .PP \fBBridge\fR [\fItransport\fR] \fIIP\fR:\fIORPort\fR [\fIfingerprint\fR] .RS 4 When set along with UseBridges, instructs Tor to use the relay at "IP:ORPort" as a "bridge" relaying into the Tor network\&. If "fingerprint" is provided (using the same format as for DirAuthority), we will verify that the relay running at that location has the right fingerprint\&. We also use fingerprint to look up the bridge descriptor at the bridge authority, if it\(cqs provided and if UpdateBridgesFromAuthority is set too\&. If "transport" is provided, and matches to a ClientTransportPlugin line, we use that pluggable transports proxy to transfer data to the bridge\&. .RE .PP \fBLearnCircuitBuildTimeout\fR \fB0\fR|\fB1\fR .RS 4 If 0, CircuitBuildTimeout adaptive learning is disabled\&. (Default: 1) .RE .PP \fBCircuitBuildTimeout\fR \fINUM\fR .RS 4 Try for at most NUM seconds when building circuits\&. If the circuit isn\(cqt open in that time, give up on it\&. If LearnCircuitBuildTimeout is 1, this value serves as the initial value to use before a timeout is learned\&. If LearnCircuitBuildTimeout is 0, this value is the only value used\&. (Default: 60 seconds) .RE .PP \fBCircuitIdleTimeout\fR \fINUM\fR .RS 4 If we have kept a clean (never used) circuit around for NUM seconds, then close it\&. This way when the Tor client is entirely idle, it can expire all of its circuits, and then expire its TLS connections\&. Also, if we end up making a circuit that is not useful for exiting any of the requests we\(cqre receiving, it won\(cqt forever take up a slot in the circuit list\&. (Default: 1 hour) .RE .PP \fBCircuitStreamTimeout\fR \fINUM\fR .RS 4 If non\-zero, this option overrides our internal timeout schedule for how many seconds until we detach a stream from a circuit and try a new circuit\&. If your network is particularly slow, you might want to set this to a number like 60\&. (Default: 0) .RE .PP \fBClientOnly\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, Tor will under no circumstances run as a relay or serve directory requests\&. This config option is mostly meaningless: we added it back when we were considering having Tor clients auto\-promote themselves to being relays if they were stable and fast enough\&. The current behavior is simply that Tor is a client unless ORPort or DirPort are configured\&. (Default: 0) .RE .PP \fBExcludeNodes\fR \fInode\fR,\fInode\fR,\fI\&...\fR .RS 4 A list of identity fingerprints, nicknames, country codes and address patterns of nodes to avoid when building a circuit\&. (Example: ExcludeNodes SlowServer, ABCD1234CDEF5678ABCD1234CDEF5678ABCD1234, {cc}, 255\&.254\&.0\&.0/8) By default, this option is treated as a preference that Tor is allowed to override in order to keep working\&. For example, if you try to connect to a hidden service, but you have excluded all of the hidden service\(cqs introduction points, Tor will connect to one of them anyway\&. If you do not want this behavior, set the StrictNodes option (documented below)\&. Note also that if you are a relay, this (and the other node selection options below) only affects your own circuits that Tor builds for you\&. Clients can still build circuits through you to any node\&. Controllers can tell Tor to build circuits through any node\&. Country codes are case\-insensitive\&. The code "{??}" refers to nodes whose country can\(cqt be identified\&. No country code, including {??}, works if no GeoIPFile can be loaded\&. See also the GeoIPExcludeUnknown option below\&. .RE .PP \fBExcludeExitNodes\fR \fInode\fR,\fInode\fR,\fI\&...\fR .RS 4 A list of identity fingerprints, nicknames, country codes and address patterns of nodes to never use when picking an exit node\-\-\-that is, a node that delivers traffic for you outside the Tor network\&. Note that any node listed in ExcludeNodes is automatically considered to be part of this list too\&. See also the caveats on the "ExitNodes" option below\&. .RE .PP \fBGeoIPExcludeUnknown\fR \fB0\fR|\fB1\fR|\fBauto\fR .RS 4 If this option is set to \fIauto\fR, then whenever any country code is set in ExcludeNodes or ExcludeExitNodes, all nodes with unknown country ({??} and possibly {A1}) are treated as excluded as well\&. If this option is set to \fI1\fR, then all unknown countries are treated as excluded in ExcludeNodes and ExcludeExitNodes\&. This option has no effect when a GeoIP file isn\(cqt configured or can\(cqt be found\&. (Default: auto) .RE .PP \fBExitNodes\fR \fInode\fR,\fInode\fR,\fI\&...\fR .RS 4 A list of identity fingerprints, nicknames, country codes and address patterns of nodes to use as exit node\-\-\-that is, a node that delivers traffic for you outside the Tor network\&. Note that if you list too few nodes here, or if you exclude too many exit nodes with ExcludeExitNodes, you can degrade functionality\&. For example, if none of the exits you list allows traffic on port 80 or 443, you won\(cqt be able to browse the web\&. Note also that not every circuit is used to deliver traffic outside of the Tor network\&. It is normal to see non\-exit circuits (such as those used to connect to hidden services, those that do directory fetches, those used for relay reachability self\-tests, and so on) that end at a non\-exit node\&. To keep a node from being used entirely, see ExcludeNodes and StrictNodes\&. The ExcludeNodes option overrides this option: any node listed in both ExitNodes and ExcludeNodes is treated as excluded\&. The \&.exit address notation, if enabled via AllowDotExit, overrides this option\&. .RE .PP \fBEntryNodes\fR \fInode\fR,\fInode\fR,\fI\&...\fR .RS 4 A list of identity fingerprints, nicknames, and country codes of nodes to use for the first hop in your normal circuits\&. Normal circuits include all circuits except for direct connections to directory servers\&. The Bridge option overrides this option; if you have configured bridges and UseBridges is 1, the Bridges are used as your entry nodes\&. The ExcludeNodes option overrides this option: any node listed in both EntryNodes and ExcludeNodes is treated as excluded\&. .RE .PP \fBStrictNodes\fR \fB0\fR|\fB1\fR .RS 4 If StrictNodes is set to 1, Tor will treat the ExcludeNodes option as a requirement to follow for all the circuits you generate, even if doing so will break functionality for you\&. If StrictNodes is set to 0, Tor will still try to avoid nodes in the ExcludeNodes list, but it will err on the side of avoiding unexpected errors\&. Specifically, StrictNodes 0 tells Tor that it is okay to use an excluded node when it is \fBnecessary\fR to perform relay reachability self\-tests, connect to a hidden service, provide a hidden service to a client, fulfill a \&.exit request, upload directory information, or download directory information\&. (Default: 0) .RE .PP \fBFascistFirewall\fR \fB0\fR|\fB1\fR .RS 4 If 1, Tor will only create outgoing connections to ORs running on ports that your firewall allows (defaults to 80 and 443; see \fBFirewallPorts\fR)\&. This will allow you to run Tor as a client behind a firewall with restrictive policies, but will not allow you to run as a server behind such a firewall\&. If you prefer more fine\-grained control, use ReachableAddresses instead\&. .RE .PP \fBFirewallPorts\fR \fIPORTS\fR .RS 4 A list of ports that your firewall allows you to connect to\&. Only used when \fBFascistFirewall\fR is set\&. This option is deprecated; use ReachableAddresses instead\&. (Default: 80, 443) .RE .PP \fBReachableAddresses\fR \fIADDR\fR[/\fIMASK\fR][:\fIPORT\fR]\&... .RS 4 A comma\-separated list of IP addresses and ports that your firewall allows you to connect to\&. The format is as for the addresses in ExitPolicy, except that "accept" is understood unless "reject" is explicitly provided\&. For example, \*(AqReachableAddresses 99\&.0\&.0\&.0/8, reject 18\&.0\&.0\&.0/8:80, accept *:80\*(Aq means that your firewall allows connections to everything inside net 99, rejects port 80 connections to net 18, and accepts connections to port 80 otherwise\&. (Default: \*(Aqaccept *:*\*(Aq\&.) .RE .PP \fBReachableDirAddresses\fR \fIADDR\fR[/\fIMASK\fR][:\fIPORT\fR]\&... .RS 4 Like \fBReachableAddresses\fR, a list of addresses and ports\&. Tor will obey these restrictions when fetching directory information, using standard HTTP GET requests\&. If not set explicitly then the value of \fBReachableAddresses\fR is used\&. If \fBHTTPProxy\fR is set then these connections will go through that proxy\&. .RE .PP \fBReachableORAddresses\fR \fIADDR\fR[/\fIMASK\fR][:\fIPORT\fR]\&... .RS 4 Like \fBReachableAddresses\fR, a list of addresses and ports\&. Tor will obey these restrictions when connecting to Onion Routers, using TLS/SSL\&. If not set explicitly then the value of \fBReachableAddresses\fR is used\&. If \fBHTTPSProxy\fR is set then these connections will go through that proxy\&. The separation between \fBReachableORAddresses\fR and \fBReachableDirAddresses\fR is only interesting when you are connecting through proxies (see \fBHTTPProxy\fR and \fBHTTPSProxy\fR)\&. Most proxies limit TLS connections (which Tor uses to connect to Onion Routers) to port 443, and some limit HTTP GET requests (which Tor uses for fetching directory information) to port 80\&. .RE .PP \fBHidServAuth\fR \fIonion\-address\fR \fIauth\-cookie\fR [\fIservice\-name\fR] .RS 4 Client authorization for a hidden service\&. Valid onion addresses contain 16 characters in a\-z2\-7 plus "\&.onion", and valid auth cookies contain 22 characters in A\-Za\-z0\-9+/\&. The service name is only used for internal purposes, e\&.g\&., for Tor controllers\&. This option may be used multiple times for different hidden services\&. If a hidden service uses authorization and this option is not set, the hidden service is not accessible\&. Hidden services can be configured to require authorization using the \fBHiddenServiceAuthorizeClient\fR option\&. .RE .PP \fBCloseHSClientCircuitsImmediatelyOnTimeout\fR \fB0\fR|\fB1\fR .RS 4 If 1, Tor will close unfinished hidden service client circuits which have not moved closer to connecting to their destination hidden service when their internal state has not changed for the duration of the current circuit\-build timeout\&. Otherwise, such circuits will be left open, in the hope that they will finish connecting to their destination hidden services\&. In either case, another set of introduction and rendezvous circuits for the same destination hidden service will be launched\&. (Default: 0) .RE .PP \fBCloseHSServiceRendCircuitsImmediatelyOnTimeout\fR \fB0\fR|\fB1\fR .RS 4 If 1, Tor will close unfinished hidden\-service\-side rendezvous circuits after the current circuit\-build timeout\&. Otherwise, such circuits will be left open, in the hope that they will finish connecting to their destinations\&. In either case, another rendezvous circuit for the same destination client will be launched\&. (Default: 0) .RE .PP \fBLongLivedPorts\fR \fIPORTS\fR .RS 4 A list of ports for services that tend to have long\-running connections (e\&.g\&. chat and interactive shells)\&. Circuits for streams that use these ports will contain only high\-uptime nodes, to reduce the chance that a node will go down before the stream is finished\&. Note that the list is also honored for circuits (both client and service side) involving hidden services whose virtual port is in this list\&. (Default: 21, 22, 706, 1863, 5050, 5190, 5222, 5223, 6523, 6667, 6697, 8300) .RE .PP \fBMapAddress\fR \fIaddress\fR \fInewaddress\fR .RS 4 When a request for address arrives to Tor, it will transform to newaddress before processing it\&. For example, if you always want connections to www\&.example\&.com to exit via \fItorserver\fR (where \fItorserver\fR is the nickname of the server), use "MapAddress www\&.example\&.com www\&.example\&.com\&.torserver\&.exit"\&. If the value is prefixed with a "*\&.", matches an entire domain\&. For example, if you always want connections to example\&.com and any if its subdomains to exit via \fItorserver\fR (where \fItorserver\fR is the nickname of the server), use "MapAddress *\&.example\&.com *\&.example\&.com\&.torserver\&.exit"\&. (Note the leading "*\&." in each part of the directive\&.) You can also redirect all subdomains of a domain to a single address\&. For example, "MapAddress *\&.example\&.com www\&.example\&.com"\&. NOTES: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} When evaluating MapAddress expressions Tor stops when it hits the most recently added expression that matches the requested address\&. So if you have the following in your torrc, www\&.torproject\&.org will map to 1\&.1\&.1\&.1: .sp .if n \{\ .RS 4 .\} .nf MapAddress www\&.torproject\&.org 2\&.2\&.2\&.2 MapAddress www\&.torproject\&.org 1\&.1\&.1\&.1 .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} Tor evaluates the MapAddress configuration until it finds no matches\&. So if you have the following in your torrc, www\&.torproject\&.org will map to 2\&.2\&.2\&.2: .sp .if n \{\ .RS 4 .\} .nf MapAddress 1\&.1\&.1\&.1 2\&.2\&.2\&.2 MapAddress www\&.torproject\&.org 1\&.1\&.1\&.1 .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} The following MapAddress expression is invalid (and will be ignored) because you cannot map from a specific address to a wildcard address: .sp .if n \{\ .RS 4 .\} .nf MapAddress www\&.torproject\&.org *\&.torproject\&.org\&.torserver\&.exit .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} Using a wildcard to match only part of a string (as in *ample\&.com) is also invalid\&. .RE .RE .PP \fBNewCircuitPeriod\fR \fINUM\fR .RS 4 Every NUM seconds consider whether to build a new circuit\&. (Default: 30 seconds) .RE .PP \fBMaxCircuitDirtiness\fR \fINUM\fR .RS 4 Feel free to reuse a circuit that was first used at most NUM seconds ago, but never attach a new stream to a circuit that is too old\&. For hidden services, this applies to the \fIlast\fR time a circuit was used, not the first\&. (Default: 10 minutes) .RE .PP \fBMaxClientCircuitsPending\fR \fINUM\fR .RS 4 Do not allow more than NUM circuits to be pending at a time for handling client streams\&. A circuit is pending if we have begun constructing it, but it has not yet been completely constructed\&. (Default: 32) .RE .PP \fBNodeFamily\fR \fInode\fR,\fInode\fR,\fI\&...\fR .RS 4 The Tor servers, defined by their identity fingerprints or nicknames, constitute a "family" of similar or co\-administered servers, so never use any two of them in the same circuit\&. Defining a NodeFamily is only needed when a server doesn\(cqt list the family itself (with MyFamily)\&. This option can be used multiple times\&. In addition to nodes, you can also list IP address and ranges and country codes in {curly braces}\&. .RE .PP \fBEnforceDistinctSubnets\fR \fB0\fR|\fB1\fR .RS 4 If 1, Tor will not put two servers whose IP addresses are "too close" on the same circuit\&. Currently, two addresses are "too close" if they lie in the same /16 range\&. (Default: 1) .RE .PP \fBSOCKSPort\fR [\fIaddress\fR:]\fIport\fR|\fBauto\fR [\fIflags\fR] [\fIisolation flags\fR] .RS 4 Open this port to listen for connections from SOCKS\-speaking applications\&. Set this to 0 if you don\(cqt want to allow application connections via SOCKS\&. Set it to "auto" to have Tor pick a port for you\&. This directive can be specified multiple times to bind to multiple addresses/ports\&. (Default: 9050) The \fIisolation flags\fR arguments give Tor rules for which streams received on this SOCKSPort are allowed to share circuits with one another\&. Recognized isolation flags are: .PP \fBIsolateClientAddr\fR .RS 4 Don\(cqt share circuits with streams from a different client address\&. (On by default and strongly recommended; you can disable it with \fBNoIsolateClientAddr\fR\&.) .RE .PP \fBIsolateSOCKSAuth\fR .RS 4 Don\(cqt share circuits with streams for which different SOCKS authentication was provided\&. (On by default; you can disable it with \fBNoIsolateSOCKSAuth\fR\&.) .RE .PP \fBIsolateClientProtocol\fR .RS 4 Don\(cqt share circuits with streams using a different protocol\&. (SOCKS 4, SOCKS 5, TransPort connections, NATDPort connections, and DNSPort requests are all considered to be different protocols\&.) .RE .PP \fBIsolateDestPort\fR .RS 4 Don\(cqt share circuits with streams targetting a different destination port\&. .RE .PP \fBIsolateDestAddr\fR .RS 4 Don\(cqt share circuits with streams targetting a different destination address\&. .RE .PP \fBSessionGroup=\fR\fIINT\fR .RS 4 If no other isolation rules would prevent it, allow streams on this port to share circuits with streams from every other port with the same session group\&. (By default, streams received on different SOCKSPorts, TransPorts, etc are always isolated from one another\&. This option overrides that behavior\&.) .sp .if n \{\ .RS 4 .\} .nf Other recognized _flags_ for a SOCKSPort are: **NoIPv4Traffic**;; Tell exits to not connect to IPv4 addresses in response to SOCKS requests on this connection\&. **IPv6Traffic**;; Tell exits to allow IPv6 addresses in response to SOCKS requests on this connection, so long as SOCKS5 is in use\&. (SOCKS4 can\*(Aqt handle IPv6\&.) **PreferIPv6**;; Tells exits that, if a host has both an IPv4 and an IPv6 address, we would prefer to connect to it via IPv6\&. (IPv4 is the default\&.) + .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf NOTE: Although this option allows you to specify an IP address other than localhost, you should do so only with extreme caution\&. The SOCKS protocol is unencrypted and (as we use it) unauthenticated, so exposing it in this way could leak your information to anybody watching your network, and allow anybody to use your computer as an open proxy\&. **CacheIPv4DNS**;; Tells the client to remember IPv4 DNS answers we receive from exit nodes via this connection\&. (On by default\&.) **CacheIPv6DNS**;; Tells the client to remember IPv6 DNS answers we receive from exit nodes via this connection\&. **CacheDNS**;; Tells the client to remember all DNS answers we receive from exit nodes via this connection\&. **UseIPv4Cache**;; Tells the client to use any cached IPv4 DNS answers we have when making requests via this connection\&. (NOTE: This option, along UseIPv6Cache and UseDNSCache, can harm your anonymity, and probably won\*(Aqt help performance as much as you might expect\&. Use with care!) **UseIPv6Cache**;; Tells the client to use any cached IPv6 DNS answers we have when making requests via this connection\&. **UseDNSCache**;; Tells the client to use any cached DNS answers we have when making requests via this connection\&. **PreferIPv6Automap**;; When serving a hostname lookup request on this port that should get automapped (according to AutomapHostsOnResove), if we could return either an IPv4 or an IPv6 answer, prefer an IPv6 answer\&. (On by default\&.) **PreferSOCKSNoAuth**;; Ordinarily, when an application offers both "username/password authentication" and "no authentication" to Tor via SOCKS5, Tor selects username/password authentication so that IsolateSOCKSAuth can work\&. This can confuse some applications, if they offer a username/password combination then get confused when asked for one\&. You can disable this behavior, so that Tor will select "No authentication" when IsolateSOCKSAuth is disabled, or when this option is set\&. .fi .if n \{\ .RE .\} .RE .RE .PP \fBSOCKSListenAddress\fR \fIIP\fR[:\fIPORT\fR] .RS 4 Bind to this address to listen for connections from Socks\-speaking applications\&. (Default: 127\&.0\&.0\&.1) You can also specify a port (e\&.g\&. 192\&.168\&.0\&.1:9100)\&. This directive can be specified multiple times to bind to multiple addresses/ports\&. (DEPRECATED: As of 0\&.2\&.3\&.x\-alpha, you can now use multiple SOCKSPort entries, and provide addresses for SOCKSPort entries, so SOCKSListenAddress no longer has a purpose\&. For backward compatibility, SOCKSListenAddress is only allowed when SOCKSPort is just a port number\&.) .RE .PP \fBSocksPolicy\fR \fIpolicy\fR,\fIpolicy\fR,\fI\&...\fR .RS 4 Set an entrance policy for this server, to limit who can connect to the SocksPort and DNSPort ports\&. The policies have the same form as exit policies below\&. .RE .PP \fBSocksTimeout\fR \fINUM\fR .RS 4 Let a socks connection wait NUM seconds handshaking, and NUM seconds unattached waiting for an appropriate circuit, before we fail it\&. (Default: 2 minutes) .RE .PP \fBTokenBucketRefillInterval\fR \fINUM\fR [\fBmsec\fR|\fBsecond\fR] .RS 4 Set the refill interval of Tor\(cqs token bucket to NUM milliseconds\&. NUM must be between 1 and 1000, inclusive\&. Note that the configured bandwidth limits are still expressed in bytes per second: this option only affects the frequency with which Tor checks to see whether previously exhausted connections may read again\&. (Default: 100 msec) .RE .PP \fBTrackHostExits\fR \fIhost\fR,\fI\&.domain\fR,\fI\&...\fR .RS 4 For each value in the comma separated list, Tor will track recent connections to hosts that match this value and attempt to reuse the same exit node for each\&. If the value is prepended with a \*(Aq\&.\*(Aq, it is treated as matching an entire domain\&. If one of the values is just a \*(Aq\&.\*(Aq, it means match everything\&. This option is useful if you frequently connect to sites that will expire all your authentication cookies (i\&.e\&. log you out) if your IP address changes\&. Note that this option does have the disadvantage of making it more clear that a given history is associated with a single user\&. However, most people who would wish to observe this will observe it through cookies or other protocol\-specific means anyhow\&. .RE .PP \fBTrackHostExitsExpire\fR \fINUM\fR .RS 4 Since exit servers go up and down, it is desirable to expire the association between host and exit server after NUM seconds\&. The default is 1800 seconds (30 minutes)\&. .RE .PP \fBUpdateBridgesFromAuthority\fR \fB0\fR|\fB1\fR .RS 4 When set (along with UseBridges), Tor will try to fetch bridge descriptors from the configured bridge authorities when feasible\&. It will fall back to a direct request if the authority responds with a 404\&. (Default: 0) .RE .PP \fBUseBridges\fR \fB0\fR|\fB1\fR .RS 4 When set, Tor will fetch descriptors for each bridge listed in the "Bridge" config lines, and use these relays as both entry guards and directory guards\&. (Default: 0) .RE .PP \fBUseEntryGuards\fR \fB0\fR|\fB1\fR .RS 4 If this option is set to 1, we pick a few long\-term entry servers, and try to stick with them\&. This is desirable because constantly changing servers increases the odds that an adversary who owns some servers will observe a fraction of your paths\&. (Default: 1) .RE .PP \fBUseEntryGuardsAsDirectoryGuards\fR \fB0\fR|\fB1\fR .RS 4 If this option is set to 1, and UseEntryGuards is also set to 1, we try to use our entry guards as directory guards, and failing that, pick more nodes to act as our directory guards\&. This helps prevent an adversary from enumerating clients\&. It\(cqs only available for clients (non\-relay, non\-bridge) that aren\(cqt configured to download any non\-default directory material\&. It doesn\(cqt currently do anything when we lack a live consensus\&. (Default: 1) .RE .PP \fBNumEntryGuards\fR \fINUM\fR .RS 4 If UseEntryGuards is set to 1, we will try to pick a total of NUM routers as long\-term entries for our circuits\&. (Default: 3) .RE .PP \fBNumDirectoryGuards\fR \fINUM\fR .RS 4 If UseEntryGuardsAsDirectoryGuards is enabled, we try to make sure we have at least NUM routers to use as directory guards\&. If this option is set to 0, use the value from NumEntryGuards\&. (Default: 0) .RE .PP \fBGuardLifetime\fR \fIN\fR \fBdays\fR|\fBweeks\fR|\fBmonths\fR .RS 4 If nonzero, and UseEntryGuards is set, minimum time to keep a guard before picking a new one\&. If zero, we use the GuardLifetime parameter from the consensus directory\&. No value here may be less than 1 month or greater than 5 years; out\-of\-range values are clamped\&. (Default: 0) .RE .PP \fBSafeSocks\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor will reject application connections that use unsafe variants of the socks protocol \(em ones that only provide an IP address, meaning the application is doing a DNS resolve first\&. Specifically, these are socks4 and socks5 when not doing remote DNS\&. (Default: 0) .RE .PP \fBTestSocks\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor will make a notice\-level log entry for each connection to the Socks port indicating whether the request used a safe socks protocol or an unsafe one (see above entry on SafeSocks)\&. This helps to determine whether an application using Tor is possibly leaking DNS requests\&. (Default: 0) .RE .PP \fBWarnUnsafeSocks\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor will warn whenever a request is received that only contains an IP address instead of a hostname\&. Allowing applications to do DNS resolves themselves is usually a bad idea and can leak your location to attackers\&. (Default: 1) .RE .sp \fBVirtualAddrNetworkIPv4\fR \fIAddress\fR/\fIbits\fR .PP \fBVirtualAddrNetworkIPv6\fR [\fIAddress\fR]/\fIbits\fR .RS 4 When Tor needs to assign a virtual (unused) address because of a MAPADDRESS command from the controller or the AutomapHostsOnResolve feature, Tor picks an unassigned address from this range\&. (Defaults: 127\&.192\&.0\&.0/10 and [FE80::]/10 respectively\&.) When providing proxy server service to a network of computers using a tool like dns\-proxy\-tor, change the IPv4 network to "10\&.192\&.0\&.0/10" or "172\&.16\&.0\&.0/12" and change the IPv6 network to "[FC00]/7"\&. The default \fBVirtualAddrNetwork\fR address ranges on a properly configured machine will route to the loopback or link\-local interface\&. For local use, no change to the default VirtualAddrNetwork setting is needed\&. .RE .PP \fBAllowNonRFC953Hostnames\fR \fB0\fR|\fB1\fR .RS 4 When this option is disabled, Tor blocks hostnames containing illegal characters (like @ and :) rather than sending them to an exit node to be resolved\&. This helps trap accidental attempts to resolve URLs and so on\&. (Default: 0) .RE .PP \fBAllowDotExit\fR \fB0\fR|\fB1\fR .RS 4 If enabled, we convert "www\&.google\&.com\&.foo\&.exit" addresses on the SocksPort/TransPort/NATDPort into "www\&.google\&.com" addresses that exit from the node "foo"\&. Disabled by default since attacking websites and exit relays can use it to manipulate your path selection\&. (Default: 0) .RE .PP \fBFastFirstHopPK\fR \fB0\fR|\fB1\fR .RS 4 When this option is disabled, Tor uses the public key step for the first hop of creating circuits\&. Skipping it is generally safe since we have already used TLS to authenticate the relay and to establish forward\-secure keys\&. Turning this option off makes circuit building slower\&. Note that Tor will always use the public key step for the first hop if it\(cqs operating as a relay, and it will never use the public key step if it doesn\(cqt yet know the onion key of the first hop\&. (Default: 1) .RE .PP \fBTransPort\fR [\fIaddress\fR:]\fIport\fR|\fBauto\fR [\fIisolation flags\fR] .RS 4 Open this port to listen for transparent proxy connections\&. Set this to 0 if you don\(cqt want to allow transparent proxy connections\&. Set the port to "auto" to have Tor pick a port for you\&. This directive can be specified multiple times to bind to multiple addresses/ports\&. See SOCKSPort for an explanation of isolation flags\&. TransPort requires OS support for transparent proxies, such as BSDs\*(Aq pf or Linux\(cqs IPTables\&. If you\(cqre planning to use Tor as a transparent proxy for a network, you\(cqll want to examine and change VirtualAddrNetwork from the default setting\&. You\(cqll also want to set the TransListenAddress option for the network you\(cqd like to proxy\&. (Default: 0) .RE .PP \fBTransListenAddress\fR \fIIP\fR[:\fIPORT\fR] .RS 4 Bind to this address to listen for transparent proxy connections\&. (Default: 127\&.0\&.0\&.1)\&. This is useful for exporting a transparent proxy server to an entire network\&. (DEPRECATED: As of 0\&.2\&.3\&.x\-alpha, you can now use multiple TransPort entries, and provide addresses for TransPort entries, so TransListenAddress no longer has a purpose\&. For backward compatibility, TransListenAddress is only allowed when TransPort is just a port number\&.) .RE .PP \fBNATDPort\fR [\fIaddress\fR:]\fIport\fR|\fBauto\fR [\fIisolation flags\fR] .RS 4 Open this port to listen for connections from old versions of ipfw (as included in old versions of FreeBSD, etc) using the NATD protocol\&. Use 0 if you don\(cqt want to allow NATD connections\&. Set the port to "auto" to have Tor pick a port for you\&. This directive can be specified multiple times to bind to multiple addresses/ports\&. See SOCKSPort for an explanation of isolation flags\&. This option is only for people who cannot use TransPort\&. (Default: 0) .RE .PP \fBNATDListenAddress\fR \fIIP\fR[:\fIPORT\fR] .RS 4 Bind to this address to listen for NATD connections\&. (DEPRECATED: As of 0\&.2\&.3\&.x\-alpha, you can now use multiple NATDPort entries, and provide addresses for NATDPort entries, so NATDListenAddress no longer has a purpose\&. For backward compatibility, NATDListenAddress is only allowed when NATDPort is just a port number\&.) .RE .PP \fBAutomapHostsOnResolve\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, and we get a request to resolve an address that ends with one of the suffixes in \fBAutomapHostsSuffixes\fR, we map an unused virtual address to that address, and return the new virtual address\&. This is handy for making "\&.onion" addresses work with applications that resolve an address and then connect to it\&. (Default: 0) .RE .PP \fBAutomapHostsSuffixes\fR \fISUFFIX\fR,\fISUFFIX\fR,\fI\&...\fR .RS 4 A comma\-separated list of suffixes to use with \fBAutomapHostsOnResolve\fR\&. The "\&." suffix is equivalent to "all addresses\&." (Default: \&.exit,\&.onion)\&. .RE .PP \fBDNSPort\fR [\fIaddress\fR:]\fIport\fR|\fBauto\fR [\fIisolation flags\fR] .RS 4 If non\-zero, open this port to listen for UDP DNS requests, and resolve them anonymously\&. This port only handles A, AAAA, and PTR requests\-\-\-it doesn\(cqt handle arbitrary DNS request types\&. Set the port to "auto" to have Tor pick a port for you\&. This directive can be specified multiple times to bind to multiple addresses/ports\&. See SOCKSPort for an explanation of isolation flags\&. (Default: 0) .RE .PP \fBDNSListenAddress\fR \fIIP\fR[:\fIPORT\fR] .RS 4 Bind to this address to listen for DNS connections\&. (DEPRECATED: As of 0\&.2\&.3\&.x\-alpha, you can now use multiple DNSPort entries, and provide addresses for DNSPort entries, so DNSListenAddress no longer has a purpose\&. For backward compatibility, DNSListenAddress is only allowed when DNSPort is just a port number\&.) .RE .PP \fBClientDNSRejectInternalAddresses\fR \fB0\fR|\fB1\fR .RS 4 If true, Tor does not believe any anonymously retrieved DNS answer that tells it that an address resolves to an internal address (like 127\&.0\&.0\&.1 or 192\&.168\&.0\&.1)\&. This option prevents certain browser\-based attacks; don\(cqt turn it off unless you know what you\(cqre doing\&. (Default: 1) .RE .PP \fBClientRejectInternalAddresses\fR \fB0\fR|\fB1\fR .RS 4 If true, Tor does not try to fulfill requests to connect to an internal address (like 127\&.0\&.0\&.1 or 192\&.168\&.0\&.1) \fIunless a exit node is specifically requested\fR (for example, via a \&.exit hostname, or a controller request)\&. (Default: 1) .RE .PP \fBDownloadExtraInfo\fR \fB0\fR|\fB1\fR .RS 4 If true, Tor downloads and caches "extra\-info" documents\&. These documents contain information about servers other than the information in their regular router descriptors\&. Tor does not use this information for anything itself; to save bandwidth, leave this option turned off\&. (Default: 0) .RE .PP \fBWarnPlaintextPorts\fR \fIport\fR,\fIport\fR,\fI\&...\fR .RS 4 Tells Tor to issue a warnings whenever the user tries to make an anonymous connection to one of these ports\&. This option is designed to alert users to services that risk sending passwords in the clear\&. (Default: 23,109,110,143) .RE .PP \fBRejectPlaintextPorts\fR \fIport\fR,\fIport\fR,\fI\&...\fR .RS 4 Like WarnPlaintextPorts, but instead of warning about risky port uses, Tor will instead refuse to make the connection\&. (Default: None) .RE .PP \fBAllowSingleHopCircuits\fR \fB0\fR|\fB1\fR .RS 4 When this option is set, the attached Tor controller can use relays that have the \fBAllowSingleHopExits\fR option turned on to build one\-hop Tor connections\&. (Default: 0) .RE .PP \fBOptimisticData\fR \fB0\fR|\fB1\fR|\fBauto\fR .RS 4 When this option is set, and Tor is using an exit node that supports the feature, it will try optimistically to send data to the exit node without waiting for the exit node to report whether the connection succeeded\&. This can save a round\-trip time for protocols like HTTP where the client talks first\&. If OptimisticData is set to \fBauto\fR, Tor will look at the UseOptimisticData parameter in the networkstatus\&. (Default: auto) .RE .PP \fBTor2webMode\fR \fB0\fR|\fB1\fR .RS 4 When this option is set, Tor connects to hidden services \fBnon\-anonymously\fR\&. This option also disables client connections to non\-hidden\-service hostnames through Tor\&. It \fBmust only\fR be used when running a tor2web Hidden Service web proxy\&. To enable this option the compile time flag \-\-enable\-tor2webmode must be specified\&. (Default: 0) .RE .PP \fBUseMicrodescriptors\fR \fB0\fR|\fB1\fR|\fBauto\fR .RS 4 Microdescriptors are a smaller version of the information that Tor needs in order to build its circuits\&. Using microdescriptors makes Tor clients download less directory information, thus saving bandwidth\&. Directory caches need to fetch regular descriptors and microdescriptors, so this option doesn\(cqt save any bandwidth for them\&. If this option is set to "auto" (recommended) then it is on for all clients that do not set FetchUselessDescriptors\&. (Default: auto) .RE .PP \fBUseNTorHandshake\fR \fB0\fR|\fB1\fR|\fBauto\fR .RS 4 The "ntor" circuit\-creation handshake is faster and (we think) more secure than the original ("TAP") circuit handshake, but starting to use it too early might make your client stand out\&. If this option is 0, your Tor client won\(cqt use the ntor handshake\&. If it\(cqs 1, your Tor client will use the ntor handshake to extend circuits through servers that support it\&. If this option is "auto" (recommended), then your client will use the ntor handshake once enough directory authorities recommend it\&. (Default: auto) .RE .sp \fBPathBiasCircThreshold\fR \fINUM\fR .sp \fBPathBiasNoticeRate\fR \fINUM\fR .sp \fBPathBiasWarnRate\fR \fINUM\fR .sp \fBPathBiasExtremeRate\fR \fINUM\fR .sp \fBPathBiasDropGuards\fR \fINUM\fR .PP \fBPathBiasScaleThreshold\fR \fINUM\fR .RS 4 These options override the default behavior of Tor\(cqs (\fBcurrently experimental\fR) path bias detection algorithm\&. To try to find broken or misbehaving guard nodes, Tor looks for nodes where more than a certain fraction of circuits through that guard fail to get built\&. The PathBiasCircThreshold option controls how many circuits we need to build through a guard before we make these checks\&. The PathBiasNoticeRate, PathBiasWarnRate and PathBiasExtremeRate options control what fraction of circuits must succeed through a guard so we won\(cqt write log messages\&. If less than PathBiasExtremeRate circuits succeed \fBand\fR PathBiasDropGuards is set to 1, we disable use of that guard\&. When we have seen more than PathBiasScaleThreshold circuits through a guard, we scale our observations by 0\&.5 (governed by the consensus) so that new observations don\(cqt get swamped by old ones\&. By default, or if a negative value is provided for one of these options, Tor uses reasonable defaults from the networkstatus consensus document\&. If no defaults are available there, these options default to 150, \&.70, \&.50, \&.30, 0, and 300 respectively\&. .RE .sp \fBPathBiasUseThreshold\fR \fINUM\fR .sp \fBPathBiasNoticeUseRate\fR \fINUM\fR .sp \fBPathBiasExtremeUseRate\fR \fINUM\fR .PP \fBPathBiasScaleUseThreshold\fR \fINUM\fR .RS 4 Similar to the above options, these options override the default behavior of Tor\(cqs (\fBcurrently experimental\fR) path use bias detection algorithm\&. Where as the path bias parameters govern thresholds for successfully building circuits, these four path use bias parameters govern thresholds only for circuit usage\&. Circuits which receive no stream usage are not counted by this detection algorithm\&. A used circuit is considered successful if it is capable of carrying streams or otherwise receiving well\-formed responses to RELAY cells\&. By default, or if a negative value is provided for one of these options, Tor uses reasonable defaults from the networkstatus consensus document\&. If no defaults are available there, these options default to 20, \&.80, \&.60, and 100, respectively\&. .RE .PP \fBClientUseIPv6\fR \fB0\fR|\fB1\fR .RS 4 If this option is set to 1, Tor might connect to entry nodes over IPv6\&. Note that clients configured with an IPv6 address in a \fBBridge\fR line will try connecting over IPv6 even if \fBClientUseIPv6\fR is set to 0\&. (Default: 0) .RE .PP \fBClientPreferIPv6ORPort\fR \fB0\fR|\fB1\fR .RS 4 If this option is set to 1, Tor prefers an OR port with an IPv6 address over one with IPv4 if a given entry node has both\&. Other things may influence the choice\&. This option breaks a tie to the favor of IPv6\&. (Default: 0) .RE .PP \fBPathsNeededToBuildCircuits\fR \fINUM\fR .RS 4 Tor clients don\(cqt build circuits for user traffic until they know about enough of the network so that they could potentially construct enough of the possible paths through the network\&. If this option is set to a fraction between 0\&.25 and 0\&.95, Tor won\(cqt build circuits until it has enough descriptors or microdescriptors to construct that fraction of possible paths\&. Note that setting this option too low can make your Tor client less anonymous, and setting it too high can prevent your Tor client from bootstrapping\&. If this option is negative, Tor will use a default value chosen by the directory authorities\&. (Default: \-1\&.) .RE .PP \fBSupport022HiddenServices\fR \fB0\fR|\fB1\fR|\fBauto\fR .RS 4 Tor hidden services running versions before 0\&.2\&.3\&.x required clients to send timestamps, which can potentially be used to distinguish clients whose view of the current time is skewed\&. If this option is set to 0, we do not send this timestamp, and hidden services on obsolete Tor versions will not work\&. If this option is set to 1, we send the timestamp\&. If this optoin is "auto", we take a recommendation from the latest consensus document\&. (Default: auto) .RE .SH "SERVER OPTIONS" .sp The following options are useful only for servers (that is, if ORPort is non\-zero): .PP \fBAddress\fR \fIaddress\fR .RS 4 The IP address or fully qualified domain name of this server (e\&.g\&. moria\&.mit\&.edu)\&. You can leave this unset, and Tor will guess your IP address\&. This IP address is the one used to tell clients and other servers where to find your Tor server; it doesn\(cqt affect the IP that your Tor client binds to\&. To bind to a different address, use the *ListenAddress and OutboundBindAddress options\&. .RE .PP \fBAllowSingleHopExits\fR \fB0\fR|\fB1\fR .RS 4 This option controls whether clients can use this server as a single hop proxy\&. If set to 1, clients can use this server as an exit even if it is the only hop in the circuit\&. Note that most clients will refuse to use servers that set this option, since most clients have ExcludeSingleHopRelays set\&. (Default: 0) .RE .PP \fBAssumeReachable\fR \fB0\fR|\fB1\fR .RS 4 This option is used when bootstrapping a new Tor network\&. If set to 1, don\(cqt do self\-reachability testing; just upload your server descriptor immediately\&. If \fBAuthoritativeDirectory\fR is also set, this option instructs the dirserver to bypass remote reachability testing too and list all connected servers as running\&. .RE .PP \fBBridgeRelay\fR \fB0\fR|\fB1\fR .RS 4 Sets the relay to act as a "bridge" with respect to relaying connections from bridge users to the Tor network\&. It mainly causes Tor to publish a server descriptor to the bridge database, rather than publishing a relay descriptor to the public directory authorities\&. .RE .PP \fBContactInfo\fR \fIemail_address\fR .RS 4 Administrative contact information for this relay or bridge\&. This line can be used to contact you if your relay or bridge is misconfigured or something else goes wrong\&. Note that we archive and publish all descriptors containing these lines and that Google indexes them, so spammers might also collect them\&. You may want to obscure the fact that it\(cqs an email address and/or generate a new address for this purpose\&. .RE .PP \fBExitPolicy\fR \fIpolicy\fR,\fIpolicy\fR,\fI\&...\fR .RS 4 Set an exit policy for this server\&. Each policy is of the form "\fBaccept\fR|\fBreject\fR \fIADDR\fR[/\fIMASK\fR][:\fIPORT\fR]"\&. If /\fIMASK\fR is omitted then this policy just applies to the host given\&. Instead of giving a host or network you can also use "*" to denote the universe (0\&.0\&.0\&.0/0)\&. \fIPORT\fR can be a single port number, an interval of ports "\fIFROM_PORT\fR\-\fITO_PORT\fR", or "*"\&. If \fIPORT\fR is omitted, that means "*"\&. For example, "accept 18\&.7\&.22\&.69:*,reject 18\&.0\&.0\&.0/8:*,accept *:*" would reject any traffic destined for MIT except for web\&.mit\&.edu, and accept anything else\&. To specify all internal and link\-local networks (including 0\&.0\&.0\&.0/8, 169\&.254\&.0\&.0/16, 127\&.0\&.0\&.0/8, 192\&.168\&.0\&.0/16, 10\&.0\&.0\&.0/8, and 172\&.16\&.0\&.0/12), you can use the "private" alias instead of an address\&. These addresses are rejected by default (at the beginning of your exit policy), along with your public IP address, unless you set the ExitPolicyRejectPrivate config option to 0\&. For example, once you\(cqve done that, you could allow HTTP to 127\&.0\&.0\&.1 and block all other connections to internal networks with "accept 127\&.0\&.0\&.1:80,reject private:*", though that may also allow connections to your own computer that are addressed to its public (external) IP address\&. See RFC 1918 and RFC 3330 for more details about internal and reserved IP address space\&. This directive can be specified multiple times so you don\(cqt have to put it all on one line\&. Policies are considered first to last, and the first match wins\&. If you want to _replace_ the default exit policy, end your exit policy with either a reject *:* or an accept *:*\&. Otherwise, you\(cqre _augmenting_ (prepending to) the default exit policy\&. The default exit policy is: .sp .if n \{\ .RS 4 .\} .nf reject *:25 reject *:119 reject *:135\-139 reject *:445 reject *:563 reject *:1214 reject *:4661\-4666 reject *:6346\-6429 reject *:6699 reject *:6881\-6999 accept *:* .fi .if n \{\ .RE .\} .RE .PP \fBExitPolicyRejectPrivate\fR \fB0\fR|\fB1\fR .RS 4 Reject all private (local) networks, along with your own public IP address, at the beginning of your exit policy\&. See above entry on ExitPolicy\&. (Default: 1) .RE .PP \fBIPv6Exit\fR \fB0\fR|\fB1\fR .RS 4 If set, and we are an exit node, allow clients to use us for IPv6 traffic\&. (Default: 0) .RE .PP \fBMaxOnionQueueDelay\fR \fINUM\fR [\fBmsec\fR|\fBsecond\fR] .RS 4 If we have more onionskins queued for processing than we can process in this amount of time, reject new ones\&. (Default: 1750 msec) .RE .PP \fBMyFamily\fR \fInode\fR,\fInode\fR,\fI\&...\fR .RS 4 Declare that this Tor server is controlled or administered by a group or organization identical or similar to that of the other servers, defined by their identity fingerprints or nicknames\&. When two servers both declare that they are in the same \*(Aqfamily\*(Aq, Tor clients will not use them in the same circuit\&. (Each server only needs to list the other servers in its family; it doesn\(cqt need to list itself, but it won\(cqt hurt\&.) Do not list any bridge relay as it would compromise its concealment\&. When listing a node, it\(cqs better to list it by fingerprint than by nickname: fingerprints are more reliable\&. .RE .PP \fBNickname\fR \fIname\fR .RS 4 Set the server\(cqs nickname to \*(Aqname\*(Aq\&. Nicknames must be between 1 and 19 characters inclusive, and must contain only the characters [a\-zA\-Z0\-9]\&. .RE .PP \fBNumCPUs\fR \fInum\fR .RS 4 How many processes to use at once for decrypting onionskins and other parallelizable operations\&. If this is set to 0, Tor will try to detect how many CPUs you have, defaulting to 1 if it can\(cqt tell\&. (Default: 0) .RE .PP \fBORPort\fR [\fIaddress\fR:]\fIPORT\fR|\fBauto\fR [\fIflags\fR] .RS 4 Advertise this port to listen for connections from Tor clients and servers\&. This option is required to be a Tor server\&. Set it to "auto" to have Tor pick a port for you\&. Set it to 0 to not run an ORPort at all\&. This option can occur more than once\&. (Default: 0) .sp .if n \{\ .RS 4 .\} .nf Tor recognizes these flags on each ORPort: **NoAdvertise**:: By default, we bind to a port and tell our users about it\&. If NoAdvertise is specified, we don\*(Aqt advertise, but listen anyway\&. This can be useful if the port everybody will be connecting to (for example, one that\*(Aqs opened on our firewall) is somewhere else\&. **NoListen**:: By default, we bind to a port and tell our users about it\&. If NoListen is specified, we don\*(Aqt bind, but advertise anyway\&. This can be useful if something else (for example, a firewall\*(Aqs port forwarding configuration) is causing connections to reach us\&. **IPv4Only**:: If the address is absent, or resolves to both an IPv4 and an IPv6 address, only listen to the IPv4 address\&. **IPv6Only**:: If the address is absent, or resolves to both an IPv4 and an IPv6 address, only listen to the IPv6 address\&. .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf For obvious reasons, NoAdvertise and NoListen are mutually exclusive, and IPv4Only and IPv6Only are mutually exclusive\&. .fi .if n \{\ .RE .\} .RE .PP \fBORListenAddress\fR \fIIP\fR[:\fIPORT\fR] .RS 4 Bind to this IP address to listen for connections from Tor clients and servers\&. If you specify a port, bind to this port rather than the one specified in ORPort\&. (Default: 0\&.0\&.0\&.0) This directive can be specified multiple times to bind to multiple addresses/ports\&. .sp .if n \{\ .RS 4 .\} .nf This option is deprecated; you can get the same behavior with ORPort now that it supports NoAdvertise and explicit addresses\&. .fi .if n \{\ .RE .\} .RE .PP \fBPortForwarding\fR \fB0\fR|\fB1\fR .RS 4 Attempt to automatically forward the DirPort and ORPort on a NAT router connecting this Tor server to the Internet\&. If set, Tor will try both NAT\-PMP (common on Apple routers) and UPnP (common on routers from other manufacturers)\&. (Default: 0) .RE .PP \fBPortForwardingHelper\fR \fIfilename\fR|\fIpathname\fR .RS 4 If PortForwarding is set, use this executable to configure the forwarding\&. If set to a filename, the system path will be searched for the executable\&. If set to a path, only the specified path will be executed\&. (Default: tor\-fw\-helper) .RE .PP \fBPublishServerDescriptor\fR \fB0\fR|\fB1\fR|\fBv1\fR|\fBv2\fR|\fBv3\fR|\fBbridge\fR,\fB\&...\fR .RS 4 This option specifies which descriptors Tor will publish when acting as a relay\&. You can choose multiple arguments, separated by commas\&. If this option is set to 0, Tor will not publish its descriptors to any directories\&. (This is useful if you\(cqre testing out your server, or if you\(cqre using a Tor controller that handles directory publishing for you\&.) Otherwise, Tor will publish its descriptors of all type(s) specified\&. The default is "1", which means "if running as a server, publish the appropriate descriptors to the authorities"\&. .RE .PP \fBShutdownWaitLength\fR \fINUM\fR .RS 4 When we get a SIGINT and we\(cqre a server, we begin shutting down: we close listeners and start refusing new circuits\&. After \fBNUM\fR seconds, we exit\&. If we get a second SIGINT, we exit immediately\&. (Default: 30 seconds) .RE .PP \fBSSLKeyLifetime\fR \fIN\fR \fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fR .RS 4 When creating a link certificate for our outermost SSL handshake, set its lifetime to this amount of time\&. If set to 0, Tor will choose some reasonable random defaults\&. (Default: 0) .RE .PP \fBHeartbeatPeriod\fR \fIN\fR \fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fR .RS 4 Log a heartbeat message every \fBHeartbeatPeriod\fR seconds\&. This is a log level \fInotice\fR message, designed to let you know your Tor server is still alive and doing useful things\&. Settings this to 0 will disable the heartbeat\&. (Default: 6 hours) .RE .PP \fBAccountingMax\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR|\fBTBytes\fR .RS 4 Never send more than the specified number of bytes in a given accounting period, or receive more than that number in the period\&. For example, with AccountingMax set to 1 GByte, a server could send 900 MBytes and receive 800 MBytes and continue running\&. It will only hibernate once one of the two reaches 1 GByte\&. When the number of bytes gets low, Tor will stop accepting new connections and circuits\&. When the number of bytes is exhausted, Tor will hibernate until some time in the next accounting period\&. To prevent all servers from waking at the same time, Tor will also wait until a random point in each period before waking up\&. If you have bandwidth cost issues, enabling hibernation is preferable to setting a low bandwidth, since it provides users with a collection of fast servers that are up some of the time, which is more useful than a set of slow servers that are always "available"\&. .RE .PP \fBAccountingStart\fR \fBday\fR|\fBweek\fR|\fBmonth\fR [\fIday\fR] \fIHH:MM\fR .RS 4 Specify how long accounting periods last\&. If \fBmonth\fR is given, each accounting period runs from the time \fIHH:MM\fR on the \fIdayth\fR day of one month to the same day and time of the next\&. (The day must be between 1 and 28\&.) If \fBweek\fR is given, each accounting period runs from the time \fIHH:MM\fR of the \fIdayth\fR day of one week to the same day and time of the next week, with Monday as day 1 and Sunday as day 7\&. If \fBday\fR is given, each accounting period runs from the time \fIHH:MM\fR each day to the same time on the next day\&. All times are local, and given in 24\-hour time\&. (Default: "month 1 0:00") .RE .PP \fBRefuseUnknownExits\fR \fB0\fR|\fB1\fR|\fBauto\fR .RS 4 Prevent nodes that don\(cqt appear in the consensus from exiting using this relay\&. If the option is 1, we always block exit attempts from such nodes; if it\(cqs 0, we never do, and if the option is "auto", then we do whatever the authorities suggest in the consensus (and block if the consensus is quiet on the issue)\&. (Default: auto) .RE .PP \fBServerDNSResolvConfFile\fR \fIfilename\fR .RS 4 Overrides the default DNS configuration with the configuration in \fIfilename\fR\&. The file format is the same as the standard Unix "\fBresolv\&.conf\fR" file (7)\&. This option, like all other ServerDNS options, only affects name lookups that your server does on behalf of clients\&. (Defaults to use the system DNS configuration\&.) .RE .PP \fBServerDNSAllowBrokenConfig\fR \fB0\fR|\fB1\fR .RS 4 If this option is false, Tor exits immediately if there are problems parsing the system DNS configuration or connecting to nameservers\&. Otherwise, Tor continues to periodically retry the system nameservers until it eventually succeeds\&. (Default: 1) .RE .PP \fBServerDNSSearchDomains\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, then we will search for addresses in the local search domain\&. For example, if this system is configured to believe it is in "example\&.com", and a client tries to connect to "www", the client will be connected to "www\&.example\&.com"\&. This option only affects name lookups that your server does on behalf of clients\&. (Default: 0) .RE .PP \fBServerDNSDetectHijacking\fR \fB0\fR|\fB1\fR .RS 4 When this option is set to 1, we will test periodically to determine whether our local nameservers have been configured to hijack failing DNS requests (usually to an advertising site)\&. If they are, we will attempt to correct this\&. This option only affects name lookups that your server does on behalf of clients\&. (Default: 1) .RE .PP \fBServerDNSTestAddresses\fR \fIaddress\fR,\fIaddress\fR,\fI\&...\fR .RS 4 When we\(cqre detecting DNS hijacking, make sure that these \fIvalid\fR addresses aren\(cqt getting redirected\&. If they are, then our DNS is completely useless, and we\(cqll reset our exit policy to "reject \fB:\fR"\&. This option only affects name lookups that your server does on behalf of clients\&. (Default: "www\&.google\&.com, www\&.mit\&.edu, www\&.yahoo\&.com, www\&.slashdot\&.org") .RE .PP \fBServerDNSAllowNonRFC953Hostnames\fR \fB0\fR|\fB1\fR .RS 4 When this option is disabled, Tor does not try to resolve hostnames containing illegal characters (like @ and :) rather than sending them to an exit node to be resolved\&. This helps trap accidental attempts to resolve URLs and so on\&. This option only affects name lookups that your server does on behalf of clients\&. (Default: 0) .RE .PP \fBBridgeRecordUsageByCountry\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled and BridgeRelay is also enabled, and we have GeoIP data, Tor keeps a keep a per\-country count of how many client addresses have contacted it so that it can help the bridge authority guess which countries have blocked access to it\&. (Default: 1) .RE .PP \fBServerDNSRandomizeCase\fR \fB0\fR|\fB1\fR .RS 4 When this option is set, Tor sets the case of each character randomly in outgoing DNS requests, and makes sure that the case matches in DNS replies\&. This so\-called "0x20 hack" helps resist some types of DNS poisoning attack\&. For more information, see "Increased DNS Forgery Resistance through 0x20\-Bit Encoding"\&. This option only affects name lookups that your server does on behalf of clients\&. (Default: 1) .RE .PP \fBGeoIPFile\fR \fIfilename\fR .RS 4 A filename containing IPv4 GeoIP data, for use with by\-country statistics\&. .RE .PP \fBGeoIPv6File\fR \fIfilename\fR .RS 4 A filename containing IPv6 GeoIP data, for use with by\-country statistics\&. .RE .PP \fBTLSECGroup\fR \fBP224\fR|\fBP256\fR .RS 4 What EC group should we try to use for incoming TLS connections? P224 is faster, but makes us stand out more\&. Has no effect if we\(cqre a client, or if our OpenSSL version lacks support for ECDHE\&. (Default: P256) .RE .PP \fBCellStatistics\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor writes statistics on the mean time that cells spend in circuit queues to disk every 24 hours\&. (Default: 0) .RE .PP \fBDirReqStatistics\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, a Tor directory writes statistics on the number and response time of network status requests to disk every 24 hours\&. (Default: 1) .RE .PP \fBEntryStatistics\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor writes statistics on the number of directly connecting clients to disk every 24 hours\&. (Default: 0) .RE .PP \fBExitPortStatistics\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor writes statistics on the number of relayed bytes and opened stream per exit port to disk every 24 hours\&. (Default: 0) .RE .PP \fBConnDirectionStatistics\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor writes statistics on the bidirectional use of connections to disk every 24 hours\&. (Default: 0) .RE .PP \fBExtraInfoStatistics\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor includes previously gathered statistics in its extra\-info documents that it uploads to the directory authorities\&. (Default: 1) .RE .PP \fBExtendAllowPrivateAddresses\fR \fB0\fR|\fB1\fR .RS 4 When this option is enabled, Tor routers allow EXTEND request to localhost, RFC1918 addresses, and so on\&. This can create security issues; you should probably leave it off\&. (Default: 0) .RE .PP \fBMaxMemInCellQueues\fR \fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR .RS 4 This option configures a threshold above which Tor will assume that it needs to stop queueing cells because it\(cqs about to run out of memory\&. If it hits this threshold, it will begin killing circuits until it has recovered at least 10% of this memory\&. Do not set this option too low, or your relay may be unreliable under load\&. This option only affects circuit queues, so the actual process size will be larger than this\&. (Default: 8GB) .RE .SH "DIRECTORY SERVER OPTIONS" .sp The following options are useful only for directory servers (that is, if DirPort is non\-zero): .PP \fBAuthoritativeDirectory\fR \fB0\fR|\fB1\fR .RS 4 When this option is set to 1, Tor operates as an authoritative directory server\&. Instead of caching the directory, it generates its own list of good servers, signs it, and sends that to the clients\&. Unless the clients already have you listed as a trusted directory, you probably do not want to set this option\&. Please coordinate with the other admins at tor\-ops@torproject\&.org if you think you should be a directory\&. .RE .PP \fBDirPortFrontPage\fR \fIFILENAME\fR .RS 4 When this option is set, it takes an HTML file and publishes it as "/" on the DirPort\&. Now relay operators can provide a disclaimer without needing to set up a separate webserver\&. There\(cqs a sample disclaimer in contrib/tor\-exit\-notice\&.html\&. .RE .PP \fBV1AuthoritativeDirectory\fR \fB0\fR|\fB1\fR .RS 4 When this option is set in addition to \fBAuthoritativeDirectory\fR, Tor generates version 1 directory and running\-routers documents (for legacy Tor clients up to 0\&.1\&.0\&.x)\&. .RE .PP \fBV2AuthoritativeDirectory\fR \fB0\fR|\fB1\fR .RS 4 When this option is set in addition to \fBAuthoritativeDirectory\fR, Tor generates version 2 network statuses and serves descriptors, etc as described in doc/spec/dir\-spec\-v2\&.txt (for Tor clients and servers running 0\&.1\&.1\&.x and 0\&.1\&.2\&.x)\&. .RE .PP \fBV3AuthoritativeDirectory\fR \fB0\fR|\fB1\fR .RS 4 When this option is set in addition to \fBAuthoritativeDirectory\fR, Tor generates version 3 network statuses and serves descriptors, etc as described in doc/spec/dir\-spec\&.txt (for Tor clients and servers running at least 0\&.2\&.0\&.x)\&. .RE .PP \fBVersioningAuthoritativeDirectory\fR \fB0\fR|\fB1\fR .RS 4 When this option is set to 1, Tor adds information on which versions of Tor are still believed safe for use to the published directory\&. Each version 1 authority is automatically a versioning authority; version 2 authorities provide this service optionally\&. See \fBRecommendedVersions\fR, \fBRecommendedClientVersions\fR, and \fBRecommendedServerVersions\fR\&. .RE .PP \fBNamingAuthoritativeDirectory\fR \fB0\fR|\fB1\fR .RS 4 When this option is set to 1, then the server advertises that it has opinions about nickname\-to\-fingerprint bindings\&. It will include these opinions in its published network\-status pages, by listing servers with the flag "Named" if a correct binding between that nickname and fingerprint has been registered with the dirserver\&. Naming dirservers will refuse to accept or publish descriptors that contradict a registered binding\&. See \fBapproved\-routers\fR in the \fBFILES\fR section below\&. .RE .PP \fBHSAuthoritativeDir\fR \fB0\fR|\fB1\fR .RS 4 When this option is set in addition to \fBAuthoritativeDirectory\fR, Tor also accepts and serves v0 hidden service descriptors, which are produced and used by Tor 0\&.2\&.1\&.x and older\&. (Default: 0) .RE .PP \fBHidServDirectoryV2\fR \fB0\fR|\fB1\fR .RS 4 When this option is set, Tor accepts and serves v2 hidden service descriptors\&. Setting DirPort is not required for this, because clients connect via the ORPort by default\&. (Default: 1) .RE .PP \fBBridgeAuthoritativeDir\fR \fB0\fR|\fB1\fR .RS 4 When this option is set in addition to \fBAuthoritativeDirectory\fR, Tor accepts and serves router descriptors, but it caches and serves the main networkstatus documents rather than generating its own\&. (Default: 0) .RE .PP \fBMinUptimeHidServDirectoryV2\fR \fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fR .RS 4 Minimum uptime of a v2 hidden service directory to be accepted as such by authoritative directories\&. (Default: 25 hours) .RE .PP \fBDirPort\fR [\fIaddress\fR:]\fIPORT\fR|\fBauto\fR [\fIflags\fR] .RS 4 If this option is nonzero, advertise the directory service on this port\&. Set it to "auto" to have Tor pick a port for you\&. This option can occur more than once\&. (Default: 0) .sp .if n \{\ .RS 4 .\} .nf The same flags are supported here as are supported by ORPort\&. .fi .if n \{\ .RE .\} .RE .PP \fBDirListenAddress\fR \fIIP\fR[:\fIPORT\fR] .RS 4 Bind the directory service to this address\&. If you specify a port, bind to this port rather than the one specified in DirPort\&. (Default: 0\&.0\&.0\&.0) This directive can be specified multiple times to bind to multiple addresses/ports\&. .sp .if n \{\ .RS 4 .\} .nf This option is deprecated; you can get the same behavior with DirPort now that it supports NoAdvertise and explicit addresses\&. .fi .if n \{\ .RE .\} .RE .PP \fBDirPolicy\fR \fIpolicy\fR,\fIpolicy\fR,\fI\&...\fR .RS 4 Set an entrance policy for this server, to limit who can connect to the directory ports\&. The policies have the same form as exit policies above\&. .RE .PP \fBFetchV2Networkstatus\fR \fB0\fR|\fB1\fR .RS 4 If set, we try to fetch the (obsolete, unused) version 2 network status consensus documents from the directory authorities\&. No currently supported Tor version uses them\&. (Default: 0) .RE .SH "DIRECTORY AUTHORITY SERVER OPTIONS" .PP \fBRecommendedVersions\fR \fISTRING\fR .RS 4 STRING is a comma\-separated list of Tor versions currently believed to be safe\&. The list is included in each directory, and nodes which pull down the directory learn whether they need to upgrade\&. This option can appear multiple times: the values from multiple lines are spliced together\&. When this is set then \fBVersioningAuthoritativeDirectory\fR should be set too\&. .RE .PP \fBRecommendedClientVersions\fR \fISTRING\fR .RS 4 STRING is a comma\-separated list of Tor versions currently believed to be safe for clients to use\&. This information is included in version 2 directories\&. If this is not set then the value of \fBRecommendedVersions\fR is used\&. When this is set then \fBVersioningAuthoritativeDirectory\fR should be set too\&. .RE .PP \fBRecommendedServerVersions\fR \fISTRING\fR .RS 4 STRING is a comma\-separated list of Tor versions currently believed to be safe for servers to use\&. This information is included in version 2 directories\&. If this is not set then the value of \fBRecommendedVersions\fR is used\&. When this is set then \fBVersioningAuthoritativeDirectory\fR should be set too\&. .RE .PP \fBConsensusParams\fR \fISTRING\fR .RS 4 STRING is a space\-separated list of key=value pairs that Tor will include in the "params" line of its networkstatus vote\&. .RE .PP \fBDirAllowPrivateAddresses\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, Tor will accept router descriptors with arbitrary "Address" elements\&. Otherwise, if the address is not an IP address or is a private IP address, it will reject the router descriptor\&. (Default: 0) .RE .PP \fBAuthDirBadDir\fR \fIAddressPattern\&...\fR .RS 4 Authoritative directories only\&. A set of address patterns for servers that will be listed as bad directories in any network status document this authority publishes, if \fBAuthDirListBadDirs\fR is set\&. .RE .PP \fBAuthDirBadExit\fR \fIAddressPattern\&...\fR .RS 4 Authoritative directories only\&. A set of address patterns for servers that will be listed as bad exits in any network status document this authority publishes, if \fBAuthDirListBadExits\fR is set\&. .RE .PP \fBAuthDirInvalid\fR \fIAddressPattern\&...\fR .RS 4 Authoritative directories only\&. A set of address patterns for servers that will never be listed as "valid" in any network status document that this authority publishes\&. .RE .PP \fBAuthDirReject\fR \fIAddressPattern\fR\&... .RS 4 Authoritative directories only\&. A set of address patterns for servers that will never be listed at all in any network status document that this authority publishes, or accepted as an OR address in any descriptor submitted for publication by this authority\&. .RE .sp \fBAuthDirBadDirCCs\fR \fICC\fR,\&... .sp \fBAuthDirBadExitCCs\fR \fICC\fR,\&... .sp \fBAuthDirInvalidCCs\fR \fICC\fR,\&... .PP \fBAuthDirRejectCCs\fR \fICC\fR,\&... .RS 4 Authoritative directories only\&. These options contain a comma\-separated list of country codes such that any server in one of those country codes will be marked as a bad directory/bad exit/invalid for use, or rejected entirely\&. .RE .PP \fBAuthDirListBadDirs\fR \fB0\fR|\fB1\fR .RS 4 Authoritative directories only\&. If set to 1, this directory has some opinion about which nodes are unsuitable as directory caches\&. (Do not set this to 1 unless you plan to list non\-functioning directories as bad; otherwise, you are effectively voting in favor of every declared directory\&.) .RE .PP \fBAuthDirListBadExits\fR \fB0\fR|\fB1\fR .RS 4 Authoritative directories only\&. If set to 1, this directory has some opinion about which nodes are unsuitable as exit nodes\&. (Do not set this to 1 unless you plan to list non\-functioning exits as bad; otherwise, you are effectively voting in favor of every declared exit as an exit\&.) .RE .PP \fBAuthDirRejectUnlisted\fR \fB0\fR|\fB1\fR .RS 4 Authoritative directories only\&. If set to 1, the directory server rejects all uploaded server descriptors that aren\(cqt explicitly listed in the fingerprints file\&. This acts as a "panic button" if we get hit with a Sybil attack\&. (Default: 0) .RE .PP \fBAuthDirMaxServersPerAddr\fR \fINUM\fR .RS 4 Authoritative directories only\&. The maximum number of servers that we will list as acceptable on a single IP address\&. Set this to "0" for "no limit"\&. (Default: 2) .RE .PP \fBAuthDirMaxServersPerAuthAddr\fR \fINUM\fR .RS 4 Authoritative directories only\&. Like AuthDirMaxServersPerAddr, but applies to addresses shared with directory authorities\&. (Default: 5) .RE .PP \fBAuthDirFastGuarantee\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 Authoritative directories only\&. If non\-zero, always vote the Fast flag for any relay advertising this amount of capacity or more\&. (Default: 100 KBytes) .RE .PP \fBAuthDirGuardBWGuarantee\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 Authoritative directories only\&. If non\-zero, this advertised capacity or more is always sufficient to satisfy the bandwidth requirement for the Guard flag\&. (Default: 250 KBytes) .RE .PP \fBBridgePassword\fR \fIPassword\fR .RS 4 If set, contains an HTTP authenticator that tells a bridge authority to serve all requested bridge information\&. Used by the (only partially implemented) "bridge community" design, where a community of bridge relay operators all use an alternate bridge directory authority, and their target user audience can periodically fetch the list of available community bridges to stay up\-to\-date\&. (Default: not set) .RE .PP \fBV3AuthVotingInterval\fR \fIN\fR \fBminutes\fR|\fBhours\fR .RS 4 V3 authoritative directories only\&. Configures the server\(cqs preferred voting interval\&. Note that voting will \fIactually\fR happen at an interval chosen by consensus from all the authorities\*(Aq preferred intervals\&. This time SHOULD divide evenly into a day\&. (Default: 1 hour) .RE .PP \fBV3AuthVoteDelay\fR \fIN\fR \fBminutes\fR|\fBhours\fR .RS 4 V3 authoritative directories only\&. Configures the server\(cqs preferred delay between publishing its vote and assuming it has all the votes from all the other authorities\&. Note that the actual time used is not the server\(cqs preferred time, but the consensus of all preferences\&. (Default: 5 minutes) .RE .PP \fBV3AuthDistDelay\fR \fIN\fR \fBminutes\fR|\fBhours\fR .RS 4 V3 authoritative directories only\&. Configures the server\(cqs preferred delay between publishing its consensus and signature and assuming it has all the signatures from all the other authorities\&. Note that the actual time used is not the server\(cqs preferred time, but the consensus of all preferences\&. (Default: 5 minutes) .RE .PP \fBV3AuthNIntervalsValid\fR \fINUM\fR .RS 4 V3 authoritative directories only\&. Configures the number of VotingIntervals for which each consensus should be valid for\&. Choosing high numbers increases network partitioning risks; choosing low numbers increases directory traffic\&. Note that the actual number of intervals used is not the server\(cqs preferred number, but the consensus of all preferences\&. Must be at least 2\&. (Default: 3) .RE .PP \fBV3BandwidthsFile\fR \fIFILENAME\fR .RS 4 V3 authoritative directories only\&. Configures the location of the bandwidth\-authority generated file storing information on relays\*(Aq measured bandwidth capacities\&. (Default: unset) .RE .PP \fBV3AuthUseLegacyKey\fR \fB0\fR|\fB1\fR .RS 4 If set, the directory authority will sign consensuses not only with its own signing key, but also with a "legacy" key and certificate with a different identity\&. This feature is used to migrate directory authority keys in the event of a compromise\&. (Default: 0) .RE .PP \fBRephistTrackTime\fR \fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fR .RS 4 Tells an authority, or other node tracking node reliability and history, that fine\-grained information about nodes can be discarded when it hasn\(cqt changed for a given amount of time\&. (Default: 24 hours) .RE .PP \fBVoteOnHidServDirectoriesV2\fR \fB0\fR|\fB1\fR .RS 4 When this option is set in addition to \fBAuthoritativeDirectory\fR, Tor votes on whether to accept relays as hidden service directories\&. (Default: 1) .RE .PP \fBAuthDirHasIPv6Connectivity\fR \fB0\fR|\fB1\fR .RS 4 Authoritative directories only\&. When set to 0, OR ports with an IPv6 address are being accepted without reachability testing\&. When set to 1, IPv6 OR ports are being tested just like IPv4 OR ports\&. (Default: 0) .RE .SH "HIDDEN SERVICE OPTIONS" .sp The following options are used to configure a hidden service\&. .PP \fBHiddenServiceDir\fR \fIDIRECTORY\fR .RS 4 Store data files for a hidden service in DIRECTORY\&. Every hidden service must have a separate directory\&. You may use this option multiple times to specify multiple services\&. DIRECTORY must be an existing directory\&. .RE .PP \fBHiddenServicePort\fR \fIVIRTPORT\fR [\fITARGET\fR] .RS 4 Configure a virtual port VIRTPORT for a hidden service\&. You may use this option multiple times; each time applies to the service using the most recent hiddenservicedir\&. By default, this option maps the virtual port to the same port on 127\&.0\&.0\&.1 over TCP\&. You may override the target port, address, or both by specifying a target of addr, port, or addr:port\&. You may also have multiple lines with the same VIRTPORT: when a user connects to that VIRTPORT, one of the TARGETs from those lines will be chosen at random\&. .RE .PP \fBPublishHidServDescriptors\fR \fB0\fR|\fB1\fR .RS 4 If set to 0, Tor will run any hidden services you configure, but it won\(cqt advertise them to the rendezvous directory\&. This option is only useful if you\(cqre using a Tor controller that handles hidserv publishing for you\&. (Default: 1) .RE .PP \fBHiddenServiceVersion\fR \fIversion\fR,\fIversion\fR,\fI\&...\fR .RS 4 A list of rendezvous service descriptor versions to publish for the hidden service\&. Currently, only version 2 is supported\&. (Default: 2) .RE .PP \fBHiddenServiceAuthorizeClient\fR \fIauth\-type\fR \fIclient\-name\fR,\fIclient\-name\fR,\fI\&...\fR .RS 4 If configured, the hidden service is accessible for authorized clients only\&. The auth\-type can either be \*(Aqbasic\*(Aq for a general\-purpose authorization protocol or \*(Aqstealth\*(Aq for a less scalable protocol that also hides service activity from unauthorized clients\&. Only clients that are listed here are authorized to access the hidden service\&. Valid client names are 1 to 19 characters long and only use characters in A\-Za\-z0\-9+\-_ (no spaces)\&. If this option is set, the hidden service is not accessible for clients without authorization any more\&. Generated authorization data can be found in the hostname file\&. Clients need to put this authorization data in their configuration file using \fBHidServAuth\fR\&. .RE .PP \fBRendPostPeriod\fR \fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fR .RS 4 Every time the specified period elapses, Tor uploads any rendezvous service descriptors to the directory servers\&. This information is also uploaded whenever it changes\&. (Default: 1 hour) .RE .SH "TESTING NETWORK OPTIONS" .sp The following options are used for running a testing Tor network\&. .PP \fBTestingTorNetwork\fR \fB0\fR|\fB1\fR .RS 4 If set to 1, Tor adjusts default values of the configuration options below, so that it is easier to set up a testing Tor network\&. May only be set if non\-default set of DirAuthorities is set\&. Cannot be unset while Tor is running\&. (Default: 0) .sp .if n \{\ .RS 4 .\} .nf ServerDNSAllowBrokenConfig 1 DirAllowPrivateAddresses 1 EnforceDistinctSubnets 0 AssumeReachable 1 AuthDirMaxServersPerAddr 0 AuthDirMaxServersPerAuthAddr 0 ClientDNSRejectInternalAddresses 0 ClientRejectInternalAddresses 0 CountPrivateBandwidth 1 ExitPolicyRejectPrivate 0 ExtendAllowPrivateAddresses 1 V3AuthVotingInterval 5 minutes V3AuthVoteDelay 20 seconds V3AuthDistDelay 20 seconds MinUptimeHidServDirectoryV2 0 seconds TestingV3AuthInitialVotingInterval 5 minutes TestingV3AuthInitialVoteDelay 20 seconds TestingV3AuthInitialDistDelay 20 seconds TestingAuthDirTimeToLearnReachability 0 minutes TestingEstimatedDescriptorPropagationTime 0 minutes .fi .if n \{\ .RE .\} .RE .PP \fBTestingV3AuthInitialVotingInterval\fR \fIN\fR \fBminutes\fR|\fBhours\fR .RS 4 Like V3AuthVotingInterval, but for initial voting interval before the first consensus has been created\&. Changing this requires that \fBTestingTorNetwork\fR is set\&. (Default: 30 minutes) .RE .PP \fBTestingV3AuthInitialVoteDelay\fR \fIN\fR \fBminutes\fR|\fBhours\fR .RS 4 Like V3AuthVoteDelay, but for initial voting interval before the first consensus has been created\&. Changing this requires that \fBTestingTorNetwork\fR is set\&. (Default: 5 minutes) .RE .PP \fBTestingV3AuthInitialDistDelay\fR \fIN\fR \fBminutes\fR|\fBhours\fR .RS 4 Like V3AuthDistDelay, but for initial voting interval before the first consensus has been created\&. Changing this requires that \fBTestingTorNetwork\fR is set\&. (Default: 5 minutes) .RE .PP \fBTestingAuthDirTimeToLearnReachability\fR \fIN\fR \fBminutes\fR|\fBhours\fR .RS 4 After starting as an authority, do not make claims about whether routers are Running until this much time has passed\&. Changing this requires that \fBTestingTorNetwork\fR is set\&. (Default: 30 minutes) .RE .PP \fBTestingEstimatedDescriptorPropagationTime\fR \fIN\fR \fBminutes\fR|\fBhours\fR .RS 4 Clients try downloading router descriptors from directory caches after this time\&. Changing this requires that \fBTestingTorNetwork\fR is set\&. (Default: 10 minutes) .RE .PP \fBTestingMinFastFlagThreshold\fR \fIN\fR \fBbytes\fR|\fBKBytes\fR|\fBMBytes\fR|\fBGBytes\fR .RS 4 Minimum value for the Fast flag\&. Overrides the ordinary minimum taken from the consensus when TestingTorNetwork is set\&. (Default: 0\&.) .RE .SH "SIGNALS" .sp Tor catches the following signals: .PP \fBSIGTERM\fR .RS 4 Tor will catch this, clean up and sync to disk if necessary, and exit\&. .RE .PP \fBSIGINT\fR .RS 4 Tor clients behave as with SIGTERM; but Tor servers will do a controlled slow shutdown, closing listeners and waiting 30 seconds before exiting\&. (The delay can be configured with the ShutdownWaitLength config option\&.) .RE .PP \fBSIGHUP\fR .RS 4 The signal instructs Tor to reload its configuration (including closing and reopening logs), and kill and restart its helper processes if applicable\&. .RE .PP \fBSIGUSR1\fR .RS 4 Log statistics about current connections, past connections, and throughput\&. .RE .PP \fBSIGUSR2\fR .RS 4 Switch all logs to loglevel debug\&. You can go back to the old loglevels by sending a SIGHUP\&. .RE .PP \fBSIGCHLD\fR .RS 4 Tor receives this signal when one of its helper processes has exited, so it can clean up\&. .RE .PP \fBSIGPIPE\fR .RS 4 Tor catches this signal and ignores it\&. .RE .PP \fBSIGXFSZ\fR .RS 4 If this signal exists on your platform, Tor catches and ignores it\&. .RE .SH "FILES" .PP \fB@CONFDIR@/torrc\fR .RS 4 The configuration file, which contains "option value" pairs\&. .RE .PP \fB@LOCALSTATEDIR@/lib/tor/\fR .RS 4 The tor process stores keys and other data here\&. .RE .PP \fIDataDirectory\fR\fB/cached\-status/\fR .RS 4 The most recently downloaded network status document for each authority\&. Each file holds one such document; the filenames are the hexadecimal identity key fingerprints of the directory authorities\&. Mostly obsolete\&. .RE .PP \fIDataDirectory\fR\fB/cached\-consensus\fR and/or \fBcached\-microdesc\-consensus\fR .RS 4 The most recent consensus network status document we\(cqve downloaded\&. .RE .PP \fIDataDirectory\fR\fB/cached\-descriptors\fR and \fBcached\-descriptors\&.new\fR .RS 4 These files hold downloaded router statuses\&. Some routers may appear more than once; if so, the most recently published descriptor is used\&. Lines beginning with @\-signs are annotations that contain more information about a given router\&. The "\&.new" file is an append\-only journal; when it gets too large, all entries are merged into a new cached\-descriptors file\&. .RE .PP \fIDataDirectory\fR\fB/cached\-microdescs\fR and \fBcached\-microdescs\&.new\fR .RS 4 These files hold downloaded microdescriptors\&. Lines beginning with @\-signs are annotations that contain more information about a given router\&. The "\&.new" file is an append\-only journal; when it gets too large, all entries are merged into a new cached\-microdescs file\&. .RE .PP \fIDataDirectory\fR\fB/cached\-routers\fR and \fBcached\-routers\&.new\fR .RS 4 Obsolete versions of cached\-descriptors and cached\-descriptors\&.new\&. When Tor can\(cqt find the newer files, it looks here instead\&. .RE .PP \fIDataDirectory\fR\fB/state\fR .RS 4 A set of persistent key\-value mappings\&. These are documented in the file\&. These include: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The current entry guards and their status\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The current bandwidth accounting values (unused so far; see below)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} When the file was last written .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} What version of Tor generated the state file .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} A short history of bandwidth usage, as produced in the router descriptors\&. .RE .RE .PP \fIDataDirectory\fR\fB/bw_accounting\fR .RS 4 Used to track bandwidth accounting values (when the current period starts and ends; how much has been read and written so far this period)\&. This file is obsolete, and the data is now stored in the \*(Aqstate\*(Aq file as well\&. Only used when bandwidth accounting is enabled\&. .RE .PP \fIDataDirectory\fR\fB/control_auth_cookie\fR .RS 4 Used for cookie authentication with the controller\&. Location can be overridden by the CookieAuthFile config option\&. Regenerated on startup\&. See control\-spec\&.txt for details\&. Only used when cookie authentication is enabled\&. .RE .PP \fIDataDirectory\fR\fB/keys/\fR* .RS 4 Only used by servers\&. Holds identity keys and onion keys\&. .RE .PP \fIDataDirectory\fR\fB/fingerprint\fR .RS 4 Only used by servers\&. Holds the fingerprint of the server\(cqs identity key\&. .RE .PP \fIDataDirectory\fR\fB/approved\-routers\fR .RS 4 Only for naming authoritative directory servers (see \fBNamingAuthoritativeDirectory\fR)\&. This file lists nickname to identity bindings\&. Each line lists a nickname and a fingerprint separated by whitespace\&. See your \fBfingerprint\fR file in the \fIDataDirectory\fR for an example line\&. If the nickname is \fB!reject\fR then descriptors from the given identity (fingerprint) are rejected by this server\&. If it is \fB!invalid\fR then descriptors are accepted but marked in the directory as not valid, that is, not recommended\&. .RE .PP \fIDataDirectory\fR\fB/router\-stability\fR .RS 4 Only used by authoritative directory servers\&. Tracks measurements for router mean\-time\-between\-failures so that authorities have a good idea of how to set their Stable flags\&. .RE .PP \fIHiddenServiceDirectory\fR\fB/hostname\fR .RS 4 The \&.onion domain name for this hidden service\&. If the hidden service is restricted to authorized clients only, this file also contains authorization data for all clients\&. .RE .PP \fIHiddenServiceDirectory\fR\fB/private_key\fR .RS 4 The private key for this hidden service\&. .RE .PP \fIHiddenServiceDirectory\fR\fB/client_keys\fR .RS 4 Authorization data for a hidden service that is only accessible by authorized clients\&. .RE .SH "SEE ALSO" .sp \fBprivoxy\fR(1), \fBtorsocks\fR(1), \fBtorify\fR(1) .sp \fBhttps://www\&.torproject\&.org/\fR .SH "BUGS" .sp Plenty, probably\&. Tor is still in development\&. Please report them\&. .SH "AUTHORS" .sp Roger Dingledine [arma at mit\&.edu], Nick Mathewson [nickm at alum\&.mit\&.edu]\&. tor-0.2.4.20/doc/tor-gencert.1.txt0000644000175000017500000000610012153762274013366 00000000000000// Copyright (c) The Tor Project, Inc. // See LICENSE for licensing information // This is an asciidoc file used to generate the manpage/html reference. // Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html :man source: Tor :man manual: Tor Manual tor-gencert(1) ============== Nick Mathewson NAME ---- tor-gencert - Generate certs and keys for Tor directory authorities SYNOPSIS -------- **tor-gencert** [-h|--help] [-v] [-r|--reuse] [--create-identity-key] [-i __id_file__] [-c __cert_file__] [-m __num__] [-a __address__:__port__] DESCRIPTION ----------- **tor-gencert** generates certificates and private keys for use by Tor directory authorities running the v3 Tor directory protocol, as used by Tor 0.2.0 and later. If you are not running a directory authority, you don't need to use tor-gencert. + Every directory authority has a long term authority __identity__ __key__ (which is distinct from the identity key it uses as a Tor server); this key should be kept offline in a secure location. It is used to certify shorter-lived __signing__ __keys__, which are kept online and used by the directory authority to sign votes and consensus documents. + After you use this program to generate a signing key and a certificate, copy those files to the keys subdirectory of your Tor process, and send Tor a SIGHUP signal. DO NOT COPY THE IDENTITY KEY. OPTIONS ------- **-v**:: Display verbose output. **-h** or **--help**:: Display help text and exit. **-r** or **--reuse**:: Generate a new certificate, but not a new signing key. This can be used to change the address or lifetime associated with a given key. **--create-identity-key**:: Generate a new identity key. You should only use this option the first time you run tor-gencert; in the future, you should use the identity key that's already there. **-i** __FILENAME__:: Read the identity key from the specified file. If the file is not present and --create-identity-key is provided, create the identity key in the specified file. Default: "./authority_identity_key" **-s** __FILENAME__:: Write the signing key to the specified file. Default: "./authority_signing_key" **-c** __FILENAME__:: Write the certificate to the specified file. Default: "./authority_certificate" **-m** __NUM__:: Number of months that the certificate should be valid. Default: 12. **--passphrase-fd** __FILEDES__:: Filedescriptor to read the file descriptor from. Ends at the first NUL or newline. Default: read from the terminal. **-a** __address__:__port__:: If provided, advertise the address:port combination as this authority's preferred directory port in its certificate. If the address is a hostname, the hostname is resolved to an IP before it's published. BUGS ---- This probably doesn't run on Windows. That's not a big issue, since we don't really want authorities to be running on Windows anyway. SEE ALSO -------- **tor**(1) + See also the "dir-spec.txt" file, distributed with Tor. AUTHORS ------- Roger Dingledine , Nick Mathewson . tor-0.2.4.20/doc/tor-gencert.html.in0000644000175000017500000005126212164363325013766 00000000000000 tor-gencert(1)

SYNOPSIS

tor-gencert [-h|--help] [-v] [-r|--reuse] [--create-identity-key] [-i id_file] [-c cert_file] [-m num] [-a address:port]

DESCRIPTION

tor-gencert generates certificates and private keys for use by Tor directory authorities running the v3 Tor directory protocol, as used by Tor 0.2.0 and later. If you are not running a directory authority, you don’t need to use tor-gencert.

Every directory authority has a long term authority identity key (which is distinct from the identity key it uses as a Tor server); this key should be kept offline in a secure location. It is used to certify shorter-lived signing keys, which are kept online and used by the directory authority to sign votes and consensus documents.

After you use this program to generate a signing key and a certificate, copy those files to the keys subdirectory of your Tor process, and send Tor a SIGHUP signal. DO NOT COPY THE IDENTITY KEY.

OPTIONS

-v

Display verbose output.

-h or --help

Display help text and exit.

-r or --reuse

Generate a new certificate, but not a new signing key. This can be used to change the address or lifetime associated with a given key.

--create-identity-key

Generate a new identity key. You should only use this option the first time you run tor-gencert; in the future, you should use the identity key that’s already there.

-i FILENAME

Read the identity key from the specified file. If the file is not present and --create-identity-key is provided, create the identity key in the specified file. Default: "./authority_identity_key"

-s FILENAME

Write the signing key to the specified file. Default: "./authority_signing_key"

-c FILENAME

Write the certificate to the specified file. Default: "./authority_certificate"

-m NUM

Number of months that the certificate should be valid. Default: 12.

--passphrase-fd FILEDES

Filedescriptor to read the file descriptor from. Ends at the first NUL or newline. Default: read from the terminal.

-a address:port

If provided, advertise the address:port combination as this authority’s preferred directory port in its certificate. If the address is a hostname, the hostname is resolved to an IP before it’s published.

BUGS

This probably doesn’t run on Windows. That’s not a big issue, since we don’t really want authorities to be running on Windows anyway.

SEE ALSO

tor(1)

See also the "dir-spec.txt" file, distributed with Tor.

AUTHORS

Roger Dingledine <arma@mit.edu>, Nick Mathewson <nickm@alum.mit.edu>.

tor-0.2.4.20/doc/tor-fw-helper.1.in0000644000175000017500000000555112170370161013415 00000000000000'\" t .\" Title: tor-fw-helper .\" Author: Jacob Appelbaum .\" Generator: DocBook XSL Stylesheets v1.76.1 .\" Date: 07/13/2013 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" .TH "TOR\-FW\-HELPER" "1" "07/13/2013" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" tor-fw-helper \- Manage upstream firewall/NAT devices .SH "SYNOPSIS" .sp \fBtor\-fw\-helper\fR [\-h|\-\-help] [\-T|\-\-test\-commandline] [\-v|\-\-verbose] [\-g|\-\-fetch\-public\-ip] [\-p \fIexternal port\fR:\fIinternal_port\fR] .SH "DESCRIPTION" .sp \fBtor\-fw\-helper\fR currently supports Apple\(cqs NAT\-PMP protocol and the UPnP standard for TCP port mapping\&. It is written as the reference implementation of tor\-fw\-helper\-spec\&.txt and conforms to that loose plugin API\&. If your network supports either NAT\-PMP or UPnP, tor\-fw\-helper will attempt to automatically map the required TCP ports for Tor\(cqs Or and Dir ports\&. .SH "OPTIONS" .PP \fB\-h\fR or \fB\-\-help\fR .RS 4 Display help text and exit\&. .RE .PP \fB\-v\fR or \fB\-\-verbose\fR .RS 4 Display verbose output\&. .RE .PP \fB\-T\fR or \fB\-\-test\-commandline\fR .RS 4 Display test information and print the test information in tor\-fw\-helper\&.log .RE .PP \fB\-g\fR or \fB\-\-fetch\-public\-ip\fR .RS 4 Fetch the the public ip address for each supported NAT helper method\&. .RE .PP \fB\-p\fR or \fB\-\-port\fR \fIexternal_port\fR:\fIinternal_port\fR .RS 4 Forward external_port to internal_port\&. This option can appear more than once\&. .RE .SH "BUGS" .sp This probably doesn\(cqt run on Windows\&. That\(cqs not a big issue, since we don\(cqt really want to deal with Windows before October 2010 anyway\&. .SH "SEE ALSO" .sp \fBtor\fR(1) .sp See also the "tor\-fw\-helper\-spec\&.txt" file, distributed with Tor\&. .SH "AUTHORS" .sp .if n \{\ .RS 4 .\} .nf Jacob Appelbaum , Steven J\&. Murdoch .fi .if n \{\ .RE .\} .SH "AUTHOR" .PP \fBJacob Appelbaum\fR .RS 4 Author. .RE tor-0.2.4.20/doc/tor.1.txt0000644000175000017500000034632612255745673011771 00000000000000// Copyright (c) The Tor Project, Inc. // See LICENSE for licensing information // This is an asciidoc file used to generate the manpage/html reference. // Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html :man source: Tor :man manual: Tor Manual TOR(1) ====== NAME ---- tor - The second-generation onion router SYNOPSIS -------- **tor** [__OPTION__ __value__]... DESCRIPTION ----------- __tor__ is a connection-oriented anonymizing communication service. Users choose a source-routed path through a set of nodes, and negotiate a "virtual circuit" through the network, in which each node knows its predecessor and successor, but no others. Traffic flowing down the circuit is unwrapped by a symmetric key at each node, which reveals the downstream node. + Basically __tor__ provides a distributed network of servers ("onion routers"). Users bounce their TCP streams -- web traffic, ftp, ssh, etc -- around the routers, and recipients, observers, and even the routers themselves have difficulty tracking the source of the stream. COMMAND-LINE OPTIONS -------------------- [[opt-h]] **-h**, **-help**:: Display a short help message and exit. [[opt-f]] **-f** __FILE__:: Specify a new configuration file to contain further Tor configuration options. (Default: $HOME/.torrc, or @CONFDIR@/torrc if that file is not found) [[opt-defaults-torrc]] **--defaults-torrc** __FILE__:: Specify a file in which to find default values for Tor options. The contents of this file are overridden by those in the regular configuration file, and by those on the command line. (Default: @CONFDIR@/torrc-defaults.) [[opt-hash-password]] **--hash-password**:: Generates a hashed password for control port access. [[opt-list-fingerprint]] **--list-fingerprint**:: Generate your keys and output your nickname and fingerprint. [[opt-verify-config]] **--verify-config**:: Verify the configuration file is valid. [[opt-serviceinstall]] **--service install** [**--options** __command-line options__]:: Install an instance of Tor as a Windows service, with the provided command-line options. Current instructions can be found at https://trac.torproject.org/projects/tor/wiki/doc/TorFAQ#HowdoIrunmyTorrelayasanNTservice [[opt-service]] **--service** **remove**|**start**|**stop**:: Remove, start, or stop a configured Tor Windows service. [[opt-nt-service]] **--nt-service**:: Used internally to implement a Windows service. [[opt-list-torrc-options]] **--list-torrc-options**:: List all valid options. [[opt-version]] **--version**:: Display Tor version and exit. [[opt-quiet]] **--quiet**|**--hush**:: Override the default console log. By default, Tor starts out logging messages at level "notice" and higher to the console. It stops doing so after it parses its configuration, if the configuration tells it to log anywhere else. You can override this behavior with the **--hush** option, which tells Tor to only send warnings and errors to the console, or with the **--quiet** option, which tells Tor not to log to the console at all. Other options can be specified on the command-line in the format "--option value", in the format "option value", or in a configuration file. For instance, you can tell Tor to start listening for SOCKS connections on port 9999 by passing --SOCKSPort 9999 or SOCKSPort 9999 to it on the command line, or by putting "SOCKSPort 9999" in the configuration file. You will need to quote options with spaces in them: if you want Tor to log all debugging messages to debug.log, you will probably need to say --Log 'debug file debug.log'. Options on the command line override those in configuration files. See the next section for more information. THE CONFIGURATION FILE FORMAT ----------------------------- All configuration options in a configuration are written on a single line by default. They take the form of an option name and a value, or an option name and a quoted value (option value or option "value"). Anything after a # character is treated as a comment. Options are case-insensitive. C-style escaped characters are allowed inside quoted values. To split one configuration entry into multiple lines, use a single backslash character (\) before the end of the line. Comments can be used in such multiline entries, but they must start at the beginning of a line. By default, an option on the command line overrides an option found in the configuration file, and an option in a configuration file overrides one in the defaults file. This rule is simple for options that take a single value, but it can become complicated for options that are allowed to occur more than once: if you specify four SOCKSPorts in your configuration file, and one more SOCKSPort on the command line, the option on the command line will replace __all__ of the SOCKSPorts in the configuration file. If this isn't what you want, prefix the option name with a plus sign, and it will be appended to the previous set of options instead. Alternatively, you might want to remove every instance of an option in the configuration file, and not replace it at all: you might want to say on the command line that you want no SOCKSPorts at all. To do that, prefix the option name with a forward slash. GENERAL OPTIONS --------------- [[BandwidthRate]] **BandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: A token bucket limits the average incoming bandwidth usage on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value. If you want to run a relay in the public network, this needs to be _at the very least_ 30 KBytes (that is, 30720 bytes). (Default: 1 GByte) [[BandwidthBurst]] **BandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: Limit the maximum token bucket size (also known as the burst) to the given number of bytes in each direction. (Default: 1 GByte) [[MaxAdvertisedBandwidth]] **MaxAdvertisedBandwidth** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: If set, we will not advertise more than this amount of bandwidth for our BandwidthRate. Server operators who want to reduce the number of clients who ask to build circuits through them (since this is proportional to advertised bandwidth rate) can thus reduce the CPU demands on their server without impacting network performance. [[RelayBandwidthRate]] **RelayBandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: If not 0, a separate token bucket limits the average incoming bandwidth usage for \_relayed traffic_ on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value. Relayed traffic currently is calculated to include answers to directory requests, but that may change in future versions. (Default: 0) [[RelayBandwidthBurst]] **RelayBandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: If not 0, limit the maximum token bucket size (also known as the burst) for \_relayed traffic_ to the given number of bytes in each direction. (Default: 0) [[PerConnBWRate]] **PerConnBWRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: If set, do separate rate limiting for each connection from a non-relay. You should never need to change this value, since a network-wide value is published in the consensus and your relay will use that value. (Default: 0) [[PerConnBWBurst]] **PerConnBWBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: If set, do separate rate limiting for each connection from a non-relay. You should never need to change this value, since a network-wide value is published in the consensus and your relay will use that value. (Default: 0) [[ClientTransportPlugin]] **ClientTransportPlugin** __transport__ socks4|socks5 __IP__:__PORT__:: **ClientTransportPlugin** __transport__ exec __path-to-binary__ [options]:: In its first form, when set along with a corresponding Bridge line, the Tor client forwards its traffic to a SOCKS-speaking proxy on "IP:PORT". It's the duty of that proxy to properly forward the traffic to the bridge. + + In its second form, when set along with a corresponding Bridge line, the Tor client launches the pluggable transport proxy executable in __path-to-binary__ using __options__ as its command-line options, and forwards its traffic to it. It's the duty of that proxy to properly forward the traffic to the bridge. [[ServerTransportPlugin]] **ServerTransportPlugin** __transport__ exec __path-to-binary__ [options]:: The Tor relay launches the pluggable transport proxy in __path-to-binary__ using __options__ as its command-line options, and expects to receive proxied client traffic from it. [[ServerTransportListenAddr]] **ServerTransportListenAddr** __transport__ __IP__:__PORT__:: When this option is set, Tor will suggest __IP__:__PORT__ as the listening address of any pluggable transport proxy that tries to launch __transport__. [[ConnLimit]] **ConnLimit** __NUM__:: The minimum number of file descriptors that must be available to the Tor process before it will start. Tor will ask the OS for as many file descriptors as the OS will allow (you can find this by "ulimit -H -n"). If this number is less than ConnLimit, then Tor will refuse to start. + + You probably don't need to adjust this. It has no effect on Windows since that platform lacks getrlimit(). (Default: 1000) [[DisableNetwork]] **DisableNetwork** **0**|**1**:: When this option is set, we don't listen for or accept any connections other than controller connections, and we don't make any outbound connections. Controllers sometimes use this option to avoid using the network until Tor is fully configured. (Default: 0) [[ConstrainedSockets]] **ConstrainedSockets** **0**|**1**:: If set, Tor will tell the kernel to attempt to shrink the buffers for all sockets to the size specified in **ConstrainedSockSize**. This is useful for virtual servers and other environments where system level TCP buffers may be limited. If you're on a virtual server, and you encounter the "Error creating network socket: No buffer space available" message, you are likely experiencing this problem. + + The preferred solution is to have the admin increase the buffer pool for the host itself via /proc/sys/net/ipv4/tcp_mem or equivalent facility; this configuration option is a second-resort. + + The DirPort option should also not be used if TCP buffers are scarce. The cached directory requests consume additional sockets which exacerbates the problem. + + You should **not** enable this feature unless you encounter the "no buffer space available" issue. Reducing the TCP buffers affects window size for the TCP stream and will reduce throughput in proportion to round trip time on long paths. (Default: 0) [[ConstrainedSockSize]] **ConstrainedSockSize** __N__ **bytes**|**KBytes**:: When **ConstrainedSockets** is enabled the receive and transmit buffers for all sockets will be set to this limit. Must be a value between 2048 and 262144, in 1024 byte increments. Default of 8192 is recommended. [[ControlPort]] **ControlPort** __PORT__|**auto**:: If set, Tor will accept connections on this port and allow those connections to control the Tor process using the Tor Control Protocol (described in control-spec.txt). Note: unless you also specify one or more of **HashedControlPassword** or **CookieAuthentication**, setting this option will cause Tor to allow any process on the local host to control it. (Setting both authentication methods means either method is sufficient to authenticate to Tor.) This option is required for many Tor controllers; most use the value of 9051. Set it to "auto" to have Tor pick a port for you. (Default: 0) [[ControlListenAddress]] **ControlListenAddress** __IP__[:__PORT__]:: Bind the controller listener to this address. If you specify a port, bind to this port rather than the one specified in ControlPort. We strongly recommend that you leave this alone unless you know what you're doing, since giving attackers access to your control listener is really dangerous. This directive can be specified multiple times to bind to multiple addresses/ports. (Default: 127.0.0.1) [[ControlSocket]] **ControlSocket** __Path__:: Like ControlPort, but listens on a Unix domain socket, rather than a TCP socket. (Unix and Unix-like systems only.) [[ControlSocketsGroupWritable]] **ControlSocketsGroupWritable** **0**|**1**:: If this option is set to 0, don't allow the filesystem group to read and write unix sockets (e.g. ControlSocket). If the option is set to 1, make the control socket readable and writable by the default GID. (Default: 0) [[HashedControlPassword]] **HashedControlPassword** __hashed_password__:: Allow connections on the control port if they present the password whose one-way hash is __hashed_password__. You can compute the hash of a password by running "tor --hash-password __password__". You can provide several acceptable passwords by using more than one HashedControlPassword line. [[CookieAuthentication]] **CookieAuthentication** **0**|**1**:: If this option is set to 1, allow connections on the control port when the connecting process knows the contents of a file named "control_auth_cookie", which Tor will create in its data directory. This authentication method should only be used on systems with good filesystem security. (Default: 0) [[CookieAuthFile]] **CookieAuthFile** __Path__:: If set, this option overrides the default location and file name for Tor's cookie file. (See CookieAuthentication above.) [[CookieAuthFileGroupReadable]] **CookieAuthFileGroupReadable** **0**|**1**|__Groupname__:: If this option is set to 0, don't allow the filesystem group to read the cookie file. If the option is set to 1, make the cookie file readable by the default GID. [Making the file readable by other groups is not yet implemented; let us know if you need this for some reason.] (Default: 0) [[ControlPortWriteToFile]] **ControlPortWriteToFile** __Path__:: If set, Tor writes the address and port of any control port it opens to this address. Usable by controllers to learn the actual control port when ControlPort is set to "auto". [[ControlPortFileGroupReadable]] **ControlPortFileGroupReadable** **0**|**1**:: If this option is set to 0, don't allow the filesystem group to read the control port file. If the option is set to 1, make the control port file readable by the default GID. (Default: 0) [[DataDirectory]] **DataDirectory** __DIR__:: Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor) [[FallbackDir]] **FallbackDir** __address__:__port__ orport=__port__ id=__fingerprint__ [weight=__num__]:: When we're unable to connect to any directory cache for directory info (usually because we don't know about any yet) we try a FallbackDir. By default, the directory authorities are also FallbackDirs. [[DirAuthority]] **DirAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__:: Use a nonstandard authoritative directory server at the provided address and port, with the specified key fingerprint. This option can be repeated many times, for multiple authoritative directory servers. Flags are separated by spaces, and determine what kind of an authority this directory is. By default, every authority is authoritative for current ("v2")-style directories, unless the "no-v2" flag is given. If the "v1" flags is provided, Tor will use this server as an authority for old-style (v1) directories as well. (Only directory mirrors care about this.) Tor will use this server as an authority for hidden service information if the "hs" flag is set, or if the "v1" flag is set and the "no-hs" flag is **not** set. Tor will use this authority as a bridge authoritative directory if the "bridge" flag is set. If a flag "orport=**port**" is given, Tor will use the given port when opening encrypted tunnels to the dirserver. If a flag "weight=**num**" is given, then the directory server is chosen randomly with probability proportional to that weight (default 1.0). Lastly, if a flag "v3ident=**fp**" is given, the dirserver is a v3 directory authority whose v3 long-term signing key has the fingerprint **fp**. + + If no **DirAuthority** line is given, Tor will use the default directory authorities. NOTE: this option is intended for setting up a private Tor network with its own directory authorities. If you use it, you will be distinguishable from other users, because you won't believe the same authorities they do. [[DirAuthorityFallbackRate]] **DirAuthorityFallbackRate** __NUM__:: When configured to use both directory authorities and fallback directories, the directory authorities also work as fallbacks. They are chosen with their regular weights, multiplied by this number, which should be 1.0 or less. (Default: 1.0) [[DynamicDHGroups]] **DynamicDHGroups** **0**|**1**:: If this option is set to 1, when running as a server, generate our own Diffie-Hellman group instead of using the one from Apache's mod_ssl. This option may help circumvent censorship based on static Diffie-Hellman parameters. (Default: 0) [[AlternateDirAuthority]] **AlternateDirAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__ + [[AlternateHSAuthority]] **AlternateHSAuthority** [__nickname__] [**flags**] __address__:__port__ __fingerprint__ + [[AlternateBridgeAuthority]] **AlternateBridgeAuthority** [__nickname__] [**flags**] __address__:__port__ __ fingerprint__:: These options behave as DirAuthority, but they replace fewer of the default directory authorities. Using AlternateDirAuthority replaces the default Tor directory authorities, but leaves the default hidden service authorities and bridge authorities in place. Similarly, AlternateHSAuthority replaces the default hidden service authorities, but not the directory or bridge authorities; and AlternateBridgeAuthority replaces the default bridge authority, but leaves the directory and hidden service authorities alone. [[DisableAllSwap]] **DisableAllSwap** **0**|**1**:: If set to 1, Tor will attempt to lock all current and future memory pages, so that memory cannot be paged out. Windows, OS X and Solaris are currently not supported. We believe that this feature works on modern Gnu/Linux distributions, and that it should work on *BSD systems (untested). This option requires that you start your Tor as root, and you should use the **User** option to properly reduce Tor's privileges. (Default: 0) [[DisableDebuggerAttachment]] **DisableDebuggerAttachment** **0**|**1**:: If set to 1, Tor will attempt to prevent basic debugging attachment attempts by other processes. This may also keep Tor from generating core files if it crashes. It has no impact for users who wish to attach if they have CAP_SYS_PTRACE or if they are root. We believe that this feature works on modern Gnu/Linux distributions, and that it may also work on *BSD systems (untested). Some modern Gnu/Linux systems such as Ubuntu have the kernel.yama.ptrace_scope sysctl and by default enable it as an attempt to limit the PTRACE scope for all user processes by default. This feature will attempt to limit the PTRACE scope for Tor specifically - it will not attempt to alter the system wide ptrace scope as it may not even exist. If you wish to attach to Tor with a debugger such as gdb or strace you will want to set this to 0 for the duration of your debugging. Normal users should leave it on. Disabling this option while Tor is running is prohibited. (Default: 1) [[FetchDirInfoEarly]] **FetchDirInfoEarly** **0**|**1**:: If set to 1, Tor will always fetch directory information like other directory caches, even if you don't meet the normal criteria for fetching early. Normal users should leave it off. (Default: 0) [[FetchDirInfoExtraEarly]] **FetchDirInfoExtraEarly** **0**|**1**:: If set to 1, Tor will fetch directory information before other directory caches. It will attempt to download directory information closer to the start of the consensus period. Normal users should leave it off. (Default: 0) [[FetchHidServDescriptors]] **FetchHidServDescriptors** **0**|**1**:: If set to 0, Tor will never fetch any hidden service descriptors from the rendezvous directories. This option is only useful if you're using a Tor controller that handles hidden service fetches for you. (Default: 1) [[FetchServerDescriptors]] **FetchServerDescriptors** **0**|**1**:: If set to 0, Tor will never fetch any network status summaries or server descriptors from the directory servers. This option is only useful if you're using a Tor controller that handles directory fetches for you. (Default: 1) [[FetchUselessDescriptors]] **FetchUselessDescriptors** **0**|**1**:: If set to 1, Tor will fetch every non-obsolete descriptor from the authorities that it hears about. Otherwise, it will avoid fetching useless descriptors, for example for routers that are not running. This option is useful if you're using the contributed "exitlist" script to enumerate Tor nodes that exit to certain addresses. (Default: 0) [[HTTPProxy]] **HTTPProxy** __host__[:__port__]:: Tor will make all its directory requests through this host:port (or host:80 if port is not specified), rather than connecting directly to any directory servers. [[HTTPProxyAuthenticator]] **HTTPProxyAuthenticator** __username:password__:: If defined, Tor will use this username:password for Basic HTTP proxy authentication, as in RFC 2617. This is currently the only form of HTTP proxy authentication that Tor supports; feel free to submit a patch if you want it to support others. [[HTTPSProxy]] **HTTPSProxy** __host__[:__port__]:: Tor will make all its OR (SSL) connections through this host:port (or host:443 if port is not specified), via HTTP CONNECT rather than connecting directly to servers. You may want to set **FascistFirewall** to restrict the set of ports you might try to connect to, if your HTTPS proxy only allows connecting to certain ports. [[HTTPSProxyAuthenticator]] **HTTPSProxyAuthenticator** __username:password__:: If defined, Tor will use this username:password for Basic HTTPS proxy authentication, as in RFC 2617. This is currently the only form of HTTPS proxy authentication that Tor supports; feel free to submit a patch if you want it to support others. [[Socks4Proxy]] **Socks4Proxy** __host__[:__port__]:: Tor will make all OR connections through the SOCKS 4 proxy at host:port (or host:1080 if port is not specified). [[Socks5Proxy]] **Socks5Proxy** __host__[:__port__]:: Tor will make all OR connections through the SOCKS 5 proxy at host:port (or host:1080 if port is not specified). [[Socks5ProxyUsername]] **Socks5ProxyUsername** __username__ + [[Socks5ProxyPassword]] **Socks5ProxyPassword** __password__:: If defined, authenticate to the SOCKS 5 server using username and password in accordance to RFC 1929. Both username and password must be between 1 and 255 characters. [[KeepalivePeriod]] **KeepalivePeriod** __NUM__:: To keep firewalls from expiring connections, send a padding keepalive cell every NUM seconds on open connections that are in use. If the connection has no open circuits, it will instead be closed after NUM seconds of idleness. (Default: 5 minutes) [[Log]] **Log** __minSeverity__[-__maxSeverity__] **stderr**|**stdout**|**syslog**:: Send all messages between __minSeverity__ and __maxSeverity__ to the standard output stream, the standard error stream, or to the system log. (The "syslog" value is only supported on Unix.) Recognized severity levels are debug, info, notice, warn, and err. We advise using "notice" in most cases, since anything more verbose may provide sensitive information to an attacker who obtains the logs. If only one severity level is given, all messages of that level or higher will be sent to the listed destination. **Log** __minSeverity__[-__maxSeverity__] **file** __FILENAME__:: As above, but send log messages to the listed filename. The "Log" option may appear more than once in a configuration file. Messages are sent to all the logs that match their severity level. **Log** **[**__domain__,...**]**__minSeverity__[-__maxSeverity__] ... **file** __FILENAME__ + **Log** **[**__domain__,...**]**__minSeverity__[-__maxSeverity__] ... **stderr**|**stdout**|**syslog**:: As above, but select messages by range of log severity __and__ by a set of "logging domains". Each logging domain corresponds to an area of functionality inside Tor. You can specify any number of severity ranges for a single log statement, each of them prefixed by a comma-separated list of logging domains. You can prefix a domain with $$~$$ to indicate negation, and use * to indicate "all domains". If you specify a severity range without a list of domains, it matches all domains. + + This is an advanced feature which is most useful for debugging one or two of Tor's subsystems at a time. + + The currently recognized domains are: general, crypto, net, config, fs, protocol, mm, http, app, control, circ, rend, bug, dir, dirserv, or, edge, acct, hist, and handshake. Domain names are case-insensitive. + + For example, "`Log [handshake]debug [~net,~mm]info notice stdout`" sends to stdout: all handshake messages of any severity, all info-and-higher messages from domains other than networking and memory management, and all messages of severity notice or higher. [[LogMessageDomains]] **LogMessageDomains** **0**|**1**:: If 1, Tor includes message domains with each log message. Every log message currently has at least one domain; most currently have exactly one. This doesn't affect controller log messages. (Default: 0) [[OutboundBindAddress]] **OutboundBindAddress** __IP__:: Make all outbound connections originate from the IP address specified. This is only useful when you have multiple network interfaces, and you want all of Tor's outgoing connections to use a single one. This option may be used twice, once with an IPv4 address and once with an IPv6 address. This setting will be ignored for connections to the loopback addresses (127.0.0.0/8 and ::1). [[PidFile]] **PidFile** __FILE__:: On startup, write our PID to FILE. On clean shutdown, remove FILE. [[ProtocolWarnings]] **ProtocolWarnings** **0**|**1**:: If 1, Tor will log with severity \'warn' various cases of other parties not following the Tor specification. Otherwise, they are logged with severity \'info'. (Default: 0) [[RunAsDaemon]] **RunAsDaemon** **0**|**1**:: If 1, Tor forks and daemonizes to the background. This option has no effect on Windows; instead you should use the --service command-line option. (Default: 0) [[LogTimeGranularity]] **LogTimeGranularity** __NUM__:: Set the resolution of timestamps in Tor's logs to NUM milliseconds. NUM must be positive and either a divisor or a multiple of 1 second. Note that this option only controls the granularity written by Tor to a file or console log. Tor does not (for example) "batch up" log messages to affect times logged by a controller, times attached to syslog messages, or the mtime fields on log files. (Default: 1 second) [[SafeLogging]] **SafeLogging** **0**|**1**|**relay**:: Tor can scrub potentially sensitive strings from log messages (e.g. addresses) by replacing them with the string [scrubbed]. This way logs can still be useful, but they don't leave behind personally identifying information about what sites a user might have visited. + + If this option is set to 0, Tor will not perform any scrubbing, if it is set to 1, all potentially sensitive strings are replaced. If it is set to relay, all log messages generated when acting as a relay are sanitized, but all messages generated when acting as a client are not. (Default: 1) [[User]] **User** __UID__:: On startup, setuid to this user and setgid to their primary group. [[HardwareAccel]] **HardwareAccel** **0**|**1**:: If non-zero, try to use built-in (static) crypto hardware acceleration when available. (Default: 0) [[AccelName]] **AccelName** __NAME__:: When using OpenSSL hardware crypto acceleration attempt to load the dynamic engine of this name. This must be used for any dynamic hardware engine. Names can be verified with the openssl engine command. [[AccelDir]] **AccelDir** __DIR__:: Specify this option if using dynamic hardware acceleration and the engine implementation library resides somewhere other than the OpenSSL default. [[AvoidDiskWrites]] **AvoidDiskWrites** **0**|**1**:: If non-zero, try to write to disk less frequently than we would otherwise. This is useful when running on flash memory or other media that support only a limited number of writes. (Default: 0) [[TunnelDirConns]] **TunnelDirConns** **0**|**1**:: If non-zero, when a directory server we contact supports it, we will build a one-hop circuit and make an encrypted connection via its ORPort. (Default: 1) [[PreferTunneledDirConns]] **PreferTunneledDirConns** **0**|**1**:: If non-zero, we will avoid directory servers that don't support tunneled directory connections, when possible. (Default: 1) [[CircuitPriorityHalflife]] **CircuitPriorityHalflife** __NUM1__:: If this value is set, we override the default algorithm for choosing which circuit's cell to deliver or relay next. When the value is 0, we round-robin between the active circuits on a connection, delivering one cell from each in turn. When the value is positive, we prefer delivering cells from whichever connection has the lowest weighted cell count, where cells are weighted exponentially according to the supplied CircuitPriorityHalflife value (in seconds). If this option is not set at all, we use the behavior recommended in the current consensus networkstatus. This is an advanced option; you generally shouldn't have to mess with it. (Default: not set) [[DisableIOCP]] **DisableIOCP** **0**|**1**:: If Tor was built to use the Libevent's "bufferevents" networking code and you're running on Windows, setting this option to 1 will tell Libevent not to use the Windows IOCP networking API. (Default: 1) [[UserspaceIOCPBuffers]] **UserspaceIOCPBuffers** **0**|**1**:: If IOCP is enabled (see DisableIOCP above), setting this option to 1 will tell Tor to disable kernel-space TCP buffers, in order to avoid needless copy operations and try not to run out of non-paged RAM. This feature is experimental; don't use it yet unless you're eager to help tracking down bugs. (Default: 0) [[_UseFilteringSSLBufferevents]] **_UseFilteringSSLBufferevents** **0**|**1**:: Tells Tor to do its SSL communication using a chain of bufferevents: one for SSL and one for networking. This option has no effect if bufferevents are disabled (in which case it can't turn on), or if IOCP bufferevents are enabled (in which case it can't turn off). This option is useful for debugging only; most users shouldn't touch it. (Default: 0) [[CountPrivateBandwidth]] **CountPrivateBandwidth** **0**|**1**:: If this option is set, then Tor's rate-limiting applies not only to remote connections, but also to connections to private addresses like 127.0.0.1 or 10.0.0.1. This is mostly useful for debugging rate-limiting. (Default: 0) CLIENT OPTIONS -------------- The following options are useful only for clients (that is, if [[SocksPort]] **SocksPort**, **TransPort**, **DNSPort**, or **NATDPort** is non-zero): [[AllowInvalidNodes]] **AllowInvalidNodes** **entry**|**exit**|**middle**|**introduction**|**rendezvous**|**...**:: If some Tor servers are obviously not working right, the directory authorities can manually mark them as invalid, meaning that it's not recommended you use them for entry or exit positions in your circuits. You can opt to use them in some circuit positions, though. The default is "middle,rendezvous", and other choices are not advised. [[ExcludeSingleHopRelays]] **ExcludeSingleHopRelays** **0**|**1**:: This option controls whether circuits built by Tor will include relays with the AllowSingleHopExits flag set to true. If ExcludeSingleHopRelays is set to 0, these relays will be included. Note that these relays might be at higher risk of being seized or observed, so they are not normally included. Also note that relatively few clients turn off this option, so using these relays might make your client stand out. (Default: 1) [[Bridge]] **Bridge** [__transport__] __IP__:__ORPort__ [__fingerprint__]:: When set along with UseBridges, instructs Tor to use the relay at "IP:ORPort" as a "bridge" relaying into the Tor network. If "fingerprint" is provided (using the same format as for DirAuthority), we will verify that the relay running at that location has the right fingerprint. We also use fingerprint to look up the bridge descriptor at the bridge authority, if it's provided and if UpdateBridgesFromAuthority is set too. + + If "transport" is provided, and matches to a ClientTransportPlugin line, we use that pluggable transports proxy to transfer data to the bridge. [[LearnCircuitBuildTimeout]] **LearnCircuitBuildTimeout** **0**|**1**:: If 0, CircuitBuildTimeout adaptive learning is disabled. (Default: 1) [[CircuitBuildTimeout]] **CircuitBuildTimeout** __NUM__:: Try for at most NUM seconds when building circuits. If the circuit isn't open in that time, give up on it. If LearnCircuitBuildTimeout is 1, this value serves as the initial value to use before a timeout is learned. If LearnCircuitBuildTimeout is 0, this value is the only value used. (Default: 60 seconds) [[CircuitIdleTimeout]] **CircuitIdleTimeout** __NUM__:: If we have kept a clean (never used) circuit around for NUM seconds, then close it. This way when the Tor client is entirely idle, it can expire all of its circuits, and then expire its TLS connections. Also, if we end up making a circuit that is not useful for exiting any of the requests we're receiving, it won't forever take up a slot in the circuit list. (Default: 1 hour) [[CircuitStreamTimeout]] **CircuitStreamTimeout** __NUM__:: If non-zero, this option overrides our internal timeout schedule for how many seconds until we detach a stream from a circuit and try a new circuit. If your network is particularly slow, you might want to set this to a number like 60. (Default: 0) [[ClientOnly]] **ClientOnly** **0**|**1**:: If set to 1, Tor will under no circumstances run as a relay or serve directory requests. This config option is mostly meaningless: we added it back when we were considering having Tor clients auto-promote themselves to being relays if they were stable and fast enough. The current behavior is simply that Tor is a client unless ORPort or DirPort are configured. (Default: 0) [[ExcludeNodes]] **ExcludeNodes** __node__,__node__,__...__:: A list of identity fingerprints, nicknames, country codes and address patterns of nodes to avoid when building a circuit. (Example: ExcludeNodes SlowServer, ABCD1234CDEF5678ABCD1234CDEF5678ABCD1234, \{cc}, 255.254.0.0/8) + + By default, this option is treated as a preference that Tor is allowed to override in order to keep working. For example, if you try to connect to a hidden service, but you have excluded all of the hidden service's introduction points, Tor will connect to one of them anyway. If you do not want this behavior, set the StrictNodes option (documented below). + + Note also that if you are a relay, this (and the other node selection options below) only affects your own circuits that Tor builds for you. Clients can still build circuits through you to any node. Controllers can tell Tor to build circuits through any node. + + Country codes are case-insensitive. The code "\{??}" refers to nodes whose country can't be identified. No country code, including \{??}, works if no GeoIPFile can be loaded. See also the GeoIPExcludeUnknown option below. [[ExcludeExitNodes]] **ExcludeExitNodes** __node__,__node__,__...__:: A list of identity fingerprints, nicknames, country codes and address patterns of nodes to never use when picking an exit node---that is, a node that delivers traffic for you outside the Tor network. Note that any node listed in ExcludeNodes is automatically considered to be part of this list too. See also the caveats on the "ExitNodes" option below. [[GeoIPExcludeUnknown]] **GeoIPExcludeUnknown** **0**|**1**|**auto**:: If this option is set to 'auto', then whenever any country code is set in ExcludeNodes or ExcludeExitNodes, all nodes with unknown country (\{??} and possibly \{A1}) are treated as excluded as well. If this option is set to '1', then all unknown countries are treated as excluded in ExcludeNodes and ExcludeExitNodes. This option has no effect when a GeoIP file isn't configured or can't be found. (Default: auto) [[ExitNodes]] **ExitNodes** __node__,__node__,__...__:: A list of identity fingerprints, nicknames, country codes and address patterns of nodes to use as exit node---that is, a node that delivers traffic for you outside the Tor network. + + Note that if you list too few nodes here, or if you exclude too many exit nodes with ExcludeExitNodes, you can degrade functionality. For example, if none of the exits you list allows traffic on port 80 or 443, you won't be able to browse the web. + + Note also that not every circuit is used to deliver traffic outside of the Tor network. It is normal to see non-exit circuits (such as those used to connect to hidden services, those that do directory fetches, those used for relay reachability self-tests, and so on) that end at a non-exit node. To keep a node from being used entirely, see ExcludeNodes and StrictNodes. + + The ExcludeNodes option overrides this option: any node listed in both ExitNodes and ExcludeNodes is treated as excluded. + + The .exit address notation, if enabled via AllowDotExit, overrides this option. [[EntryNodes]] **EntryNodes** __node__,__node__,__...__:: A list of identity fingerprints, nicknames, and country codes of nodes to use for the first hop in your normal circuits. Normal circuits include all circuits except for direct connections to directory servers. The Bridge option overrides this option; if you have configured bridges and UseBridges is 1, the Bridges are used as your entry nodes. + + The ExcludeNodes option overrides this option: any node listed in both EntryNodes and ExcludeNodes is treated as excluded. [[StrictNodes]] **StrictNodes** **0**|**1**:: If StrictNodes is set to 1, Tor will treat the ExcludeNodes option as a requirement to follow for all the circuits you generate, even if doing so will break functionality for you. If StrictNodes is set to 0, Tor will still try to avoid nodes in the ExcludeNodes list, but it will err on the side of avoiding unexpected errors. Specifically, StrictNodes 0 tells Tor that it is okay to use an excluded node when it is *necessary* to perform relay reachability self-tests, connect to a hidden service, provide a hidden service to a client, fulfill a .exit request, upload directory information, or download directory information. (Default: 0) [[FascistFirewall]] **FascistFirewall** **0**|**1**:: If 1, Tor will only create outgoing connections to ORs running on ports that your firewall allows (defaults to 80 and 443; see **FirewallPorts**). This will allow you to run Tor as a client behind a firewall with restrictive policies, but will not allow you to run as a server behind such a firewall. If you prefer more fine-grained control, use ReachableAddresses instead. [[FirewallPorts]] **FirewallPorts** __PORTS__:: A list of ports that your firewall allows you to connect to. Only used when **FascistFirewall** is set. This option is deprecated; use ReachableAddresses instead. (Default: 80, 443) [[ReachableAddresses]] **ReachableAddresses** __ADDR__[/__MASK__][:__PORT__]...:: A comma-separated list of IP addresses and ports that your firewall allows you to connect to. The format is as for the addresses in ExitPolicy, except that "accept" is understood unless "reject" is explicitly provided. For example, \'ReachableAddresses 99.0.0.0/8, reject 18.0.0.0/8:80, accept \*:80' means that your firewall allows connections to everything inside net 99, rejects port 80 connections to net 18, and accepts connections to port 80 otherwise. (Default: \'accept \*:*'.) [[ReachableDirAddresses]] **ReachableDirAddresses** __ADDR__[/__MASK__][:__PORT__]...:: Like **ReachableAddresses**, a list of addresses and ports. Tor will obey these restrictions when fetching directory information, using standard HTTP GET requests. If not set explicitly then the value of **ReachableAddresses** is used. If **HTTPProxy** is set then these connections will go through that proxy. [[ReachableORAddresses]] **ReachableORAddresses** __ADDR__[/__MASK__][:__PORT__]...:: Like **ReachableAddresses**, a list of addresses and ports. Tor will obey these restrictions when connecting to Onion Routers, using TLS/SSL. If not set explicitly then the value of **ReachableAddresses** is used. If **HTTPSProxy** is set then these connections will go through that proxy. + + The separation between **ReachableORAddresses** and **ReachableDirAddresses** is only interesting when you are connecting through proxies (see **HTTPProxy** and **HTTPSProxy**). Most proxies limit TLS connections (which Tor uses to connect to Onion Routers) to port 443, and some limit HTTP GET requests (which Tor uses for fetching directory information) to port 80. [[HidServAuth]] **HidServAuth** __onion-address__ __auth-cookie__ [__service-name__]:: Client authorization for a hidden service. Valid onion addresses contain 16 characters in a-z2-7 plus ".onion", and valid auth cookies contain 22 characters in A-Za-z0-9+/. The service name is only used for internal purposes, e.g., for Tor controllers. This option may be used multiple times for different hidden services. If a hidden service uses authorization and this option is not set, the hidden service is not accessible. Hidden services can be configured to require authorization using the **HiddenServiceAuthorizeClient** option. [[CloseHSClientCircuitsImmediatelyOnTimeout]] **CloseHSClientCircuitsImmediatelyOnTimeout** **0**|**1**:: If 1, Tor will close unfinished hidden service client circuits which have not moved closer to connecting to their destination hidden service when their internal state has not changed for the duration of the current circuit-build timeout. Otherwise, such circuits will be left open, in the hope that they will finish connecting to their destination hidden services. In either case, another set of introduction and rendezvous circuits for the same destination hidden service will be launched. (Default: 0) [[CloseHSServiceRendCircuitsImmediatelyOnTimeout]] **CloseHSServiceRendCircuitsImmediatelyOnTimeout** **0**|**1**:: If 1, Tor will close unfinished hidden-service-side rendezvous circuits after the current circuit-build timeout. Otherwise, such circuits will be left open, in the hope that they will finish connecting to their destinations. In either case, another rendezvous circuit for the same destination client will be launched. (Default: 0) [[LongLivedPorts]] **LongLivedPorts** __PORTS__:: A list of ports for services that tend to have long-running connections (e.g. chat and interactive shells). Circuits for streams that use these ports will contain only high-uptime nodes, to reduce the chance that a node will go down before the stream is finished. Note that the list is also honored for circuits (both client and service side) involving hidden services whose virtual port is in this list. (Default: 21, 22, 706, 1863, 5050, 5190, 5222, 5223, 6523, 6667, 6697, 8300) [[MapAddress]] **MapAddress** __address__ __newaddress__:: When a request for address arrives to Tor, it will transform to newaddress before processing it. For example, if you always want connections to www.example.com to exit via __torserver__ (where __torserver__ is the nickname of the server), use "MapAddress www.example.com www.example.com.torserver.exit". If the value is prefixed with a "\*.", matches an entire domain. For example, if you always want connections to example.com and any if its subdomains to exit via __torserver__ (where __torserver__ is the nickname of the server), use "MapAddress \*.example.com \*.example.com.torserver.exit". (Note the leading "*." in each part of the directive.) You can also redirect all subdomains of a domain to a single address. For example, "MapAddress *.example.com www.example.com". + + NOTES: 1. When evaluating MapAddress expressions Tor stops when it hits the most recently added expression that matches the requested address. So if you have the following in your torrc, www.torproject.org will map to 1.1.1.1: MapAddress www.torproject.org 2.2.2.2 MapAddress www.torproject.org 1.1.1.1 2. Tor evaluates the MapAddress configuration until it finds no matches. So if you have the following in your torrc, www.torproject.org will map to 2.2.2.2: MapAddress 1.1.1.1 2.2.2.2 MapAddress www.torproject.org 1.1.1.1 3. The following MapAddress expression is invalid (and will be ignored) because you cannot map from a specific address to a wildcard address: MapAddress www.torproject.org *.torproject.org.torserver.exit 4. Using a wildcard to match only part of a string (as in *ample.com) is also invalid. [[NewCircuitPeriod]] **NewCircuitPeriod** __NUM__:: Every NUM seconds consider whether to build a new circuit. (Default: 30 seconds) [[MaxCircuitDirtiness]] **MaxCircuitDirtiness** __NUM__:: Feel free to reuse a circuit that was first used at most NUM seconds ago, but never attach a new stream to a circuit that is too old. For hidden services, this applies to the __last__ time a circuit was used, not the first. (Default: 10 minutes) [[MaxClientCircuitsPending]] **MaxClientCircuitsPending** __NUM__:: Do not allow more than NUM circuits to be pending at a time for handling client streams. A circuit is pending if we have begun constructing it, but it has not yet been completely constructed. (Default: 32) [[NodeFamily]] **NodeFamily** __node__,__node__,__...__:: The Tor servers, defined by their identity fingerprints or nicknames, constitute a "family" of similar or co-administered servers, so never use any two of them in the same circuit. Defining a NodeFamily is only needed when a server doesn't list the family itself (with MyFamily). This option can be used multiple times. In addition to nodes, you can also list IP address and ranges and country codes in {curly braces}. [[EnforceDistinctSubnets]] **EnforceDistinctSubnets** **0**|**1**:: If 1, Tor will not put two servers whose IP addresses are "too close" on the same circuit. Currently, two addresses are "too close" if they lie in the same /16 range. (Default: 1) [[SOCKSPort]] **SOCKSPort** \['address':]__port__|**auto** [_flags_] [_isolation flags_]:: Open this port to listen for connections from SOCKS-speaking applications. Set this to 0 if you don't want to allow application connections via SOCKS. Set it to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. (Default: 9050) + + The _isolation flags_ arguments give Tor rules for which streams received on this SOCKSPort are allowed to share circuits with one another. Recognized isolation flags are: **IsolateClientAddr**;; Don't share circuits with streams from a different client address. (On by default and strongly recommended; you can disable it with **NoIsolateClientAddr**.) **IsolateSOCKSAuth**;; Don't share circuits with streams for which different SOCKS authentication was provided. (On by default; you can disable it with **NoIsolateSOCKSAuth**.) **IsolateClientProtocol**;; Don't share circuits with streams using a different protocol. (SOCKS 4, SOCKS 5, TransPort connections, NATDPort connections, and DNSPort requests are all considered to be different protocols.) **IsolateDestPort**;; Don't share circuits with streams targetting a different destination port. **IsolateDestAddr**;; Don't share circuits with streams targetting a different destination address. **SessionGroup=**__INT__;; If no other isolation rules would prevent it, allow streams on this port to share circuits with streams from every other port with the same session group. (By default, streams received on different SOCKSPorts, TransPorts, etc are always isolated from one another. This option overrides that behavior.) + + Other recognized _flags_ for a SOCKSPort are: **NoIPv4Traffic**;; Tell exits to not connect to IPv4 addresses in response to SOCKS requests on this connection. **IPv6Traffic**;; Tell exits to allow IPv6 addresses in response to SOCKS requests on this connection, so long as SOCKS5 is in use. (SOCKS4 can't handle IPv6.) **PreferIPv6**;; Tells exits that, if a host has both an IPv4 and an IPv6 address, we would prefer to connect to it via IPv6. (IPv4 is the default.) + + NOTE: Although this option allows you to specify an IP address other than localhost, you should do so only with extreme caution. The SOCKS protocol is unencrypted and (as we use it) unauthenticated, so exposing it in this way could leak your information to anybody watching your network, and allow anybody to use your computer as an open proxy. **CacheIPv4DNS**;; Tells the client to remember IPv4 DNS answers we receive from exit nodes via this connection. (On by default.) **CacheIPv6DNS**;; Tells the client to remember IPv6 DNS answers we receive from exit nodes via this connection. **CacheDNS**;; Tells the client to remember all DNS answers we receive from exit nodes via this connection. **UseIPv4Cache**;; Tells the client to use any cached IPv4 DNS answers we have when making requests via this connection. (NOTE: This option, along UseIPv6Cache and UseDNSCache, can harm your anonymity, and probably won't help performance as much as you might expect. Use with care!) **UseIPv6Cache**;; Tells the client to use any cached IPv6 DNS answers we have when making requests via this connection. **UseDNSCache**;; Tells the client to use any cached DNS answers we have when making requests via this connection. **PreferIPv6Automap**;; When serving a hostname lookup request on this port that should get automapped (according to AutomapHostsOnResove), if we could return either an IPv4 or an IPv6 answer, prefer an IPv6 answer. (On by default.) **PreferSOCKSNoAuth**;; Ordinarily, when an application offers both "username/password authentication" and "no authentication" to Tor via SOCKS5, Tor selects username/password authentication so that IsolateSOCKSAuth can work. This can confuse some applications, if they offer a username/password combination then get confused when asked for one. You can disable this behavior, so that Tor will select "No authentication" when IsolateSOCKSAuth is disabled, or when this option is set. [[SOCKSListenAddress]] **SOCKSListenAddress** __IP__[:__PORT__]:: Bind to this address to listen for connections from Socks-speaking applications. (Default: 127.0.0.1) You can also specify a port (e.g. 192.168.0.1:9100). This directive can be specified multiple times to bind to multiple addresses/ports. (DEPRECATED: As of 0.2.3.x-alpha, you can now use multiple SOCKSPort entries, and provide addresses for SOCKSPort entries, so SOCKSListenAddress no longer has a purpose. For backward compatibility, SOCKSListenAddress is only allowed when SOCKSPort is just a port number.) [[SocksPolicy]] **SocksPolicy** __policy__,__policy__,__...__:: Set an entrance policy for this server, to limit who can connect to the SocksPort and DNSPort ports. The policies have the same form as exit policies below. [[SocksTimeout]] **SocksTimeout** __NUM__:: Let a socks connection wait NUM seconds handshaking, and NUM seconds unattached waiting for an appropriate circuit, before we fail it. (Default: 2 minutes) [[TokenBucketRefillInterval]] **TokenBucketRefillInterval** __NUM__ [**msec**|**second**]:: Set the refill interval of Tor's token bucket to NUM milliseconds. NUM must be between 1 and 1000, inclusive. Note that the configured bandwidth limits are still expressed in bytes per second: this option only affects the frequency with which Tor checks to see whether previously exhausted connections may read again. (Default: 100 msec) [[TrackHostExits]] **TrackHostExits** __host__,__.domain__,__...__:: For each value in the comma separated list, Tor will track recent connections to hosts that match this value and attempt to reuse the same exit node for each. If the value is prepended with a \'.\', it is treated as matching an entire domain. If one of the values is just a \'.', it means match everything. This option is useful if you frequently connect to sites that will expire all your authentication cookies (i.e. log you out) if your IP address changes. Note that this option does have the disadvantage of making it more clear that a given history is associated with a single user. However, most people who would wish to observe this will observe it through cookies or other protocol-specific means anyhow. [[TrackHostExitsExpire]] **TrackHostExitsExpire** __NUM__:: Since exit servers go up and down, it is desirable to expire the association between host and exit server after NUM seconds. The default is 1800 seconds (30 minutes). [[UpdateBridgesFromAuthority]] **UpdateBridgesFromAuthority** **0**|**1**:: When set (along with UseBridges), Tor will try to fetch bridge descriptors from the configured bridge authorities when feasible. It will fall back to a direct request if the authority responds with a 404. (Default: 0) [[UseBridges]] **UseBridges** **0**|**1**:: When set, Tor will fetch descriptors for each bridge listed in the "Bridge" config lines, and use these relays as both entry guards and directory guards. (Default: 0) [[UseEntryGuards]] **UseEntryGuards** **0**|**1**:: If this option is set to 1, we pick a few long-term entry servers, and try to stick with them. This is desirable because constantly changing servers increases the odds that an adversary who owns some servers will observe a fraction of your paths. (Default: 1) [[UseEntryGuardsAsDirectoryGuards]] **UseEntryGuardsAsDirectoryGuards** **0**|**1**:: If this option is set to 1, and UseEntryGuards is also set to 1, we try to use our entry guards as directory guards, and failing that, pick more nodes to act as our directory guards. This helps prevent an adversary from enumerating clients. It's only available for clients (non-relay, non-bridge) that aren't configured to download any non-default directory material. It doesn't currently do anything when we lack a live consensus. (Default: 1) [[NumEntryGuards]] **NumEntryGuards** __NUM__:: If UseEntryGuards is set to 1, we will try to pick a total of NUM routers as long-term entries for our circuits. (Default: 3) [[NumDirectoryGuards]] **NumDirectoryGuards** __NUM__:: If UseEntryGuardsAsDirectoryGuards is enabled, we try to make sure we have at least NUM routers to use as directory guards. If this option is set to 0, use the value from NumEntryGuards. (Default: 0) [[GuardLifetime]] **GuardLifetime** __N__ **days**|**weeks**|**months**:: If nonzero, and UseEntryGuards is set, minimum time to keep a guard before picking a new one. If zero, we use the GuardLifetime parameter from the consensus directory. No value here may be less than 1 month or greater than 5 years; out-of-range values are clamped. (Default: 0) [[SafeSocks]] **SafeSocks** **0**|**1**:: When this option is enabled, Tor will reject application connections that use unsafe variants of the socks protocol -- ones that only provide an IP address, meaning the application is doing a DNS resolve first. Specifically, these are socks4 and socks5 when not doing remote DNS. (Default: 0) [[TestSocks]] **TestSocks** **0**|**1**:: When this option is enabled, Tor will make a notice-level log entry for each connection to the Socks port indicating whether the request used a safe socks protocol or an unsafe one (see above entry on SafeSocks). This helps to determine whether an application using Tor is possibly leaking DNS requests. (Default: 0) [[WarnUnsafeSocks]] **WarnUnsafeSocks** **0**|**1**:: When this option is enabled, Tor will warn whenever a request is received that only contains an IP address instead of a hostname. Allowing applications to do DNS resolves themselves is usually a bad idea and can leak your location to attackers. (Default: 1) [[VirtualAddrNetworkIPv4]] **VirtualAddrNetworkIPv4** __Address__/__bits__ + [[VirtualAddrNetworkIPv6]] **VirtualAddrNetworkIPv6** [__Address__]/__bits__:: When Tor needs to assign a virtual (unused) address because of a MAPADDRESS command from the controller or the AutomapHostsOnResolve feature, Tor picks an unassigned address from this range. (Defaults: 127.192.0.0/10 and [FE80::]/10 respectively.) + + When providing proxy server service to a network of computers using a tool like dns-proxy-tor, change the IPv4 network to "10.192.0.0/10" or "172.16.0.0/12" and change the IPv6 network to "[FC00]/7". The default **VirtualAddrNetwork** address ranges on a properly configured machine will route to the loopback or link-local interface. For local use, no change to the default VirtualAddrNetwork setting is needed. [[AllowNonRFC953Hostnames]] **AllowNonRFC953Hostnames** **0**|**1**:: When this option is disabled, Tor blocks hostnames containing illegal characters (like @ and :) rather than sending them to an exit node to be resolved. This helps trap accidental attempts to resolve URLs and so on. (Default: 0) [[AllowDotExit]] **AllowDotExit** **0**|**1**:: If enabled, we convert "www.google.com.foo.exit" addresses on the SocksPort/TransPort/NATDPort into "www.google.com" addresses that exit from the node "foo". Disabled by default since attacking websites and exit relays can use it to manipulate your path selection. (Default: 0) [[FastFirstHopPK]] **FastFirstHopPK** **0**|**1**:: When this option is disabled, Tor uses the public key step for the first hop of creating circuits. Skipping it is generally safe since we have already used TLS to authenticate the relay and to establish forward-secure keys. Turning this option off makes circuit building slower. + + Note that Tor will always use the public key step for the first hop if it's operating as a relay, and it will never use the public key step if it doesn't yet know the onion key of the first hop. (Default: 1) [[TransPort]] **TransPort** \['address':]__port__|**auto** [_isolation flags_]:: Open this port to listen for transparent proxy connections. Set this to 0 if you don't want to allow transparent proxy connections. Set the port to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. See SOCKSPort for an explanation of isolation flags. + + TransPort requires OS support for transparent proxies, such as BSDs' pf or Linux's IPTables. If you're planning to use Tor as a transparent proxy for a network, you'll want to examine and change VirtualAddrNetwork from the default setting. You'll also want to set the TransListenAddress option for the network you'd like to proxy. (Default: 0) [[TransListenAddress]] **TransListenAddress** __IP__[:__PORT__]:: Bind to this address to listen for transparent proxy connections. (Default: 127.0.0.1). This is useful for exporting a transparent proxy server to an entire network. (DEPRECATED: As of 0.2.3.x-alpha, you can now use multiple TransPort entries, and provide addresses for TransPort entries, so TransListenAddress no longer has a purpose. For backward compatibility, TransListenAddress is only allowed when TransPort is just a port number.) [[NATDPort]] **NATDPort** \['address':]__port__|**auto** [_isolation flags_]:: Open this port to listen for connections from old versions of ipfw (as included in old versions of FreeBSD, etc) using the NATD protocol. Use 0 if you don't want to allow NATD connections. Set the port to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. See SOCKSPort for an explanation of isolation flags. + + This option is only for people who cannot use TransPort. (Default: 0) [[NATDListenAddress]] **NATDListenAddress** __IP__[:__PORT__]:: Bind to this address to listen for NATD connections. (DEPRECATED: As of 0.2.3.x-alpha, you can now use multiple NATDPort entries, and provide addresses for NATDPort entries, so NATDListenAddress no longer has a purpose. For backward compatibility, NATDListenAddress is only allowed when NATDPort is just a port number.) [[AutomapHostsOnResolve]] **AutomapHostsOnResolve** **0**|**1**:: When this option is enabled, and we get a request to resolve an address that ends with one of the suffixes in **AutomapHostsSuffixes**, we map an unused virtual address to that address, and return the new virtual address. This is handy for making ".onion" addresses work with applications that resolve an address and then connect to it. (Default: 0) [[AutomapHostsSuffixes]] **AutomapHostsSuffixes** __SUFFIX__,__SUFFIX__,__...__:: A comma-separated list of suffixes to use with **AutomapHostsOnResolve**. The "." suffix is equivalent to "all addresses." (Default: .exit,.onion). [[DNSPort]] **DNSPort** \['address':]__port__|**auto** [_isolation flags_]:: If non-zero, open this port to listen for UDP DNS requests, and resolve them anonymously. This port only handles A, AAAA, and PTR requests---it doesn't handle arbitrary DNS request types. Set the port to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. See SOCKSPort for an explanation of isolation flags. (Default: 0) [[DNSListenAddress]] **DNSListenAddress** __IP__[:__PORT__]:: Bind to this address to listen for DNS connections. (DEPRECATED: As of 0.2.3.x-alpha, you can now use multiple DNSPort entries, and provide addresses for DNSPort entries, so DNSListenAddress no longer has a purpose. For backward compatibility, DNSListenAddress is only allowed when DNSPort is just a port number.) [[ClientDNSRejectInternalAddresses]] **ClientDNSRejectInternalAddresses** **0**|**1**:: If true, Tor does not believe any anonymously retrieved DNS answer that tells it that an address resolves to an internal address (like 127.0.0.1 or 192.168.0.1). This option prevents certain browser-based attacks; don't turn it off unless you know what you're doing. (Default: 1) [[ClientRejectInternalAddresses]] **ClientRejectInternalAddresses** **0**|**1**:: If true, Tor does not try to fulfill requests to connect to an internal address (like 127.0.0.1 or 192.168.0.1) __unless a exit node is specifically requested__ (for example, via a .exit hostname, or a controller request). (Default: 1) [[DownloadExtraInfo]] **DownloadExtraInfo** **0**|**1**:: If true, Tor downloads and caches "extra-info" documents. These documents contain information about servers other than the information in their regular router descriptors. Tor does not use this information for anything itself; to save bandwidth, leave this option turned off. (Default: 0) [[WarnPlaintextPorts]] **WarnPlaintextPorts** __port__,__port__,__...__:: Tells Tor to issue a warnings whenever the user tries to make an anonymous connection to one of these ports. This option is designed to alert users to services that risk sending passwords in the clear. (Default: 23,109,110,143) [[RejectPlaintextPorts]] **RejectPlaintextPorts** __port__,__port__,__...__:: Like WarnPlaintextPorts, but instead of warning about risky port uses, Tor will instead refuse to make the connection. (Default: None) [[AllowSingleHopCircuits]] **AllowSingleHopCircuits** **0**|**1**:: When this option is set, the attached Tor controller can use relays that have the **AllowSingleHopExits** option turned on to build one-hop Tor connections. (Default: 0) [[OptimisticData]] **OptimisticData** **0**|**1**|**auto**:: When this option is set, and Tor is using an exit node that supports the feature, it will try optimistically to send data to the exit node without waiting for the exit node to report whether the connection succeeded. This can save a round-trip time for protocols like HTTP where the client talks first. If OptimisticData is set to **auto**, Tor will look at the UseOptimisticData parameter in the networkstatus. (Default: auto) [[Tor2webMode]] **Tor2webMode** **0**|**1**:: When this option is set, Tor connects to hidden services **non-anonymously**. This option also disables client connections to non-hidden-service hostnames through Tor. It **must only** be used when running a tor2web Hidden Service web proxy. To enable this option the compile time flag --enable-tor2webmode must be specified. (Default: 0) [[UseMicrodescriptors]] **UseMicrodescriptors** **0**|**1**|**auto**:: Microdescriptors are a smaller version of the information that Tor needs in order to build its circuits. Using microdescriptors makes Tor clients download less directory information, thus saving bandwidth. Directory caches need to fetch regular descriptors and microdescriptors, so this option doesn't save any bandwidth for them. If this option is set to "auto" (recommended) then it is on for all clients that do not set FetchUselessDescriptors. (Default: auto) [[UseNTorHandshake]] **UseNTorHandshake** **0**|**1**|**auto**:: The "ntor" circuit-creation handshake is faster and (we think) more secure than the original ("TAP") circuit handshake, but starting to use it too early might make your client stand out. If this option is 0, your Tor client won't use the ntor handshake. If it's 1, your Tor client will use the ntor handshake to extend circuits through servers that support it. If this option is "auto" (recommended), then your client will use the ntor handshake once enough directory authorities recommend it. (Default: auto) [[PathBiasCircThreshold]] **PathBiasCircThreshold** __NUM__ + [[PathBiasNoticeRate]] **PathBiasNoticeRate** __NUM__ + [[PathBiasWarnRate]] **PathBiasWarnRate** __NUM__ + [[PathBiasExtremeRate]] **PathBiasExtremeRate** __NUM__ + [[PathBiasDropGuards]] **PathBiasDropGuards** __NUM__ + [[PathBiasScaleThreshold]] **PathBiasScaleThreshold** __NUM__:: These options override the default behavior of Tor's (**currently experimental**) path bias detection algorithm. To try to find broken or misbehaving guard nodes, Tor looks for nodes where more than a certain fraction of circuits through that guard fail to get built. + The PathBiasCircThreshold option controls how many circuits we need to build through a guard before we make these checks. The PathBiasNoticeRate, PathBiasWarnRate and PathBiasExtremeRate options control what fraction of circuits must succeed through a guard so we won't write log messages. If less than PathBiasExtremeRate circuits succeed *and* PathBiasDropGuards is set to 1, we disable use of that guard. + + When we have seen more than PathBiasScaleThreshold circuits through a guard, we scale our observations by 0.5 (governed by the consensus) so that new observations don't get swamped by old ones. + + By default, or if a negative value is provided for one of these options, Tor uses reasonable defaults from the networkstatus consensus document. If no defaults are available there, these options default to 150, .70, .50, .30, 0, and 300 respectively. [[PathBiasUseThreshold]] **PathBiasUseThreshold** __NUM__ + [[PathBiasNoticeUseRate]] **PathBiasNoticeUseRate** __NUM__ + [[PathBiasExtremeUseRate]] **PathBiasExtremeUseRate** __NUM__ + [[PathBiasScaleUseThreshold]] **PathBiasScaleUseThreshold** __NUM__:: Similar to the above options, these options override the default behavior of Tor's (**currently experimental**) path use bias detection algorithm. + Where as the path bias parameters govern thresholds for successfully building circuits, these four path use bias parameters govern thresholds only for circuit usage. Circuits which receive no stream usage are not counted by this detection algorithm. A used circuit is considered successful if it is capable of carrying streams or otherwise receiving well-formed responses to RELAY cells. + By default, or if a negative value is provided for one of these options, Tor uses reasonable defaults from the networkstatus consensus document. If no defaults are available there, these options default to 20, .80, .60, and 100, respectively. [[ClientUseIPv6]] **ClientUseIPv6** **0**|**1**:: If this option is set to 1, Tor might connect to entry nodes over IPv6. Note that clients configured with an IPv6 address in a **Bridge** line will try connecting over IPv6 even if **ClientUseIPv6** is set to 0. (Default: 0) [[ClientPreferIPv6ORPort]] **ClientPreferIPv6ORPort** **0**|**1**:: If this option is set to 1, Tor prefers an OR port with an IPv6 address over one with IPv4 if a given entry node has both. Other things may influence the choice. This option breaks a tie to the favor of IPv6. (Default: 0) [[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__:: Tor clients don't build circuits for user traffic until they know about enough of the network so that they could potentially construct enough of the possible paths through the network. If this option is set to a fraction between 0.25 and 0.95, Tor won't build circuits until it has enough descriptors or microdescriptors to construct that fraction of possible paths. Note that setting this option too low can make your Tor client less anonymous, and setting it too high can prevent your Tor client from bootstrapping. If this option is negative, Tor will use a default value chosen by the directory authorities. (Default: -1.) [[Support022HiddenServices]] **Support022HiddenServices** **0**|**1**|**auto**:: Tor hidden services running versions before 0.2.3.x required clients to send timestamps, which can potentially be used to distinguish clients whose view of the current time is skewed. If this option is set to 0, we do not send this timestamp, and hidden services on obsolete Tor versions will not work. If this option is set to 1, we send the timestamp. If this optoin is "auto", we take a recommendation from the latest consensus document. (Default: auto) SERVER OPTIONS -------------- The following options are useful only for servers (that is, if ORPort is non-zero): [[Address]] **Address** __address__:: The IP address or fully qualified domain name of this server (e.g. moria.mit.edu). You can leave this unset, and Tor will guess your IP address. This IP address is the one used to tell clients and other servers where to find your Tor server; it doesn't affect the IP that your Tor client binds to. To bind to a different address, use the *ListenAddress and OutboundBindAddress options. [[AllowSingleHopExits]] **AllowSingleHopExits** **0**|**1**:: This option controls whether clients can use this server as a single hop proxy. If set to 1, clients can use this server as an exit even if it is the only hop in the circuit. Note that most clients will refuse to use servers that set this option, since most clients have ExcludeSingleHopRelays set. (Default: 0) [[AssumeReachable]] **AssumeReachable** **0**|**1**:: This option is used when bootstrapping a new Tor network. If set to 1, don't do self-reachability testing; just upload your server descriptor immediately. If **AuthoritativeDirectory** is also set, this option instructs the dirserver to bypass remote reachability testing too and list all connected servers as running. [[BridgeRelay]] **BridgeRelay** **0**|**1**:: Sets the relay to act as a "bridge" with respect to relaying connections from bridge users to the Tor network. It mainly causes Tor to publish a server descriptor to the bridge database, rather than publishing a relay descriptor to the public directory authorities. [[ContactInfo]] **ContactInfo** __email_address__:: Administrative contact information for this relay or bridge. This line can be used to contact you if your relay or bridge is misconfigured or something else goes wrong. Note that we archive and publish all descriptors containing these lines and that Google indexes them, so spammers might also collect them. You may want to obscure the fact that it's an email address and/or generate a new address for this purpose. [[ExitPolicy]] **ExitPolicy** __policy__,__policy__,__...__:: Set an exit policy for this server. Each policy is of the form "**accept**|**reject** __ADDR__[/__MASK__][:__PORT__]". If /__MASK__ is omitted then this policy just applies to the host given. Instead of giving a host or network you can also use "\*" to denote the universe (0.0.0.0/0). __PORT__ can be a single port number, an interval of ports "__FROM_PORT__-__TO_PORT__", or "\*". If __PORT__ is omitted, that means "\*". + + For example, "accept 18.7.22.69:\*,reject 18.0.0.0/8:\*,accept \*:\*" would reject any traffic destined for MIT except for web.mit.edu, and accept anything else. + + To specify all internal and link-local networks (including 0.0.0.0/8, 169.254.0.0/16, 127.0.0.0/8, 192.168.0.0/16, 10.0.0.0/8, and 172.16.0.0/12), you can use the "private" alias instead of an address. These addresses are rejected by default (at the beginning of your exit policy), along with your public IP address, unless you set the ExitPolicyRejectPrivate config option to 0. For example, once you've done that, you could allow HTTP to 127.0.0.1 and block all other connections to internal networks with "accept 127.0.0.1:80,reject private:\*", though that may also allow connections to your own computer that are addressed to its public (external) IP address. See RFC 1918 and RFC 3330 for more details about internal and reserved IP address space. + + This directive can be specified multiple times so you don't have to put it all on one line. + + Policies are considered first to last, and the first match wins. If you want to \_replace_ the default exit policy, end your exit policy with either a reject \*:* or an accept \*:*. Otherwise, you're \_augmenting_ (prepending to) the default exit policy. The default exit policy is: + reject *:25 reject *:119 reject *:135-139 reject *:445 reject *:563 reject *:1214 reject *:4661-4666 reject *:6346-6429 reject *:6699 reject *:6881-6999 accept *:* [[ExitPolicyRejectPrivate]] **ExitPolicyRejectPrivate** **0**|**1**:: Reject all private (local) networks, along with your own public IP address, at the beginning of your exit policy. See above entry on ExitPolicy. (Default: 1) [[IPv6Exit]] **IPv6Exit** **0**|**1**:: If set, and we are an exit node, allow clients to use us for IPv6 traffic. (Default: 0) [[MaxOnionQueueDelay]] **MaxOnionQueueDelay** __NUM__ [**msec**|**second**]:: If we have more onionskins queued for processing than we can process in this amount of time, reject new ones. (Default: 1750 msec) [[MyFamily]] **MyFamily** __node__,__node__,__...__:: Declare that this Tor server is controlled or administered by a group or organization identical or similar to that of the other servers, defined by their identity fingerprints or nicknames. When two servers both declare that they are in the same \'family', Tor clients will not use them in the same circuit. (Each server only needs to list the other servers in its family; it doesn't need to list itself, but it won't hurt.) Do not list any bridge relay as it would compromise its concealment. + When listing a node, it's better to list it by fingerprint than by nickname: fingerprints are more reliable. [[Nickname]] **Nickname** __name__:: Set the server's nickname to \'name'. Nicknames must be between 1 and 19 characters inclusive, and must contain only the characters [a-zA-Z0-9]. [[NumCPUs]] **NumCPUs** __num__:: How many processes to use at once for decrypting onionskins and other parallelizable operations. If this is set to 0, Tor will try to detect how many CPUs you have, defaulting to 1 if it can't tell. (Default: 0) [[ORPort]] **ORPort** \['address':]__PORT__|**auto** [_flags_]:: Advertise this port to listen for connections from Tor clients and servers. This option is required to be a Tor server. Set it to "auto" to have Tor pick a port for you. Set it to 0 to not run an ORPort at all. This option can occur more than once. (Default: 0) + Tor recognizes these flags on each ORPort: **NoAdvertise**:: By default, we bind to a port and tell our users about it. If NoAdvertise is specified, we don't advertise, but listen anyway. This can be useful if the port everybody will be connecting to (for example, one that's opened on our firewall) is somewhere else. **NoListen**:: By default, we bind to a port and tell our users about it. If NoListen is specified, we don't bind, but advertise anyway. This can be useful if something else (for example, a firewall's port forwarding configuration) is causing connections to reach us. **IPv4Only**:: If the address is absent, or resolves to both an IPv4 and an IPv6 address, only listen to the IPv4 address. **IPv6Only**:: If the address is absent, or resolves to both an IPv4 and an IPv6 address, only listen to the IPv6 address. + For obvious reasons, NoAdvertise and NoListen are mutually exclusive, and IPv4Only and IPv6Only are mutually exclusive. [[ORListenAddress]] **ORListenAddress** __IP__[:__PORT__]:: Bind to this IP address to listen for connections from Tor clients and servers. If you specify a port, bind to this port rather than the one specified in ORPort. (Default: 0.0.0.0) This directive can be specified multiple times to bind to multiple addresses/ports. + This option is deprecated; you can get the same behavior with ORPort now that it supports NoAdvertise and explicit addresses. [[PortForwarding]] **PortForwarding** **0**|**1**:: Attempt to automatically forward the DirPort and ORPort on a NAT router connecting this Tor server to the Internet. If set, Tor will try both NAT-PMP (common on Apple routers) and UPnP (common on routers from other manufacturers). (Default: 0) [[PortForwardingHelper]] **PortForwardingHelper** __filename__|__pathname__:: If PortForwarding is set, use this executable to configure the forwarding. If set to a filename, the system path will be searched for the executable. If set to a path, only the specified path will be executed. (Default: tor-fw-helper) [[PublishServerDescriptor]] **PublishServerDescriptor** **0**|**1**|**v1**|**v2**|**v3**|**bridge**,**...**:: This option specifies which descriptors Tor will publish when acting as a relay. You can choose multiple arguments, separated by commas. + If this option is set to 0, Tor will not publish its descriptors to any directories. (This is useful if you're testing out your server, or if you're using a Tor controller that handles directory publishing for you.) Otherwise, Tor will publish its descriptors of all type(s) specified. The default is "1", which means "if running as a server, publish the appropriate descriptors to the authorities". [[ShutdownWaitLength]] **ShutdownWaitLength** __NUM__:: When we get a SIGINT and we're a server, we begin shutting down: we close listeners and start refusing new circuits. After **NUM** seconds, we exit. If we get a second SIGINT, we exit immediately. (Default: 30 seconds) [[SSLKeyLifetime]] **SSLKeyLifetime** __N__ **minutes**|**hours**|**days**|**weeks**:: When creating a link certificate for our outermost SSL handshake, set its lifetime to this amount of time. If set to 0, Tor will choose some reasonable random defaults. (Default: 0) [[HeartbeatPeriod]] **HeartbeatPeriod** __N__ **minutes**|**hours**|**days**|**weeks**:: Log a heartbeat message every **HeartbeatPeriod** seconds. This is a log level __notice__ message, designed to let you know your Tor server is still alive and doing useful things. Settings this to 0 will disable the heartbeat. (Default: 6 hours) [[AccountingMax]] **AccountingMax** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**TBytes**:: Never send more than the specified number of bytes in a given accounting period, or receive more than that number in the period. For example, with AccountingMax set to 1 GByte, a server could send 900 MBytes and receive 800 MBytes and continue running. It will only hibernate once one of the two reaches 1 GByte. When the number of bytes gets low, Tor will stop accepting new connections and circuits. When the number of bytes is exhausted, Tor will hibernate until some time in the next accounting period. To prevent all servers from waking at the same time, Tor will also wait until a random point in each period before waking up. If you have bandwidth cost issues, enabling hibernation is preferable to setting a low bandwidth, since it provides users with a collection of fast servers that are up some of the time, which is more useful than a set of slow servers that are always "available". [[AccountingStart]] **AccountingStart** **day**|**week**|**month** [__day__] __HH:MM__:: Specify how long accounting periods last. If **month** is given, each accounting period runs from the time __HH:MM__ on the __dayth__ day of one month to the same day and time of the next. (The day must be between 1 and 28.) If **week** is given, each accounting period runs from the time __HH:MM__ of the __dayth__ day of one week to the same day and time of the next week, with Monday as day 1 and Sunday as day 7. If **day** is given, each accounting period runs from the time __HH:MM__ each day to the same time on the next day. All times are local, and given in 24-hour time. (Default: "month 1 0:00") [[RefuseUnknownExits]] **RefuseUnknownExits** **0**|**1**|**auto**:: Prevent nodes that don't appear in the consensus from exiting using this relay. If the option is 1, we always block exit attempts from such nodes; if it's 0, we never do, and if the option is "auto", then we do whatever the authorities suggest in the consensus (and block if the consensus is quiet on the issue). (Default: auto) [[ServerDNSResolvConfFile]] **ServerDNSResolvConfFile** __filename__:: Overrides the default DNS configuration with the configuration in __filename__. The file format is the same as the standard Unix "**resolv.conf**" file (7). This option, like all other ServerDNS options, only affects name lookups that your server does on behalf of clients. (Defaults to use the system DNS configuration.) [[ServerDNSAllowBrokenConfig]] **ServerDNSAllowBrokenConfig** **0**|**1**:: If this option is false, Tor exits immediately if there are problems parsing the system DNS configuration or connecting to nameservers. Otherwise, Tor continues to periodically retry the system nameservers until it eventually succeeds. (Default: 1) [[ServerDNSSearchDomains]] **ServerDNSSearchDomains** **0**|**1**:: If set to 1, then we will search for addresses in the local search domain. For example, if this system is configured to believe it is in "example.com", and a client tries to connect to "www", the client will be connected to "www.example.com". This option only affects name lookups that your server does on behalf of clients. (Default: 0) [[ServerDNSDetectHijacking]] **ServerDNSDetectHijacking** **0**|**1**:: When this option is set to 1, we will test periodically to determine whether our local nameservers have been configured to hijack failing DNS requests (usually to an advertising site). If they are, we will attempt to correct this. This option only affects name lookups that your server does on behalf of clients. (Default: 1) [[ServerDNSTestAddresses]] **ServerDNSTestAddresses** __address__,__address__,__...__:: When we're detecting DNS hijacking, make sure that these __valid__ addresses aren't getting redirected. If they are, then our DNS is completely useless, and we'll reset our exit policy to "reject *:*". This option only affects name lookups that your server does on behalf of clients. (Default: "www.google.com, www.mit.edu, www.yahoo.com, www.slashdot.org") [[ServerDNSAllowNonRFC953Hostnames]] **ServerDNSAllowNonRFC953Hostnames** **0**|**1**:: When this option is disabled, Tor does not try to resolve hostnames containing illegal characters (like @ and :) rather than sending them to an exit node to be resolved. This helps trap accidental attempts to resolve URLs and so on. This option only affects name lookups that your server does on behalf of clients. (Default: 0) [[BridgeRecordUsageByCountry]] **BridgeRecordUsageByCountry** **0**|**1**:: When this option is enabled and BridgeRelay is also enabled, and we have GeoIP data, Tor keeps a keep a per-country count of how many client addresses have contacted it so that it can help the bridge authority guess which countries have blocked access to it. (Default: 1) [[ServerDNSRandomizeCase]] **ServerDNSRandomizeCase** **0**|**1**:: When this option is set, Tor sets the case of each character randomly in outgoing DNS requests, and makes sure that the case matches in DNS replies. This so-called "0x20 hack" helps resist some types of DNS poisoning attack. For more information, see "Increased DNS Forgery Resistance through 0x20-Bit Encoding". This option only affects name lookups that your server does on behalf of clients. (Default: 1) [[GeoIPFile]] **GeoIPFile** __filename__:: A filename containing IPv4 GeoIP data, for use with by-country statistics. [[GeoIPv6File]] **GeoIPv6File** __filename__:: A filename containing IPv6 GeoIP data, for use with by-country statistics. [[TLSECGroup]] **TLSECGroup** **P224**|**P256**:: What EC group should we try to use for incoming TLS connections? P224 is faster, but makes us stand out more. Has no effect if we're a client, or if our OpenSSL version lacks support for ECDHE. (Default: P256) [[CellStatistics]] **CellStatistics** **0**|**1**:: When this option is enabled, Tor writes statistics on the mean time that cells spend in circuit queues to disk every 24 hours. (Default: 0) [[DirReqStatistics]] **DirReqStatistics** **0**|**1**:: When this option is enabled, a Tor directory writes statistics on the number and response time of network status requests to disk every 24 hours. (Default: 1) [[EntryStatistics]] **EntryStatistics** **0**|**1**:: When this option is enabled, Tor writes statistics on the number of directly connecting clients to disk every 24 hours. (Default: 0) [[ExitPortStatistics]] **ExitPortStatistics** **0**|**1**:: When this option is enabled, Tor writes statistics on the number of relayed bytes and opened stream per exit port to disk every 24 hours. (Default: 0) [[ConnDirectionStatistics]] **ConnDirectionStatistics** **0**|**1**:: When this option is enabled, Tor writes statistics on the bidirectional use of connections to disk every 24 hours. (Default: 0) [[ExtraInfoStatistics]] **ExtraInfoStatistics** **0**|**1**:: When this option is enabled, Tor includes previously gathered statistics in its extra-info documents that it uploads to the directory authorities. (Default: 1) [[ExtendAllowPrivateAddresses]] **ExtendAllowPrivateAddresses** **0**|**1**:: When this option is enabled, Tor routers allow EXTEND request to localhost, RFC1918 addresses, and so on. This can create security issues; you should probably leave it off. (Default: 0) [[MaxMemInCellQueues]] **MaxMemInCellQueues** __N__ **bytes**|**KB**|**MB**|**GB**:: This option configures a threshold above which Tor will assume that it needs to stop queueing cells because it's about to run out of memory. If it hits this threshold, it will begin killing circuits until it has recovered at least 10% of this memory. Do not set this option too low, or your relay may be unreliable under load. This option only affects circuit queues, so the actual process size will be larger than this. (Default: 8GB) DIRECTORY SERVER OPTIONS ------------------------ The following options are useful only for directory servers (that is, if DirPort is non-zero): [[AuthoritativeDirectory]] **AuthoritativeDirectory** **0**|**1**:: When this option is set to 1, Tor operates as an authoritative directory server. Instead of caching the directory, it generates its own list of good servers, signs it, and sends that to the clients. Unless the clients already have you listed as a trusted directory, you probably do not want to set this option. Please coordinate with the other admins at tor-ops@torproject.org if you think you should be a directory. [[DirPortFrontPage]] **DirPortFrontPage** __FILENAME__:: When this option is set, it takes an HTML file and publishes it as "/" on the DirPort. Now relay operators can provide a disclaimer without needing to set up a separate webserver. There's a sample disclaimer in contrib/tor-exit-notice.html. [[V1AuthoritativeDirectory]] **V1AuthoritativeDirectory** **0**|**1**:: When this option is set in addition to **AuthoritativeDirectory**, Tor generates version 1 directory and running-routers documents (for legacy Tor clients up to 0.1.0.x). [[V2AuthoritativeDirectory]] **V2AuthoritativeDirectory** **0**|**1**:: When this option is set in addition to **AuthoritativeDirectory**, Tor generates version 2 network statuses and serves descriptors, etc as described in doc/spec/dir-spec-v2.txt (for Tor clients and servers running 0.1.1.x and 0.1.2.x). [[V3AuthoritativeDirectory]] **V3AuthoritativeDirectory** **0**|**1**:: When this option is set in addition to **AuthoritativeDirectory**, Tor generates version 3 network statuses and serves descriptors, etc as described in doc/spec/dir-spec.txt (for Tor clients and servers running at least 0.2.0.x). [[VersioningAuthoritativeDirectory]] **VersioningAuthoritativeDirectory** **0**|**1**:: When this option is set to 1, Tor adds information on which versions of Tor are still believed safe for use to the published directory. Each version 1 authority is automatically a versioning authority; version 2 authorities provide this service optionally. See **RecommendedVersions**, **RecommendedClientVersions**, and **RecommendedServerVersions**. [[NamingAuthoritativeDirectory]] **NamingAuthoritativeDirectory** **0**|**1**:: When this option is set to 1, then the server advertises that it has opinions about nickname-to-fingerprint bindings. It will include these opinions in its published network-status pages, by listing servers with the flag "Named" if a correct binding between that nickname and fingerprint has been registered with the dirserver. Naming dirservers will refuse to accept or publish descriptors that contradict a registered binding. See **approved-routers** in the **FILES** section below. [[HSAuthoritativeDir]] **HSAuthoritativeDir** **0**|**1**:: When this option is set in addition to **AuthoritativeDirectory**, Tor also accepts and serves v0 hidden service descriptors, which are produced and used by Tor 0.2.1.x and older. (Default: 0) [[HidServDirectoryV2]] **HidServDirectoryV2** **0**|**1**:: When this option is set, Tor accepts and serves v2 hidden service descriptors. Setting DirPort is not required for this, because clients connect via the ORPort by default. (Default: 1) [[BridgeAuthoritativeDir]] **BridgeAuthoritativeDir** **0**|**1**:: When this option is set in addition to **AuthoritativeDirectory**, Tor accepts and serves router descriptors, but it caches and serves the main networkstatus documents rather than generating its own. (Default: 0) [[MinUptimeHidServDirectoryV2]] **MinUptimeHidServDirectoryV2** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**:: Minimum uptime of a v2 hidden service directory to be accepted as such by authoritative directories. (Default: 25 hours) [[DirPort]] **DirPort** \['address':]__PORT__|**auto** [_flags_]:: If this option is nonzero, advertise the directory service on this port. Set it to "auto" to have Tor pick a port for you. This option can occur more than once. (Default: 0) + The same flags are supported here as are supported by ORPort. [[DirListenAddress]] **DirListenAddress** __IP__[:__PORT__]:: Bind the directory service to this address. If you specify a port, bind to this port rather than the one specified in DirPort. (Default: 0.0.0.0) This directive can be specified multiple times to bind to multiple addresses/ports. + This option is deprecated; you can get the same behavior with DirPort now that it supports NoAdvertise and explicit addresses. [[DirPolicy]] **DirPolicy** __policy__,__policy__,__...__:: Set an entrance policy for this server, to limit who can connect to the directory ports. The policies have the same form as exit policies above. [[FetchV2Networkstatus]] **FetchV2Networkstatus** **0**|**1**:: If set, we try to fetch the (obsolete, unused) version 2 network status consensus documents from the directory authorities. No currently supported Tor version uses them. (Default: 0) DIRECTORY AUTHORITY SERVER OPTIONS ---------------------------------- [[RecommendedVersions]] **RecommendedVersions** __STRING__:: STRING is a comma-separated list of Tor versions currently believed to be safe. The list is included in each directory, and nodes which pull down the directory learn whether they need to upgrade. This option can appear multiple times: the values from multiple lines are spliced together. When this is set then **VersioningAuthoritativeDirectory** should be set too. [[RecommendedClientVersions]] **RecommendedClientVersions** __STRING__:: STRING is a comma-separated list of Tor versions currently believed to be safe for clients to use. This information is included in version 2 directories. If this is not set then the value of **RecommendedVersions** is used. When this is set then **VersioningAuthoritativeDirectory** should be set too. [[RecommendedServerVersions]] **RecommendedServerVersions** __STRING__:: STRING is a comma-separated list of Tor versions currently believed to be safe for servers to use. This information is included in version 2 directories. If this is not set then the value of **RecommendedVersions** is used. When this is set then **VersioningAuthoritativeDirectory** should be set too. [[ConsensusParams]] **ConsensusParams** __STRING__:: STRING is a space-separated list of key=value pairs that Tor will include in the "params" line of its networkstatus vote. [[DirAllowPrivateAddresses]] **DirAllowPrivateAddresses** **0**|**1**:: If set to 1, Tor will accept router descriptors with arbitrary "Address" elements. Otherwise, if the address is not an IP address or is a private IP address, it will reject the router descriptor. (Default: 0) [[AuthDirBadDir]] **AuthDirBadDir** __AddressPattern...__:: Authoritative directories only. A set of address patterns for servers that will be listed as bad directories in any network status document this authority publishes, if **AuthDirListBadDirs** is set. [[AuthDirBadExit]] **AuthDirBadExit** __AddressPattern...__:: Authoritative directories only. A set of address patterns for servers that will be listed as bad exits in any network status document this authority publishes, if **AuthDirListBadExits** is set. [[AuthDirInvalid]] **AuthDirInvalid** __AddressPattern...__:: Authoritative directories only. A set of address patterns for servers that will never be listed as "valid" in any network status document that this authority publishes. [[AuthDirReject]] **AuthDirReject** __AddressPattern__...:: Authoritative directories only. A set of address patterns for servers that will never be listed at all in any network status document that this authority publishes, or accepted as an OR address in any descriptor submitted for publication by this authority. [[AuthDirBadDirCCs]] **AuthDirBadDirCCs** __CC__,... + [[AuthDirBadExitCCs]] **AuthDirBadExitCCs** __CC__,... + [[AuthDirInvalidCCs]] **AuthDirInvalidCCs** __CC__,... + [[AuthDirRejectCCs]] **AuthDirRejectCCs** __CC__,...:: Authoritative directories only. These options contain a comma-separated list of country codes such that any server in one of those country codes will be marked as a bad directory/bad exit/invalid for use, or rejected entirely. [[AuthDirListBadDirs]] **AuthDirListBadDirs** **0**|**1**:: Authoritative directories only. If set to 1, this directory has some opinion about which nodes are unsuitable as directory caches. (Do not set this to 1 unless you plan to list non-functioning directories as bad; otherwise, you are effectively voting in favor of every declared directory.) [[AuthDirListBadExits]] **AuthDirListBadExits** **0**|**1**:: Authoritative directories only. If set to 1, this directory has some opinion about which nodes are unsuitable as exit nodes. (Do not set this to 1 unless you plan to list non-functioning exits as bad; otherwise, you are effectively voting in favor of every declared exit as an exit.) [[AuthDirRejectUnlisted]] **AuthDirRejectUnlisted** **0**|**1**:: Authoritative directories only. If set to 1, the directory server rejects all uploaded server descriptors that aren't explicitly listed in the fingerprints file. This acts as a "panic button" if we get hit with a Sybil attack. (Default: 0) [[AuthDirMaxServersPerAddr]] **AuthDirMaxServersPerAddr** __NUM__:: Authoritative directories only. The maximum number of servers that we will list as acceptable on a single IP address. Set this to "0" for "no limit". (Default: 2) [[AuthDirMaxServersPerAuthAddr]] **AuthDirMaxServersPerAuthAddr** __NUM__:: Authoritative directories only. Like AuthDirMaxServersPerAddr, but applies to addresses shared with directory authorities. (Default: 5) [[AuthDirFastGuarantee]] **AuthDirFastGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: Authoritative directories only. If non-zero, always vote the Fast flag for any relay advertising this amount of capacity or more. (Default: 100 KBytes) [[AuthDirGuardBWGuarantee]] **AuthDirGuardBWGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: Authoritative directories only. If non-zero, this advertised capacity or more is always sufficient to satisfy the bandwidth requirement for the Guard flag. (Default: 250 KBytes) [[BridgePassword]] **BridgePassword** __Password__:: If set, contains an HTTP authenticator that tells a bridge authority to serve all requested bridge information. Used by the (only partially implemented) "bridge community" design, where a community of bridge relay operators all use an alternate bridge directory authority, and their target user audience can periodically fetch the list of available community bridges to stay up-to-date. (Default: not set) [[V3AuthVotingInterval]] **V3AuthVotingInterval** __N__ **minutes**|**hours**:: V3 authoritative directories only. Configures the server's preferred voting interval. Note that voting will __actually__ happen at an interval chosen by consensus from all the authorities' preferred intervals. This time SHOULD divide evenly into a day. (Default: 1 hour) [[V3AuthVoteDelay]] **V3AuthVoteDelay** __N__ **minutes**|**hours**:: V3 authoritative directories only. Configures the server's preferred delay between publishing its vote and assuming it has all the votes from all the other authorities. Note that the actual time used is not the server's preferred time, but the consensus of all preferences. (Default: 5 minutes) [[V3AuthDistDelay]] **V3AuthDistDelay** __N__ **minutes**|**hours**:: V3 authoritative directories only. Configures the server's preferred delay between publishing its consensus and signature and assuming it has all the signatures from all the other authorities. Note that the actual time used is not the server's preferred time, but the consensus of all preferences. (Default: 5 minutes) [[V3AuthNIntervalsValid]] **V3AuthNIntervalsValid** __NUM__:: V3 authoritative directories only. Configures the number of VotingIntervals for which each consensus should be valid for. Choosing high numbers increases network partitioning risks; choosing low numbers increases directory traffic. Note that the actual number of intervals used is not the server's preferred number, but the consensus of all preferences. Must be at least 2. (Default: 3) [[V3BandwidthsFile]] **V3BandwidthsFile** __FILENAME__:: V3 authoritative directories only. Configures the location of the bandwidth-authority generated file storing information on relays' measured bandwidth capacities. (Default: unset) [[V3AuthUseLegacyKey]] **V3AuthUseLegacyKey** **0**|**1**:: If set, the directory authority will sign consensuses not only with its own signing key, but also with a "legacy" key and certificate with a different identity. This feature is used to migrate directory authority keys in the event of a compromise. (Default: 0) [[RephistTrackTime]] **RephistTrackTime** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**:: Tells an authority, or other node tracking node reliability and history, that fine-grained information about nodes can be discarded when it hasn't changed for a given amount of time. (Default: 24 hours) [[VoteOnHidServDirectoriesV2]] **VoteOnHidServDirectoriesV2** **0**|**1**:: When this option is set in addition to **AuthoritativeDirectory**, Tor votes on whether to accept relays as hidden service directories. (Default: 1) [[AuthDirHasIPv6Connectivity]] **AuthDirHasIPv6Connectivity** **0**|**1**:: Authoritative directories only. When set to 0, OR ports with an IPv6 address are being accepted without reachability testing. When set to 1, IPv6 OR ports are being tested just like IPv4 OR ports. (Default: 0) HIDDEN SERVICE OPTIONS ---------------------- The following options are used to configure a hidden service. [[HiddenServiceDir]] **HiddenServiceDir** __DIRECTORY__:: Store data files for a hidden service in DIRECTORY. Every hidden service must have a separate directory. You may use this option multiple times to specify multiple services. DIRECTORY must be an existing directory. [[HiddenServicePort]] **HiddenServicePort** __VIRTPORT__ [__TARGET__]:: Configure a virtual port VIRTPORT for a hidden service. You may use this option multiple times; each time applies to the service using the most recent hiddenservicedir. By default, this option maps the virtual port to the same port on 127.0.0.1 over TCP. You may override the target port, address, or both by specifying a target of addr, port, or addr:port. You may also have multiple lines with the same VIRTPORT: when a user connects to that VIRTPORT, one of the TARGETs from those lines will be chosen at random. [[PublishHidServDescriptors]] **PublishHidServDescriptors** **0**|**1**:: If set to 0, Tor will run any hidden services you configure, but it won't advertise them to the rendezvous directory. This option is only useful if you're using a Tor controller that handles hidserv publishing for you. (Default: 1) [[HiddenServiceVersion]] **HiddenServiceVersion** __version__,__version__,__...__:: A list of rendezvous service descriptor versions to publish for the hidden service. Currently, only version 2 is supported. (Default: 2) [[HiddenServiceAuthorizeClient]] **HiddenServiceAuthorizeClient** __auth-type__ __client-name__,__client-name__,__...__:: If configured, the hidden service is accessible for authorized clients only. The auth-type can either be \'basic' for a general-purpose authorization protocol or \'stealth' for a less scalable protocol that also hides service activity from unauthorized clients. Only clients that are listed here are authorized to access the hidden service. Valid client names are 1 to 19 characters long and only use characters in A-Za-z0-9+-_ (no spaces). If this option is set, the hidden service is not accessible for clients without authorization any more. Generated authorization data can be found in the hostname file. Clients need to put this authorization data in their configuration file using **HidServAuth**. [[RendPostPeriod]] **RendPostPeriod** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**:: Every time the specified period elapses, Tor uploads any rendezvous service descriptors to the directory servers. This information is also uploaded whenever it changes. (Default: 1 hour) TESTING NETWORK OPTIONS ----------------------- The following options are used for running a testing Tor network. [[TestingTorNetwork]] **TestingTorNetwork** **0**|**1**:: If set to 1, Tor adjusts default values of the configuration options below, so that it is easier to set up a testing Tor network. May only be set if non-default set of DirAuthorities is set. Cannot be unset while Tor is running. (Default: 0) + ServerDNSAllowBrokenConfig 1 DirAllowPrivateAddresses 1 EnforceDistinctSubnets 0 AssumeReachable 1 AuthDirMaxServersPerAddr 0 AuthDirMaxServersPerAuthAddr 0 ClientDNSRejectInternalAddresses 0 ClientRejectInternalAddresses 0 CountPrivateBandwidth 1 ExitPolicyRejectPrivate 0 ExtendAllowPrivateAddresses 1 V3AuthVotingInterval 5 minutes V3AuthVoteDelay 20 seconds V3AuthDistDelay 20 seconds MinUptimeHidServDirectoryV2 0 seconds TestingV3AuthInitialVotingInterval 5 minutes TestingV3AuthInitialVoteDelay 20 seconds TestingV3AuthInitialDistDelay 20 seconds TestingAuthDirTimeToLearnReachability 0 minutes TestingEstimatedDescriptorPropagationTime 0 minutes [[TestingV3AuthInitialVotingInterval]] **TestingV3AuthInitialVotingInterval** __N__ **minutes**|**hours**:: Like V3AuthVotingInterval, but for initial voting interval before the first consensus has been created. Changing this requires that **TestingTorNetwork** is set. (Default: 30 minutes) [[TestingV3AuthInitialVoteDelay]] **TestingV3AuthInitialVoteDelay** __N__ **minutes**|**hours**:: Like V3AuthVoteDelay, but for initial voting interval before the first consensus has been created. Changing this requires that **TestingTorNetwork** is set. (Default: 5 minutes) [[TestingV3AuthInitialDistDelay]] **TestingV3AuthInitialDistDelay** __N__ **minutes**|**hours**:: Like V3AuthDistDelay, but for initial voting interval before the first consensus has been created. Changing this requires that **TestingTorNetwork** is set. (Default: 5 minutes) [[TestingAuthDirTimeToLearnReachability]] **TestingAuthDirTimeToLearnReachability** __N__ **minutes**|**hours**:: After starting as an authority, do not make claims about whether routers are Running until this much time has passed. Changing this requires that **TestingTorNetwork** is set. (Default: 30 minutes) [[TestingEstimatedDescriptorPropagationTime]] **TestingEstimatedDescriptorPropagationTime** __N__ **minutes**|**hours**:: Clients try downloading router descriptors from directory caches after this time. Changing this requires that **TestingTorNetwork** is set. (Default: 10 minutes) [[TestingMinFastFlagThreshold]] **TestingMinFastFlagThreshold** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: Minimum value for the Fast flag. Overrides the ordinary minimum taken from the consensus when TestingTorNetwork is set. (Default: 0.) SIGNALS ------- Tor catches the following signals: [[SIGTERM]] **SIGTERM**:: Tor will catch this, clean up and sync to disk if necessary, and exit. [[SIGINT]] **SIGINT**:: Tor clients behave as with SIGTERM; but Tor servers will do a controlled slow shutdown, closing listeners and waiting 30 seconds before exiting. (The delay can be configured with the ShutdownWaitLength config option.) [[SIGHUP]] **SIGHUP**:: The signal instructs Tor to reload its configuration (including closing and reopening logs), and kill and restart its helper processes if applicable. [[SIGUSR1]] **SIGUSR1**:: Log statistics about current connections, past connections, and throughput. [[SIGUSR2]] **SIGUSR2**:: Switch all logs to loglevel debug. You can go back to the old loglevels by sending a SIGHUP. [[SIGCHLD]] **SIGCHLD**:: Tor receives this signal when one of its helper processes has exited, so it can clean up. [[SIGPIPE]] **SIGPIPE**:: Tor catches this signal and ignores it. [[SIGXFSZ]] **SIGXFSZ**:: If this signal exists on your platform, Tor catches and ignores it. FILES ----- **@CONFDIR@/torrc**:: The configuration file, which contains "option value" pairs. **@LOCALSTATEDIR@/lib/tor/**:: The tor process stores keys and other data here. __DataDirectory__**/cached-status/**:: The most recently downloaded network status document for each authority. Each file holds one such document; the filenames are the hexadecimal identity key fingerprints of the directory authorities. Mostly obsolete. __DataDirectory__**/cached-consensus** and/or **cached-microdesc-consensus**:: The most recent consensus network status document we've downloaded. __DataDirectory__**/cached-descriptors** and **cached-descriptors.new**:: These files hold downloaded router statuses. Some routers may appear more than once; if so, the most recently published descriptor is used. Lines beginning with @-signs are annotations that contain more information about a given router. The ".new" file is an append-only journal; when it gets too large, all entries are merged into a new cached-descriptors file. __DataDirectory__**/cached-microdescs** and **cached-microdescs.new**:: These files hold downloaded microdescriptors. Lines beginning with @-signs are annotations that contain more information about a given router. The ".new" file is an append-only journal; when it gets too large, all entries are merged into a new cached-microdescs file. __DataDirectory__**/cached-routers** and **cached-routers.new**:: Obsolete versions of cached-descriptors and cached-descriptors.new. When Tor can't find the newer files, it looks here instead. __DataDirectory__**/state**:: A set of persistent key-value mappings. These are documented in the file. These include: - The current entry guards and their status. - The current bandwidth accounting values (unused so far; see below). - When the file was last written - What version of Tor generated the state file - A short history of bandwidth usage, as produced in the router descriptors. __DataDirectory__**/bw_accounting**:: Used to track bandwidth accounting values (when the current period starts and ends; how much has been read and written so far this period). This file is obsolete, and the data is now stored in the \'state' file as well. Only used when bandwidth accounting is enabled. __DataDirectory__**/control_auth_cookie**:: Used for cookie authentication with the controller. Location can be overridden by the CookieAuthFile config option. Regenerated on startup. See control-spec.txt for details. Only used when cookie authentication is enabled. __DataDirectory__**/keys/***:: Only used by servers. Holds identity keys and onion keys. __DataDirectory__**/fingerprint**:: Only used by servers. Holds the fingerprint of the server's identity key. __DataDirectory__**/approved-routers**:: Only for naming authoritative directory servers (see **NamingAuthoritativeDirectory**). This file lists nickname to identity bindings. Each line lists a nickname and a fingerprint separated by whitespace. See your **fingerprint** file in the __DataDirectory__ for an example line. If the nickname is **!reject** then descriptors from the given identity (fingerprint) are rejected by this server. If it is **!invalid** then descriptors are accepted but marked in the directory as not valid, that is, not recommended. __DataDirectory__**/router-stability**:: Only used by authoritative directory servers. Tracks measurements for router mean-time-between-failures so that authorities have a good idea of how to set their Stable flags. __HiddenServiceDirectory__**/hostname**:: The .onion domain name for this hidden service. If the hidden service is restricted to authorized clients only, this file also contains authorization data for all clients. __HiddenServiceDirectory__**/private_key**:: The private key for this hidden service. __HiddenServiceDirectory__**/client_keys**:: Authorization data for a hidden service that is only accessible by authorized clients. SEE ALSO -------- **privoxy**(1), **torsocks**(1), **torify**(1) + **https://www.torproject.org/** BUGS ---- Plenty, probably. Tor is still in development. Please report them. AUTHORS ------- Roger Dingledine [arma at mit.edu], Nick Mathewson [nickm at alum.mit.edu]. tor-0.2.4.20/doc/tor-gencert.1.in0000644000175000017500000001035612164363317013162 00000000000000'\" t .\" Title: tor-gencert .\" Author: Nick Mathewson .\" Generator: DocBook XSL Stylesheets v1.76.1 .\" Date: 07/01/2013 .\" Manual: Tor Manual .\" Source: Tor .\" Language: English .\" .TH "TOR\-GENCERT" "1" "07/01/2013" "Tor" "Tor Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" tor-gencert \- Generate certs and keys for Tor directory authorities .SH "SYNOPSIS" .sp \fBtor\-gencert\fR [\-h|\-\-help] [\-v] [\-r|\-\-reuse] [\-\-create\-identity\-key] [\-i \fIid_file\fR] [\-c \fIcert_file\fR] [\-m \fInum\fR] [\-a \fIaddress\fR:\fIport\fR] .SH "DESCRIPTION" .sp \fBtor\-gencert\fR generates certificates and private keys for use by Tor directory authorities running the v3 Tor directory protocol, as used by Tor 0\&.2\&.0 and later\&. If you are not running a directory authority, you don\(cqt need to use tor\-gencert\&. .sp Every directory authority has a long term authority \fIidentity\fR \fIkey\fR (which is distinct from the identity key it uses as a Tor server); this key should be kept offline in a secure location\&. It is used to certify shorter\-lived \fIsigning\fR \fIkeys\fR, which are kept online and used by the directory authority to sign votes and consensus documents\&. .sp After you use this program to generate a signing key and a certificate, copy those files to the keys subdirectory of your Tor process, and send Tor a SIGHUP signal\&. DO NOT COPY THE IDENTITY KEY\&. .SH "OPTIONS" .PP \fB\-v\fR .RS 4 Display verbose output\&. .RE .PP \fB\-h\fR or \fB\-\-help\fR .RS 4 Display help text and exit\&. .RE .PP \fB\-r\fR or \fB\-\-reuse\fR .RS 4 Generate a new certificate, but not a new signing key\&. This can be used to change the address or lifetime associated with a given key\&. .RE .PP \fB\-\-create\-identity\-key\fR .RS 4 Generate a new identity key\&. You should only use this option the first time you run tor\-gencert; in the future, you should use the identity key that\(cqs already there\&. .RE .PP \fB\-i\fR \fIFILENAME\fR .RS 4 Read the identity key from the specified file\&. If the file is not present and \-\-create\-identity\-key is provided, create the identity key in the specified file\&. Default: "\&./authority_identity_key" .RE .PP \fB\-s\fR \fIFILENAME\fR .RS 4 Write the signing key to the specified file\&. Default: "\&./authority_signing_key" .RE .PP \fB\-c\fR \fIFILENAME\fR .RS 4 Write the certificate to the specified file\&. Default: "\&./authority_certificate" .RE .PP \fB\-m\fR \fINUM\fR .RS 4 Number of months that the certificate should be valid\&. Default: 12\&. .RE .PP \fB\-\-passphrase\-fd\fR \fIFILEDES\fR .RS 4 Filedescriptor to read the file descriptor from\&. Ends at the first NUL or newline\&. Default: read from the terminal\&. .RE .PP \fB\-a\fR \fIaddress\fR:\fIport\fR .RS 4 If provided, advertise the address:port combination as this authority\(cqs preferred directory port in its certificate\&. If the address is a hostname, the hostname is resolved to an IP before it\(cqs published\&. .RE .SH "BUGS" .sp This probably doesn\(cqt run on Windows\&. That\(cqs not a big issue, since we don\(cqt really want authorities to be running on Windows anyway\&. .SH "SEE ALSO" .sp \fBtor\fR(1) .sp See also the "dir\-spec\&.txt" file, distributed with Tor\&. .SH "AUTHORS" .sp .if n \{\ .RS 4 .\} .nf Roger Dingledine , Nick Mathewson \&. .fi .if n \{\ .RE .\} .SH "AUTHOR" .PP \fBNick Mathewson\fR .RS 4 Author. .RE tor-0.2.4.20/doc/torify.html.in0000644000175000017500000004344112166116250013044 00000000000000 torify(1)

SYNOPSIS

torify application [application’s arguments]

DESCRIPTION

torify is a simple wrapper that attempts to find the best underlying Tor wrapper available on a system. It calls torsocks with a tor specific configuration file.

torsocks is an improved wrapper that explicitly rejects UDP, safely resolves DNS lookups and properly socksifies your TCP connections.

Please note that since both method use LD_PRELOAD, torify cannot be applied to suid binaries.

WARNING

When used with torsocks, torify should not leak DNS requests or UDP data.

Both will leak ICMP data.

SEE ALSO

tor(1), tor-resolve(1), torsocks(1)

AUTHORS

Peter Palfrader and Jacob Appelbaum wrote this manual.


tor-0.2.4.20/doc/tor-fw-helper.html.in0000644000175000017500000004566112170370161014227 00000000000000 tor-fw-helper(1)

SYNOPSIS

tor-fw-helper [-h|--help] [-T|--test-commandline] [-v|--verbose] [-g|--fetch-public-ip] [-p external port:internal_port]

DESCRIPTION

tor-fw-helper currently supports Apple’s NAT-PMP protocol and the UPnP standard for TCP port mapping. It is written as the reference implementation of tor-fw-helper-spec.txt and conforms to that loose plugin API. If your network supports either NAT-PMP or UPnP, tor-fw-helper will attempt to automatically map the required TCP ports for Tor’s Or and Dir ports.

OPTIONS

-h or --help

Display help text and exit.

-v or --verbose

Display verbose output.

-T or --test-commandline

Display test information and print the test information in tor-fw-helper.log

-g or --fetch-public-ip

Fetch the the public ip address for each supported NAT helper method.

-p or --port external_port:internal_port

Forward external_port to internal_port. This option can appear more than once.

BUGS

This probably doesn’t run on Windows. That’s not a big issue, since we don’t really want to deal with Windows before October 2010 anyway.

SEE ALSO

tor(1)

See also the "tor-fw-helper-spec.txt" file, distributed with Tor.

AUTHORS

Jacob Appelbaum <jacob@torproject.org>, Steven J. Murdoch <Steven.Murdoch@cl.cam.ac.uk>

tor-0.2.4.20/doc/tor.html.in0000644000175000017500000051210012255753467012345 00000000000000 TOR(1)

SYNOPSIS

tor [OPTION value]…

DESCRIPTION

tor is a connection-oriented anonymizing communication service. Users choose a source-routed path through a set of nodes, and negotiate a "virtual circuit" through the network, in which each node knows its predecessor and successor, but no others. Traffic flowing down the circuit is unwrapped by a symmetric key at each node, which reveals the downstream node.

Basically tor provides a distributed network of servers ("onion routers"). Users bounce their TCP streams — web traffic, ftp, ssh, etc — around the routers, and recipients, observers, and even the routers themselves have difficulty tracking the source of the stream.

COMMAND-LINE OPTIONS

-h, -help

Display a short help message and exit.

-f FILE

Specify a new configuration file to contain further Tor configuration options. (Default: $HOME/.torrc, or @CONFDIR@/torrc if that file is not found)

--defaults-torrc FILE

Specify a file in which to find default values for Tor options. The contents of this file are overridden by those in the regular configuration file, and by those on the command line. (Default: @CONFDIR@/torrc-defaults.)

--hash-password

Generates a hashed password for control port access.

--list-fingerprint

Generate your keys and output your nickname and fingerprint.

--verify-config

Verify the configuration file is valid.

--service install [--options command-line options]

Install an instance of Tor as a Windows service, with the provided command-line options. Current instructions can be found at https://trac.torproject.org/projects/tor/wiki/doc/TorFAQ#HowdoIrunmyTorrelayasanNTservice

--service remove|start|stop

Remove, start, or stop a configured Tor Windows service.

--nt-service

Used internally to implement a Windows service.

--list-torrc-options

List all valid options.

--version

Display Tor version and exit.

--quiet|--hush

Override the default console log. By default, Tor starts out logging messages at level "notice" and higher to the console. It stops doing so after it parses its configuration, if the configuration tells it to log anywhere else. You can override this behavior with the --hush option, which tells Tor to only send warnings and errors to the console, or with the --quiet option, which tells Tor not to log to the console at all.

Other options can be specified on the command-line in the format "--option value", in the format "option value", or in a configuration file. For instance, you can tell Tor to start listening for SOCKS connections on port 9999 by passing --SOCKSPort 9999 or SOCKSPort 9999 to it on the command line, or by putting "SOCKSPort 9999" in the configuration file. You will need to quote options with spaces in them: if you want Tor to log all debugging messages to debug.log, you will probably need to say --Log debug file debug.log.

Options on the command line override those in configuration files. See the next section for more information.

THE CONFIGURATION FILE FORMAT

All configuration options in a configuration are written on a single line by default. They take the form of an option name and a value, or an option name and a quoted value (option value or option "value"). Anything after a # character is treated as a comment. Options are case-insensitive. C-style escaped characters are allowed inside quoted values. To split one configuration entry into multiple lines, use a single backslash character (\) before the end of the line. Comments can be used in such multiline entries, but they must start at the beginning of a line.

By default, an option on the command line overrides an option found in the configuration file, and an option in a configuration file overrides one in the defaults file.

This rule is simple for options that take a single value, but it can become complicated for options that are allowed to occur more than once: if you specify four SOCKSPorts in your configuration file, and one more SOCKSPort on the command line, the option on the command line will replace all of the SOCKSPorts in the configuration file. If this isn’t what you want, prefix the option name with a plus sign, and it will be appended to the previous set of options instead.

Alternatively, you might want to remove every instance of an option in the configuration file, and not replace it at all: you might want to say on the command line that you want no SOCKSPorts at all. To do that, prefix the option name with a forward slash.

GENERAL OPTIONS

BandwidthRate N bytes|KBytes|MBytes|GBytes

A token bucket limits the average incoming bandwidth usage on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value. If you want to run a relay in the public network, this needs to be at the very least 30 KBytes (that is, 30720 bytes). (Default: 1 GByte)

BandwidthBurst N bytes|KBytes|MBytes|GBytes

Limit the maximum token bucket size (also known as the burst) to the given number of bytes in each direction. (Default: 1 GByte)

MaxAdvertisedBandwidth N bytes|KBytes|MBytes|GBytes

If set, we will not advertise more than this amount of bandwidth for our BandwidthRate. Server operators who want to reduce the number of clients who ask to build circuits through them (since this is proportional to advertised bandwidth rate) can thus reduce the CPU demands on their server without impacting network performance.

RelayBandwidthRate N bytes|KBytes|MBytes|GBytes

If not 0, a separate token bucket limits the average incoming bandwidth usage for _relayed traffic_ on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value. Relayed traffic currently is calculated to include answers to directory requests, but that may change in future versions. (Default: 0)

RelayBandwidthBurst N bytes|KBytes|MBytes|GBytes

If not 0, limit the maximum token bucket size (also known as the burst) for _relayed traffic_ to the given number of bytes in each direction. (Default: 0)

PerConnBWRate N bytes|KBytes|MBytes|GBytes

If set, do separate rate limiting for each connection from a non-relay. You should never need to change this value, since a network-wide value is published in the consensus and your relay will use that value. (Default: 0)

PerConnBWBurst N bytes|KBytes|MBytes|GBytes

If set, do separate rate limiting for each connection from a non-relay. You should never need to change this value, since a network-wide value is published in the consensus and your relay will use that value. (Default: 0)

ClientTransportPlugin transport socks4|socks5 IP:PORT
ClientTransportPlugin transport exec path-to-binary [options]

In its first form, when set along with a corresponding Bridge line, the Tor client forwards its traffic to a SOCKS-speaking proxy on "IP:PORT". It’s the duty of that proxy to properly forward the traffic to the bridge.

In its second form, when set along with a corresponding Bridge line, the Tor client launches the pluggable transport proxy executable in path-to-binary using options as its command-line options, and forwards its traffic to it. It’s the duty of that proxy to properly forward the traffic to the bridge.

ServerTransportPlugin transport exec path-to-binary [options]

The Tor relay launches the pluggable transport proxy in path-to-binary using options as its command-line options, and expects to receive proxied client traffic from it.

ServerTransportListenAddr transport IP:PORT

When this option is set, Tor will suggest IP:PORT as the listening address of any pluggable transport proxy that tries to launch transport.

ConnLimit NUM

The minimum number of file descriptors that must be available to the Tor process before it will start. Tor will ask the OS for as many file descriptors as the OS will allow (you can find this by "ulimit -H -n"). If this number is less than ConnLimit, then Tor will refuse to start.

You probably don’t need to adjust this. It has no effect on Windows since that platform lacks getrlimit(). (Default: 1000)

DisableNetwork 0|1

When this option is set, we don’t listen for or accept any connections other than controller connections, and we don’t make any outbound connections. Controllers sometimes use this option to avoid using the network until Tor is fully configured. (Default: 0)

ConstrainedSockets 0|1

If set, Tor will tell the kernel to attempt to shrink the buffers for all sockets to the size specified in ConstrainedSockSize. This is useful for virtual servers and other environments where system level TCP buffers may be limited. If you’re on a virtual server, and you encounter the "Error creating network socket: No buffer space available" message, you are likely experiencing this problem.

The preferred solution is to have the admin increase the buffer pool for the host itself via /proc/sys/net/ipv4/tcp_mem or equivalent facility; this configuration option is a second-resort.

The DirPort option should also not be used if TCP buffers are scarce. The cached directory requests consume additional sockets which exacerbates the problem.

You should not enable this feature unless you encounter the "no buffer space available" issue. Reducing the TCP buffers affects window size for the TCP stream and will reduce throughput in proportion to round trip time on long paths. (Default: 0)

ConstrainedSockSize N bytes|KBytes

When ConstrainedSockets is enabled the receive and transmit buffers for all sockets will be set to this limit. Must be a value between 2048 and 262144, in 1024 byte increments. Default of 8192 is recommended.

ControlPort PORT|auto

If set, Tor will accept connections on this port and allow those connections to control the Tor process using the Tor Control Protocol (described in control-spec.txt). Note: unless you also specify one or more of HashedControlPassword or CookieAuthentication, setting this option will cause Tor to allow any process on the local host to control it. (Setting both authentication methods means either method is sufficient to authenticate to Tor.) This option is required for many Tor controllers; most use the value of 9051. Set it to "auto" to have Tor pick a port for you. (Default: 0)

ControlListenAddress IP[:PORT]

Bind the controller listener to this address. If you specify a port, bind to this port rather than the one specified in ControlPort. We strongly recommend that you leave this alone unless you know what you’re doing, since giving attackers access to your control listener is really dangerous. This directive can be specified multiple times to bind to multiple addresses/ports. (Default: 127.0.0.1)

ControlSocket Path

Like ControlPort, but listens on a Unix domain socket, rather than a TCP socket. (Unix and Unix-like systems only.)

ControlSocketsGroupWritable 0|1

If this option is set to 0, don’t allow the filesystem group to read and write unix sockets (e.g. ControlSocket). If the option is set to 1, make the control socket readable and writable by the default GID. (Default: 0)

HashedControlPassword hashed_password

Allow connections on the control port if they present the password whose one-way hash is hashed_password. You can compute the hash of a password by running "tor --hash-password password". You can provide several acceptable passwords by using more than one HashedControlPassword line.

CookieAuthentication 0|1

If this option is set to 1, allow connections on the control port when the connecting process knows the contents of a file named "control_auth_cookie", which Tor will create in its data directory. This authentication method should only be used on systems with good filesystem security. (Default: 0)

CookieAuthFile Path

If set, this option overrides the default location and file name for Tor’s cookie file. (See CookieAuthentication above.)

CookieAuthFileGroupReadable 0|1|Groupname

If this option is set to 0, don’t allow the filesystem group to read the cookie file. If the option is set to 1, make the cookie file readable by the default GID. [Making the file readable by other groups is not yet implemented; let us know if you need this for some reason.] (Default: 0)

ControlPortWriteToFile Path

If set, Tor writes the address and port of any control port it opens to this address. Usable by controllers to learn the actual control port when ControlPort is set to "auto".

ControlPortFileGroupReadable 0|1

If this option is set to 0, don’t allow the filesystem group to read the control port file. If the option is set to 1, make the control port file readable by the default GID. (Default: 0)

DataDirectory DIR

Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor)

FallbackDir address:port orport=port id=fingerprint [weight=num]

When we’re unable to connect to any directory cache for directory info (usually because we don’t know about any yet) we try a FallbackDir. By default, the directory authorities are also FallbackDirs.

DirAuthority [nickname] [flags] address:port fingerprint

Use a nonstandard authoritative directory server at the provided address and port, with the specified key fingerprint. This option can be repeated many times, for multiple authoritative directory servers. Flags are separated by spaces, and determine what kind of an authority this directory is. By default, every authority is authoritative for current ("v2")-style directories, unless the "no-v2" flag is given. If the "v1" flags is provided, Tor will use this server as an authority for old-style (v1) directories as well. (Only directory mirrors care about this.) Tor will use this server as an authority for hidden service information if the "hs" flag is set, or if the "v1" flag is set and the "no-hs" flag is not set. Tor will use this authority as a bridge authoritative directory if the "bridge" flag is set. If a flag "orport=port" is given, Tor will use the given port when opening encrypted tunnels to the dirserver. If a flag "weight=num" is given, then the directory server is chosen randomly with probability proportional to that weight (default 1.0). Lastly, if a flag "v3ident=fp" is given, the dirserver is a v3 directory authority whose v3 long-term signing key has the fingerprint fp.

If no DirAuthority line is given, Tor will use the default directory authorities. NOTE: this option is intended for setting up a private Tor network with its own directory authorities. If you use it, you will be distinguishable from other users, because you won’t believe the same authorities they do.

DirAuthorityFallbackRate NUM

When configured to use both directory authorities and fallback directories, the directory authorities also work as fallbacks. They are chosen with their regular weights, multiplied by this number, which should be 1.0 or less. (Default: 1.0)

DynamicDHGroups 0|1

If this option is set to 1, when running as a server, generate our own Diffie-Hellman group instead of using the one from Apache’s mod_ssl. This option may help circumvent censorship based on static Diffie-Hellman parameters. (Default: 0)

AlternateDirAuthority [nickname] [flags] address:port fingerprint

AlternateHSAuthority [nickname] [flags] address:port fingerprint

AlternateBridgeAuthority [nickname] [flags] address:port fingerprint

These options behave as DirAuthority, but they replace fewer of the default directory authorities. Using AlternateDirAuthority replaces the default Tor directory authorities, but leaves the default hidden service authorities and bridge authorities in place. Similarly, AlternateHSAuthority replaces the default hidden service authorities, but not the directory or bridge authorities; and AlternateBridgeAuthority replaces the default bridge authority, but leaves the directory and hidden service authorities alone.

DisableAllSwap 0|1

If set to 1, Tor will attempt to lock all current and future memory pages, so that memory cannot be paged out. Windows, OS X and Solaris are currently not supported. We believe that this feature works on modern Gnu/Linux distributions, and that it should work on *BSD systems (untested). This option requires that you start your Tor as root, and you should use the User option to properly reduce Tor’s privileges. (Default: 0)

DisableDebuggerAttachment 0|1

If set to 1, Tor will attempt to prevent basic debugging attachment attempts by other processes. This may also keep Tor from generating core files if it crashes. It has no impact for users who wish to attach if they have CAP_SYS_PTRACE or if they are root. We believe that this feature works on modern Gnu/Linux distributions, and that it may also work on *BSD systems (untested). Some modern Gnu/Linux systems such as Ubuntu have the kernel.yama.ptrace_scope sysctl and by default enable it as an attempt to limit the PTRACE scope for all user processes by default. This feature will attempt to limit the PTRACE scope for Tor specifically - it will not attempt to alter the system wide ptrace scope as it may not even exist. If you wish to attach to Tor with a debugger such as gdb or strace you will want to set this to 0 for the duration of your debugging. Normal users should leave it on. Disabling this option while Tor is running is prohibited. (Default: 1)

FetchDirInfoEarly 0|1

If set to 1, Tor will always fetch directory information like other directory caches, even if you don’t meet the normal criteria for fetching early. Normal users should leave it off. (Default: 0)

FetchDirInfoExtraEarly 0|1

If set to 1, Tor will fetch directory information before other directory caches. It will attempt to download directory information closer to the start of the consensus period. Normal users should leave it off. (Default: 0)

FetchHidServDescriptors 0|1

If set to 0, Tor will never fetch any hidden service descriptors from the rendezvous directories. This option is only useful if you’re using a Tor controller that handles hidden service fetches for you. (Default: 1)

FetchServerDescriptors 0|1

If set to 0, Tor will never fetch any network status summaries or server descriptors from the directory servers. This option is only useful if you’re using a Tor controller that handles directory fetches for you. (Default: 1)

FetchUselessDescriptors 0|1

If set to 1, Tor will fetch every non-obsolete descriptor from the authorities that it hears about. Otherwise, it will avoid fetching useless descriptors, for example for routers that are not running. This option is useful if you’re using the contributed "exitlist" script to enumerate Tor nodes that exit to certain addresses. (Default: 0)

HTTPProxy host[:port]

Tor will make all its directory requests through this host:port (or host:80 if port is not specified), rather than connecting directly to any directory servers.

HTTPProxyAuthenticator username:password

If defined, Tor will use this username:password for Basic HTTP proxy authentication, as in RFC 2617. This is currently the only form of HTTP proxy authentication that Tor supports; feel free to submit a patch if you want it to support others.

HTTPSProxy host[:port]

Tor will make all its OR (SSL) connections through this host:port (or host:443 if port is not specified), via HTTP CONNECT rather than connecting directly to servers. You may want to set FascistFirewall to restrict the set of ports you might try to connect to, if your HTTPS proxy only allows connecting to certain ports.

HTTPSProxyAuthenticator username:password

If defined, Tor will use this username:password for Basic HTTPS proxy authentication, as in RFC 2617. This is currently the only form of HTTPS proxy authentication that Tor supports; feel free to submit a patch if you want it to support others.

Socks4Proxy host[:port]

Tor will make all OR connections through the SOCKS 4 proxy at host:port (or host:1080 if port is not specified).

Socks5Proxy host[:port]

Tor will make all OR connections through the SOCKS 5 proxy at host:port (or host:1080 if port is not specified).

Socks5ProxyUsername username

Socks5ProxyPassword password

If defined, authenticate to the SOCKS 5 server using username and password in accordance to RFC 1929. Both username and password must be between 1 and 255 characters.

KeepalivePeriod NUM

To keep firewalls from expiring connections, send a padding keepalive cell every NUM seconds on open connections that are in use. If the connection has no open circuits, it will instead be closed after NUM seconds of idleness. (Default: 5 minutes)

Log minSeverity[-maxSeverity] stderr|stdout|syslog

Send all messages between minSeverity and maxSeverity to the standard output stream, the standard error stream, or to the system log. (The "syslog" value is only supported on Unix.) Recognized severity levels are debug, info, notice, warn, and err. We advise using "notice" in most cases, since anything more verbose may provide sensitive information to an attacker who obtains the logs. If only one severity level is given, all messages of that level or higher will be sent to the listed destination.

Log minSeverity[-maxSeverity] file FILENAME

As above, but send log messages to the listed filename. The "Log" option may appear more than once in a configuration file. Messages are sent to all the logs that match their severity level.

Log [domain,…]minSeverity[-maxSeverity] … file FILENAME

Log [domain,…]minSeverity[-maxSeverity] … stderr|stdout|syslog

As above, but select messages by range of log severity and by a set of "logging domains". Each logging domain corresponds to an area of functionality inside Tor. You can specify any number of severity ranges for a single log statement, each of them prefixed by a comma-separated list of logging domains. You can prefix a domain with ~ to indicate negation, and use * to indicate "all domains". If you specify a severity range without a list of domains, it matches all domains.

This is an advanced feature which is most useful for debugging one or two of Tor’s subsystems at a time.

The currently recognized domains are: general, crypto, net, config, fs, protocol, mm, http, app, control, circ, rend, bug, dir, dirserv, or, edge, acct, hist, and handshake. Domain names are case-insensitive.

For example, "Log [handshake]debug [~net,~mm]info notice stdout" sends to stdout: all handshake messages of any severity, all info-and-higher messages from domains other than networking and memory management, and all messages of severity notice or higher.

LogMessageDomains 0|1

If 1, Tor includes message domains with each log message. Every log message currently has at least one domain; most currently have exactly one. This doesn’t affect controller log messages. (Default: 0)

OutboundBindAddress IP

Make all outbound connections originate from the IP address specified. This is only useful when you have multiple network interfaces, and you want all of Tor’s outgoing connections to use a single one. This option may be used twice, once with an IPv4 address and once with an IPv6 address. This setting will be ignored for connections to the loopback addresses (127.0.0.0/8 and ::1).

PidFile FILE

On startup, write our PID to FILE. On clean shutdown, remove FILE.

ProtocolWarnings 0|1

If 1, Tor will log with severity 'warn' various cases of other parties not following the Tor specification. Otherwise, they are logged with severity 'info'. (Default: 0)

RunAsDaemon 0|1

If 1, Tor forks and daemonizes to the background. This option has no effect on Windows; instead you should use the --service command-line option. (Default: 0)

LogTimeGranularity NUM

Set the resolution of timestamps in Tor’s logs to NUM milliseconds. NUM must be positive and either a divisor or a multiple of 1 second. Note that this option only controls the granularity written by Tor to a file or console log. Tor does not (for example) "batch up" log messages to affect times logged by a controller, times attached to syslog messages, or the mtime fields on log files. (Default: 1 second)

SafeLogging 0|1|relay

Tor can scrub potentially sensitive strings from log messages (e.g. addresses) by replacing them with the string [scrubbed]. This way logs can still be useful, but they don’t leave behind personally identifying information about what sites a user might have visited.

If this option is set to 0, Tor will not perform any scrubbing, if it is set to 1, all potentially sensitive strings are replaced. If it is set to relay, all log messages generated when acting as a relay are sanitized, but all messages generated when acting as a client are not. (Default: 1)

User UID

On startup, setuid to this user and setgid to their primary group.

HardwareAccel 0|1

If non-zero, try to use built-in (static) crypto hardware acceleration when available. (Default: 0)

AccelName NAME

When using OpenSSL hardware crypto acceleration attempt to load the dynamic engine of this name. This must be used for any dynamic hardware engine. Names can be verified with the openssl engine command.

AccelDir DIR

Specify this option if using dynamic hardware acceleration and the engine implementation library resides somewhere other than the OpenSSL default.

AvoidDiskWrites 0|1

If non-zero, try to write to disk less frequently than we would otherwise. This is useful when running on flash memory or other media that support only a limited number of writes. (Default: 0)

TunnelDirConns 0|1

If non-zero, when a directory server we contact supports it, we will build a one-hop circuit and make an encrypted connection via its ORPort. (Default: 1)

PreferTunneledDirConns 0|1

If non-zero, we will avoid directory servers that don’t support tunneled directory connections, when possible. (Default: 1)

CircuitPriorityHalflife NUM1

If this value is set, we override the default algorithm for choosing which circuit’s cell to deliver or relay next. When the value is 0, we round-robin between the active circuits on a connection, delivering one cell from each in turn. When the value is positive, we prefer delivering cells from whichever connection has the lowest weighted cell count, where cells are weighted exponentially according to the supplied CircuitPriorityHalflife value (in seconds). If this option is not set at all, we use the behavior recommended in the current consensus networkstatus. This is an advanced option; you generally shouldn’t have to mess with it. (Default: not set)

DisableIOCP 0|1

If Tor was built to use the Libevent’s "bufferevents" networking code and you’re running on Windows, setting this option to 1 will tell Libevent not to use the Windows IOCP networking API. (Default: 1)

UserspaceIOCPBuffers 0|1

If IOCP is enabled (see DisableIOCP above), setting this option to 1 will tell Tor to disable kernel-space TCP buffers, in order to avoid needless copy operations and try not to run out of non-paged RAM. This feature is experimental; don’t use it yet unless you’re eager to help tracking down bugs. (Default: 0)

_UseFilteringSSLBufferevents 0|1

Tells Tor to do its SSL communication using a chain of bufferevents: one for SSL and one for networking. This option has no effect if bufferevents are disabled (in which case it can’t turn on), or if IOCP bufferevents are enabled (in which case it can’t turn off). This option is useful for debugging only; most users shouldn’t touch it. (Default: 0)

CountPrivateBandwidth 0|1

If this option is set, then Tor’s rate-limiting applies not only to remote connections, but also to connections to private addresses like 127.0.0.1 or 10.0.0.1. This is mostly useful for debugging rate-limiting. (Default: 0)

CLIENT OPTIONS

The following options are useful only for clients (that is, if SocksPort, TransPort, DNSPort, or NATDPort is non-zero):

AllowInvalidNodes entry|exit|middle|introduction|rendezvous|

If some Tor servers are obviously not working right, the directory authorities can manually mark them as invalid, meaning that it’s not recommended you use them for entry or exit positions in your circuits. You can opt to use them in some circuit positions, though. The default is "middle,rendezvous", and other choices are not advised.

ExcludeSingleHopRelays 0|1

This option controls whether circuits built by Tor will include relays with the AllowSingleHopExits flag set to true. If ExcludeSingleHopRelays is set to 0, these relays will be included. Note that these relays might be at higher risk of being seized or observed, so they are not normally included. Also note that relatively few clients turn off this option, so using these relays might make your client stand out. (Default: 1)

Bridge [transport] IP:ORPort [fingerprint]

When set along with UseBridges, instructs Tor to use the relay at "IP:ORPort" as a "bridge" relaying into the Tor network. If "fingerprint" is provided (using the same format as for DirAuthority), we will verify that the relay running at that location has the right fingerprint. We also use fingerprint to look up the bridge descriptor at the bridge authority, if it’s provided and if UpdateBridgesFromAuthority is set too.

If "transport" is provided, and matches to a ClientTransportPlugin line, we use that pluggable transports proxy to transfer data to the bridge.

LearnCircuitBuildTimeout 0|1

If 0, CircuitBuildTimeout adaptive learning is disabled. (Default: 1)

CircuitBuildTimeout NUM

Try for at most NUM seconds when building circuits. If the circuit isn’t open in that time, give up on it. If LearnCircuitBuildTimeout is 1, this value serves as the initial value to use before a timeout is learned. If LearnCircuitBuildTimeout is 0, this value is the only value used. (Default: 60 seconds)

CircuitIdleTimeout NUM

If we have kept a clean (never used) circuit around for NUM seconds, then close it. This way when the Tor client is entirely idle, it can expire all of its circuits, and then expire its TLS connections. Also, if we end up making a circuit that is not useful for exiting any of the requests we’re receiving, it won’t forever take up a slot in the circuit list. (Default: 1 hour)

CircuitStreamTimeout NUM

If non-zero, this option overrides our internal timeout schedule for how many seconds until we detach a stream from a circuit and try a new circuit. If your network is particularly slow, you might want to set this to a number like 60. (Default: 0)

ClientOnly 0|1

If set to 1, Tor will under no circumstances run as a relay or serve directory requests. This config option is mostly meaningless: we added it back when we were considering having Tor clients auto-promote themselves to being relays if they were stable and fast enough. The current behavior is simply that Tor is a client unless ORPort or DirPort are configured. (Default: 0)

ExcludeNodes node,node,

A list of identity fingerprints, nicknames, country codes and address patterns of nodes to avoid when building a circuit. (Example: ExcludeNodes SlowServer, ABCD1234CDEF5678ABCD1234CDEF5678ABCD1234, {cc}, 255.254.0.0/8)

By default, this option is treated as a preference that Tor is allowed to override in order to keep working. For example, if you try to connect to a hidden service, but you have excluded all of the hidden service’s introduction points, Tor will connect to one of them anyway. If you do not want this behavior, set the StrictNodes option (documented below).

Note also that if you are a relay, this (and the other node selection options below) only affects your own circuits that Tor builds for you. Clients can still build circuits through you to any node. Controllers can tell Tor to build circuits through any node.

Country codes are case-insensitive. The code "{??}" refers to nodes whose country can’t be identified. No country code, including {??}, works if no GeoIPFile can be loaded. See also the GeoIPExcludeUnknown option below.

ExcludeExitNodes node,node,

A list of identity fingerprints, nicknames, country codes and address patterns of nodes to never use when picking an exit node---that is, a node that delivers traffic for you outside the Tor network. Note that any node listed in ExcludeNodes is automatically considered to be part of this list too. See also the caveats on the "ExitNodes" option below.

GeoIPExcludeUnknown 0|1|auto

If this option is set to auto, then whenever any country code is set in ExcludeNodes or ExcludeExitNodes, all nodes with unknown country ({??} and possibly {A1}) are treated as excluded as well. If this option is set to 1, then all unknown countries are treated as excluded in ExcludeNodes and ExcludeExitNodes. This option has no effect when a GeoIP file isn’t configured or can’t be found. (Default: auto)

ExitNodes node,node,

A list of identity fingerprints, nicknames, country codes and address patterns of nodes to use as exit node---that is, a node that delivers traffic for you outside the Tor network.

Note that if you list too few nodes here, or if you exclude too many exit nodes with ExcludeExitNodes, you can degrade functionality. For example, if none of the exits you list allows traffic on port 80 or 443, you won’t be able to browse the web.

Note also that not every circuit is used to deliver traffic outside of the Tor network. It is normal to see non-exit circuits (such as those used to connect to hidden services, those that do directory fetches, those used for relay reachability self-tests, and so on) that end at a non-exit node. To keep a node from being used entirely, see ExcludeNodes and StrictNodes.

The ExcludeNodes option overrides this option: any node listed in both ExitNodes and ExcludeNodes is treated as excluded.

The .exit address notation, if enabled via AllowDotExit, overrides this option.

EntryNodes node,node,

A list of identity fingerprints, nicknames, and country codes of nodes to use for the first hop in your normal circuits. Normal circuits include all circuits except for direct connections to directory servers. The Bridge option overrides this option; if you have configured bridges and UseBridges is 1, the Bridges are used as your entry nodes.

The ExcludeNodes option overrides this option: any node listed in both EntryNodes and ExcludeNodes is treated as excluded.

StrictNodes 0|1

If StrictNodes is set to 1, Tor will treat the ExcludeNodes option as a requirement to follow for all the circuits you generate, even if doing so will break functionality for you. If StrictNodes is set to 0, Tor will still try to avoid nodes in the ExcludeNodes list, but it will err on the side of avoiding unexpected errors. Specifically, StrictNodes 0 tells Tor that it is okay to use an excluded node when it is necessary to perform relay reachability self-tests, connect to a hidden service, provide a hidden service to a client, fulfill a .exit request, upload directory information, or download directory information. (Default: 0)

FascistFirewall 0|1

If 1, Tor will only create outgoing connections to ORs running on ports that your firewall allows (defaults to 80 and 443; see FirewallPorts). This will allow you to run Tor as a client behind a firewall with restrictive policies, but will not allow you to run as a server behind such a firewall. If you prefer more fine-grained control, use ReachableAddresses instead.

FirewallPorts PORTS

A list of ports that your firewall allows you to connect to. Only used when FascistFirewall is set. This option is deprecated; use ReachableAddresses instead. (Default: 80, 443)

ReachableAddresses ADDR[/MASK][:PORT]…

A comma-separated list of IP addresses and ports that your firewall allows you to connect to. The format is as for the addresses in ExitPolicy, except that "accept" is understood unless "reject" is explicitly provided. For example, 'ReachableAddresses 99.0.0.0/8, reject 18.0.0.0/8:80, accept *:80' means that your firewall allows connections to everything inside net 99, rejects port 80 connections to net 18, and accepts connections to port 80 otherwise. (Default: 'accept *:*'.)

ReachableDirAddresses ADDR[/MASK][:PORT]…

Like ReachableAddresses, a list of addresses and ports. Tor will obey these restrictions when fetching directory information, using standard HTTP GET requests. If not set explicitly then the value of ReachableAddresses is used. If HTTPProxy is set then these connections will go through that proxy.

ReachableORAddresses ADDR[/MASK][:PORT]…

Like ReachableAddresses, a list of addresses and ports. Tor will obey these restrictions when connecting to Onion Routers, using TLS/SSL. If not set explicitly then the value of ReachableAddresses is used. If HTTPSProxy is set then these connections will go through that proxy.

The separation between ReachableORAddresses and ReachableDirAddresses is only interesting when you are connecting through proxies (see HTTPProxy and HTTPSProxy). Most proxies limit TLS connections (which Tor uses to connect to Onion Routers) to port 443, and some limit HTTP GET requests (which Tor uses for fetching directory information) to port 80.

HidServAuth onion-address auth-cookie [service-name]

Client authorization for a hidden service. Valid onion addresses contain 16 characters in a-z2-7 plus ".onion", and valid auth cookies contain 22 characters in A-Za-z0-9+/. The service name is only used for internal purposes, e.g., for Tor controllers. This option may be used multiple times for different hidden services. If a hidden service uses authorization and this option is not set, the hidden service is not accessible. Hidden services can be configured to require authorization using the HiddenServiceAuthorizeClient option.

CloseHSClientCircuitsImmediatelyOnTimeout 0|1

If 1, Tor will close unfinished hidden service client circuits which have not moved closer to connecting to their destination hidden service when their internal state has not changed for the duration of the current circuit-build timeout. Otherwise, such circuits will be left open, in the hope that they will finish connecting to their destination hidden services. In either case, another set of introduction and rendezvous circuits for the same destination hidden service will be launched. (Default: 0)

CloseHSServiceRendCircuitsImmediatelyOnTimeout 0|1

If 1, Tor will close unfinished hidden-service-side rendezvous circuits after the current circuit-build timeout. Otherwise, such circuits will be left open, in the hope that they will finish connecting to their destinations. In either case, another rendezvous circuit for the same destination client will be launched. (Default: 0)

LongLivedPorts PORTS

A list of ports for services that tend to have long-running connections (e.g. chat and interactive shells). Circuits for streams that use these ports will contain only high-uptime nodes, to reduce the chance that a node will go down before the stream is finished. Note that the list is also honored for circuits (both client and service side) involving hidden services whose virtual port is in this list. (Default: 21, 22, 706, 1863, 5050, 5190, 5222, 5223, 6523, 6667, 6697, 8300)

MapAddress address newaddress

When a request for address arrives to Tor, it will transform to newaddress before processing it. For example, if you always want connections to www.example.com to exit via torserver (where torserver is the nickname of the server), use "MapAddress www.example.com www.example.com.torserver.exit". If the value is prefixed with a "*.", matches an entire domain. For example, if you always want connections to example.com and any if its subdomains to exit via torserver (where torserver is the nickname of the server), use "MapAddress *.example.com *.example.com.torserver.exit". (Note the leading "*." in each part of the directive.) You can also redirect all subdomains of a domain to a single address. For example, "MapAddress *.example.com www.example.com".

NOTES:

  1. When evaluating MapAddress expressions Tor stops when it hits the most recently added expression that matches the requested address. So if you have the following in your torrc, www.torproject.org will map to 1.1.1.1:

    MapAddress www.torproject.org 2.2.2.2
    MapAddress www.torproject.org 1.1.1.1
  2. Tor evaluates the MapAddress configuration until it finds no matches. So if you have the following in your torrc, www.torproject.org will map to 2.2.2.2:

    MapAddress 1.1.1.1 2.2.2.2
    MapAddress www.torproject.org 1.1.1.1
  3. The following MapAddress expression is invalid (and will be ignored) because you cannot map from a specific address to a wildcard address:

    MapAddress www.torproject.org *.torproject.org.torserver.exit
  4. Using a wildcard to match only part of a string (as in *ample.com) is also invalid.

NewCircuitPeriod NUM

Every NUM seconds consider whether to build a new circuit. (Default: 30 seconds)

MaxCircuitDirtiness NUM

Feel free to reuse a circuit that was first used at most NUM seconds ago, but never attach a new stream to a circuit that is too old. For hidden services, this applies to the last time a circuit was used, not the first. (Default: 10 minutes)

MaxClientCircuitsPending NUM

Do not allow more than NUM circuits to be pending at a time for handling client streams. A circuit is pending if we have begun constructing it, but it has not yet been completely constructed. (Default: 32)

NodeFamily node,node,

The Tor servers, defined by their identity fingerprints or nicknames, constitute a "family" of similar or co-administered servers, so never use any two of them in the same circuit. Defining a NodeFamily is only needed when a server doesn’t list the family itself (with MyFamily). This option can be used multiple times. In addition to nodes, you can also list IP address and ranges and country codes in {curly braces}.

EnforceDistinctSubnets 0|1

If 1, Tor will not put two servers whose IP addresses are "too close" on the same circuit. Currently, two addresses are "too close" if they lie in the same /16 range. (Default: 1)

SOCKSPort [address:]port|auto [flags] [isolation flags]

Open this port to listen for connections from SOCKS-speaking applications. Set this to 0 if you don’t want to allow application connections via SOCKS. Set it to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. (Default: 9050)

The isolation flags arguments give Tor rules for which streams received on this SOCKSPort are allowed to share circuits with one another. Recognized isolation flags are:

IsolateClientAddr

Don’t share circuits with streams from a different client address. (On by default and strongly recommended; you can disable it with NoIsolateClientAddr.)

IsolateSOCKSAuth

Don’t share circuits with streams for which different SOCKS authentication was provided. (On by default; you can disable it with NoIsolateSOCKSAuth.)

IsolateClientProtocol

Don’t share circuits with streams using a different protocol. (SOCKS 4, SOCKS 5, TransPort connections, NATDPort connections, and DNSPort requests are all considered to be different protocols.)

IsolateDestPort

Don’t share circuits with streams targetting a different destination port.

IsolateDestAddr

Don’t share circuits with streams targetting a different destination address.

SessionGroup=INT

If no other isolation rules would prevent it, allow streams on this port to share circuits with streams from every other port with the same session group. (By default, streams received on different SOCKSPorts, TransPorts, etc are always isolated from one another. This option overrides that behavior.)

Other recognized _flags_ for a SOCKSPort are:
**NoIPv4Traffic**;;
    Tell exits to not connect to IPv4 addresses in response to SOCKS
    requests on this connection.
**IPv6Traffic**;;
    Tell exits to allow IPv6 addresses in response to SOCKS requests on
    this connection, so long as SOCKS5 is in use.  (SOCKS4 can't handle
    IPv6.)
**PreferIPv6**;;
    Tells exits that, if a host has both an IPv4 and an IPv6 address,
    we would prefer to connect to it via IPv6. (IPv4 is the default.) +
   NOTE: Although this option allows you to specify an IP address
   other than localhost, you should do so only with extreme caution.
   The SOCKS protocol is unencrypted and (as we use it)
   unauthenticated, so exposing it in this way could leak your
   information to anybody watching your network, and allow anybody
   to use your computer as an open proxy.
**CacheIPv4DNS**;;
    Tells the client to remember IPv4 DNS answers we receive from exit
    nodes via this connection. (On by default.)
**CacheIPv6DNS**;;
    Tells the client to remember IPv6 DNS answers we receive from exit
    nodes via this connection.
**CacheDNS**;;
    Tells the client to remember all DNS answers we receive from exit
    nodes via this connection.
**UseIPv4Cache**;;
    Tells the client to use any cached IPv4 DNS answers we have when making
    requests via this connection. (NOTE: This option, along UseIPv6Cache
    and UseDNSCache, can harm your anonymity, and probably
    won't help performance as much as you might expect. Use with care!)
**UseIPv6Cache**;;
    Tells the client to use any cached IPv6 DNS answers we have when making
    requests via this connection.
**UseDNSCache**;;
    Tells the client to use any cached DNS answers we have when making
    requests via this connection.
**PreferIPv6Automap**;;
    When serving a hostname lookup request on this port that
    should get automapped (according to AutomapHostsOnResove),
    if we could return either an IPv4 or an IPv6 answer, prefer
    an IPv6 answer. (On by default.)
**PreferSOCKSNoAuth**;;
    Ordinarily, when an application offers both "username/password
    authentication" and "no authentication" to Tor via SOCKS5, Tor
    selects username/password authentication so that IsolateSOCKSAuth can
    work.  This can confuse some applications, if they offer a
    username/password combination then get confused when asked for
    one. You can disable this behavior, so that Tor will select "No
    authentication" when IsolateSOCKSAuth is disabled, or when this
    option is set.
SOCKSListenAddress IP[:PORT]

Bind to this address to listen for connections from Socks-speaking applications. (Default: 127.0.0.1) You can also specify a port (e.g. 192.168.0.1:9100). This directive can be specified multiple times to bind to multiple addresses/ports. (DEPRECATED: As of 0.2.3.x-alpha, you can now use multiple SOCKSPort entries, and provide addresses for SOCKSPort entries, so SOCKSListenAddress no longer has a purpose. For backward compatibility, SOCKSListenAddress is only allowed when SOCKSPort is just a port number.)

SocksPolicy policy,policy,

Set an entrance policy for this server, to limit who can connect to the SocksPort and DNSPort ports. The policies have the same form as exit policies below.

SocksTimeout NUM

Let a socks connection wait NUM seconds handshaking, and NUM seconds unattached waiting for an appropriate circuit, before we fail it. (Default: 2 minutes)

TokenBucketRefillInterval NUM [msec|second]

Set the refill interval of Tor’s token bucket to NUM milliseconds. NUM must be between 1 and 1000, inclusive. Note that the configured bandwidth limits are still expressed in bytes per second: this option only affects the frequency with which Tor checks to see whether previously exhausted connections may read again. (Default: 100 msec)

TrackHostExits host,.domain,

For each value in the comma separated list, Tor will track recent connections to hosts that match this value and attempt to reuse the same exit node for each. If the value is prepended with a '.', it is treated as matching an entire domain. If one of the values is just a '.', it means match everything. This option is useful if you frequently connect to sites that will expire all your authentication cookies (i.e. log you out) if your IP address changes. Note that this option does have the disadvantage of making it more clear that a given history is associated with a single user. However, most people who would wish to observe this will observe it through cookies or other protocol-specific means anyhow.

TrackHostExitsExpire NUM

Since exit servers go up and down, it is desirable to expire the association between host and exit server after NUM seconds. The default is 1800 seconds (30 minutes).

UpdateBridgesFromAuthority 0|1

When set (along with UseBridges), Tor will try to fetch bridge descriptors from the configured bridge authorities when feasible. It will fall back to a direct request if the authority responds with a 404. (Default: 0)

UseBridges 0|1

When set, Tor will fetch descriptors for each bridge listed in the "Bridge" config lines, and use these relays as both entry guards and directory guards. (Default: 0)

UseEntryGuards 0|1

If this option is set to 1, we pick a few long-term entry servers, and try to stick with them. This is desirable because constantly changing servers increases the odds that an adversary who owns some servers will observe a fraction of your paths. (Default: 1)

UseEntryGuardsAsDirectoryGuards 0|1

If this option is set to 1, and UseEntryGuards is also set to 1, we try to use our entry guards as directory guards, and failing that, pick more nodes to act as our directory guards. This helps prevent an adversary from enumerating clients. It’s only available for clients (non-relay, non-bridge) that aren’t configured to download any non-default directory material. It doesn’t currently do anything when we lack a live consensus. (Default: 1)

NumEntryGuards NUM

If UseEntryGuards is set to 1, we will try to pick a total of NUM routers as long-term entries for our circuits. (Default: 3)

NumDirectoryGuards NUM

If UseEntryGuardsAsDirectoryGuards is enabled, we try to make sure we have at least NUM routers to use as directory guards. If this option is set to 0, use the value from NumEntryGuards. (Default: 0)

GuardLifetime N days|weeks|months

If nonzero, and UseEntryGuards is set, minimum time to keep a guard before picking a new one. If zero, we use the GuardLifetime parameter from the consensus directory. No value here may be less than 1 month or greater than 5 years; out-of-range values are clamped. (Default: 0)

SafeSocks 0|1

When this option is enabled, Tor will reject application connections that use unsafe variants of the socks protocol — ones that only provide an IP address, meaning the application is doing a DNS resolve first. Specifically, these are socks4 and socks5 when not doing remote DNS. (Default: 0)

TestSocks 0|1

When this option is enabled, Tor will make a notice-level log entry for each connection to the Socks port indicating whether the request used a safe socks protocol or an unsafe one (see above entry on SafeSocks). This helps to determine whether an application using Tor is possibly leaking DNS requests. (Default: 0)

WarnUnsafeSocks 0|1

When this option is enabled, Tor will warn whenever a request is received that only contains an IP address instead of a hostname. Allowing applications to do DNS resolves themselves is usually a bad idea and can leak your location to attackers. (Default: 1)

VirtualAddrNetworkIPv4 Address/bits

VirtualAddrNetworkIPv6 [Address]/bits

When Tor needs to assign a virtual (unused) address because of a MAPADDRESS command from the controller or the AutomapHostsOnResolve feature, Tor picks an unassigned address from this range. (Defaults: 127.192.0.0/10 and [FE80::]/10 respectively.)

When providing proxy server service to a network of computers using a tool like dns-proxy-tor, change the IPv4 network to "10.192.0.0/10" or "172.16.0.0/12" and change the IPv6 network to "[FC00]/7". The default VirtualAddrNetwork address ranges on a properly configured machine will route to the loopback or link-local interface. For local use, no change to the default VirtualAddrNetwork setting is needed.

AllowNonRFC953Hostnames 0|1

When this option is disabled, Tor blocks hostnames containing illegal characters (like @ and :) rather than sending them to an exit node to be resolved. This helps trap accidental attempts to resolve URLs and so on. (Default: 0)

AllowDotExit 0|1

If enabled, we convert "www.google.com.foo.exit" addresses on the SocksPort/TransPort/NATDPort into "www.google.com" addresses that exit from the node "foo". Disabled by default since attacking websites and exit relays can use it to manipulate your path selection. (Default: 0)

FastFirstHopPK 0|1

When this option is disabled, Tor uses the public key step for the first hop of creating circuits. Skipping it is generally safe since we have already used TLS to authenticate the relay and to establish forward-secure keys. Turning this option off makes circuit building slower.

Note that Tor will always use the public key step for the first hop if it’s operating as a relay, and it will never use the public key step if it doesn’t yet know the onion key of the first hop. (Default: 1)

TransPort [address:]port|auto [isolation flags]

Open this port to listen for transparent proxy connections. Set this to 0 if you don’t want to allow transparent proxy connections. Set the port to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. See SOCKSPort for an explanation of isolation flags.

TransPort requires OS support for transparent proxies, such as BSDs' pf or Linux’s IPTables. If you’re planning to use Tor as a transparent proxy for a network, you’ll want to examine and change VirtualAddrNetwork from the default setting. You’ll also want to set the TransListenAddress option for the network you’d like to proxy. (Default: 0)

TransListenAddress IP[:PORT]

Bind to this address to listen for transparent proxy connections. (Default: 127.0.0.1). This is useful for exporting a transparent proxy server to an entire network. (DEPRECATED: As of 0.2.3.x-alpha, you can now use multiple TransPort entries, and provide addresses for TransPort entries, so TransListenAddress no longer has a purpose. For backward compatibility, TransListenAddress is only allowed when TransPort is just a port number.)

NATDPort [address:]port|auto [isolation flags]

Open this port to listen for connections from old versions of ipfw (as included in old versions of FreeBSD, etc) using the NATD protocol. Use 0 if you don’t want to allow NATD connections. Set the port to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. See SOCKSPort for an explanation of isolation flags.

This option is only for people who cannot use TransPort. (Default: 0)

NATDListenAddress IP[:PORT]

Bind to this address to listen for NATD connections. (DEPRECATED: As of 0.2.3.x-alpha, you can now use multiple NATDPort entries, and provide addresses for NATDPort entries, so NATDListenAddress no longer has a purpose. For backward compatibility, NATDListenAddress is only allowed when NATDPort is just a port number.)

AutomapHostsOnResolve 0|1

When this option is enabled, and we get a request to resolve an address that ends with one of the suffixes in AutomapHostsSuffixes, we map an unused virtual address to that address, and return the new virtual address. This is handy for making ".onion" addresses work with applications that resolve an address and then connect to it. (Default: 0)

AutomapHostsSuffixes SUFFIX,SUFFIX,

A comma-separated list of suffixes to use with AutomapHostsOnResolve. The "." suffix is equivalent to "all addresses." (Default: .exit,.onion).

DNSPort [address:]port|auto [isolation flags]

If non-zero, open this port to listen for UDP DNS requests, and resolve them anonymously. This port only handles A, AAAA, and PTR requests---it doesn’t handle arbitrary DNS request types. Set the port to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. See SOCKSPort for an explanation of isolation flags. (Default: 0)

DNSListenAddress IP[:PORT]

Bind to this address to listen for DNS connections. (DEPRECATED: As of 0.2.3.x-alpha, you can now use multiple DNSPort entries, and provide addresses for DNSPort entries, so DNSListenAddress no longer has a purpose. For backward compatibility, DNSListenAddress is only allowed when DNSPort is just a port number.)

ClientDNSRejectInternalAddresses 0|1

If true, Tor does not believe any anonymously retrieved DNS answer that tells it that an address resolves to an internal address (like 127.0.0.1 or 192.168.0.1). This option prevents certain browser-based attacks; don’t turn it off unless you know what you’re doing. (Default: 1)

ClientRejectInternalAddresses 0|1

If true, Tor does not try to fulfill requests to connect to an internal address (like 127.0.0.1 or 192.168.0.1) unless a exit node is specifically requested (for example, via a .exit hostname, or a controller request). (Default: 1)

DownloadExtraInfo 0|1

If true, Tor downloads and caches "extra-info" documents. These documents contain information about servers other than the information in their regular router descriptors. Tor does not use this information for anything itself; to save bandwidth, leave this option turned off. (Default: 0)

WarnPlaintextPorts port,port,

Tells Tor to issue a warnings whenever the user tries to make an anonymous connection to one of these ports. This option is designed to alert users to services that risk sending passwords in the clear. (Default: 23,109,110,143)

RejectPlaintextPorts port,port,

Like WarnPlaintextPorts, but instead of warning about risky port uses, Tor will instead refuse to make the connection. (Default: None)

AllowSingleHopCircuits 0|1

When this option is set, the attached Tor controller can use relays that have the AllowSingleHopExits option turned on to build one-hop Tor connections. (Default: 0)

OptimisticData 0|1|auto

When this option is set, and Tor is using an exit node that supports the feature, it will try optimistically to send data to the exit node without waiting for the exit node to report whether the connection succeeded. This can save a round-trip time for protocols like HTTP where the client talks first. If OptimisticData is set to auto, Tor will look at the UseOptimisticData parameter in the networkstatus. (Default: auto)

Tor2webMode 0|1

When this option is set, Tor connects to hidden services non-anonymously. This option also disables client connections to non-hidden-service hostnames through Tor. It must only be used when running a tor2web Hidden Service web proxy. To enable this option the compile time flag --enable-tor2webmode must be specified. (Default: 0)

UseMicrodescriptors 0|1|auto

Microdescriptors are a smaller version of the information that Tor needs in order to build its circuits. Using microdescriptors makes Tor clients download less directory information, thus saving bandwidth. Directory caches need to fetch regular descriptors and microdescriptors, so this option doesn’t save any bandwidth for them. If this option is set to "auto" (recommended) then it is on for all clients that do not set FetchUselessDescriptors. (Default: auto)

UseNTorHandshake 0|1|auto

The "ntor" circuit-creation handshake is faster and (we think) more secure than the original ("TAP") circuit handshake, but starting to use it too early might make your client stand out. If this option is 0, your Tor client won’t use the ntor handshake. If it’s 1, your Tor client will use the ntor handshake to extend circuits through servers that support it. If this option is "auto" (recommended), then your client will use the ntor handshake once enough directory authorities recommend it. (Default: auto)

PathBiasCircThreshold NUM

PathBiasNoticeRate NUM

PathBiasWarnRate NUM

PathBiasExtremeRate NUM

PathBiasDropGuards NUM

PathBiasScaleThreshold NUM

These options override the default behavior of Tor’s (currently experimental) path bias detection algorithm. To try to find broken or misbehaving guard nodes, Tor looks for nodes where more than a certain fraction of circuits through that guard fail to get built.
The PathBiasCircThreshold option controls how many circuits we need to build through a guard before we make these checks. The PathBiasNoticeRate, PathBiasWarnRate and PathBiasExtremeRate options control what fraction of circuits must succeed through a guard so we won’t write log messages. If less than PathBiasExtremeRate circuits succeed and PathBiasDropGuards is set to 1, we disable use of that guard.

When we have seen more than PathBiasScaleThreshold circuits through a guard, we scale our observations by 0.5 (governed by the consensus) so that new observations don’t get swamped by old ones.

By default, or if a negative value is provided for one of these options, Tor uses reasonable defaults from the networkstatus consensus document. If no defaults are available there, these options default to 150, .70, .50, .30, 0, and 300 respectively.

PathBiasUseThreshold NUM

PathBiasNoticeUseRate NUM

PathBiasExtremeUseRate NUM

PathBiasScaleUseThreshold NUM

Similar to the above options, these options override the default behavior of Tor’s (currently experimental) path use bias detection algorithm.
Where as the path bias parameters govern thresholds for successfully building circuits, these four path use bias parameters govern thresholds only for circuit usage. Circuits which receive no stream usage are not counted by this detection algorithm. A used circuit is considered successful if it is capable of carrying streams or otherwise receiving well-formed responses to RELAY cells.
By default, or if a negative value is provided for one of these options, Tor uses reasonable defaults from the networkstatus consensus document. If no defaults are available there, these options default to 20, .80, .60, and 100, respectively.

ClientUseIPv6 0|1

If this option is set to 1, Tor might connect to entry nodes over IPv6. Note that clients configured with an IPv6 address in a Bridge line will try connecting over IPv6 even if ClientUseIPv6 is set to 0. (Default: 0)

ClientPreferIPv6ORPort 0|1

If this option is set to 1, Tor prefers an OR port with an IPv6 address over one with IPv4 if a given entry node has both. Other things may influence the choice. This option breaks a tie to the favor of IPv6. (Default: 0)

PathsNeededToBuildCircuits NUM

Tor clients don’t build circuits for user traffic until they know about enough of the network so that they could potentially construct enough of the possible paths through the network. If this option is set to a fraction between 0.25 and 0.95, Tor won’t build circuits until it has enough descriptors or microdescriptors to construct that fraction of possible paths. Note that setting this option too low can make your Tor client less anonymous, and setting it too high can prevent your Tor client from bootstrapping. If this option is negative, Tor will use a default value chosen by the directory authorities. (Default: -1.)

Support022HiddenServices 0|1|auto

Tor hidden services running versions before 0.2.3.x required clients to send timestamps, which can potentially be used to distinguish clients whose view of the current time is skewed. If this option is set to 0, we do not send this timestamp, and hidden services on obsolete Tor versions will not work. If this option is set to 1, we send the timestamp. If this optoin is "auto", we take a recommendation from the latest consensus document. (Default: auto)

SERVER OPTIONS

The following options are useful only for servers (that is, if ORPort is non-zero):

Address address

The IP address or fully qualified domain name of this server (e.g. moria.mit.edu). You can leave this unset, and Tor will guess your IP address. This IP address is the one used to tell clients and other servers where to find your Tor server; it doesn’t affect the IP that your Tor client binds to. To bind to a different address, use the *ListenAddress and OutboundBindAddress options.

AllowSingleHopExits 0|1

This option controls whether clients can use this server as a single hop proxy. If set to 1, clients can use this server as an exit even if it is the only hop in the circuit. Note that most clients will refuse to use servers that set this option, since most clients have ExcludeSingleHopRelays set. (Default: 0)

AssumeReachable 0|1

This option is used when bootstrapping a new Tor network. If set to 1, don’t do self-reachability testing; just upload your server descriptor immediately. If AuthoritativeDirectory is also set, this option instructs the dirserver to bypass remote reachability testing too and list all connected servers as running.

BridgeRelay 0|1

Sets the relay to act as a "bridge" with respect to relaying connections from bridge users to the Tor network. It mainly causes Tor to publish a server descriptor to the bridge database, rather than publishing a relay descriptor to the public directory authorities.

ContactInfo email_address

Administrative contact information for this relay or bridge. This line can be used to contact you if your relay or bridge is misconfigured or something else goes wrong. Note that we archive and publish all descriptors containing these lines and that Google indexes them, so spammers might also collect them. You may want to obscure the fact that it’s an email address and/or generate a new address for this purpose.

ExitPolicy policy,policy,

Set an exit policy for this server. Each policy is of the form "accept|reject ADDR[/MASK][:PORT]". If /MASK is omitted then this policy just applies to the host given. Instead of giving a host or network you can also use "*" to denote the universe (0.0.0.0/0). PORT can be a single port number, an interval of ports "FROM_PORT-TO_PORT", or "*". If PORT is omitted, that means "*".

For example, "accept 18.7.22.69:*,reject 18.0.0.0/8:*,accept *:*" would reject any traffic destined for MIT except for web.mit.edu, and accept anything else.

To specify all internal and link-local networks (including 0.0.0.0/8, 169.254.0.0/16, 127.0.0.0/8, 192.168.0.0/16, 10.0.0.0/8, and 172.16.0.0/12), you can use the "private" alias instead of an address. These addresses are rejected by default (at the beginning of your exit policy), along with your public IP address, unless you set the ExitPolicyRejectPrivate config option to 0. For example, once you’ve done that, you could allow HTTP to 127.0.0.1 and block all other connections to internal networks with "accept 127.0.0.1:80,reject private:*", though that may also allow connections to your own computer that are addressed to its public (external) IP address. See RFC 1918 and RFC 3330 for more details about internal and reserved IP address space.

This directive can be specified multiple times so you don’t have to put it all on one line.

Policies are considered first to last, and the first match wins. If you want to _replace_ the default exit policy, end your exit policy with either a reject *:* or an accept *:*. Otherwise, you’re _augmenting_ (prepending to) the default exit policy. The default exit policy is:

reject *:25
reject *:119
reject *:135-139
reject *:445
reject *:563
reject *:1214
reject *:4661-4666
reject *:6346-6429
reject *:6699
reject *:6881-6999
accept *:*
ExitPolicyRejectPrivate 0|1

Reject all private (local) networks, along with your own public IP address, at the beginning of your exit policy. See above entry on ExitPolicy. (Default: 1)

IPv6Exit 0|1

If set, and we are an exit node, allow clients to use us for IPv6 traffic. (Default: 0)

MaxOnionQueueDelay NUM [msec|second]

If we have more onionskins queued for processing than we can process in this amount of time, reject new ones. (Default: 1750 msec)

MyFamily node,node,

Declare that this Tor server is controlled or administered by a group or organization identical or similar to that of the other servers, defined by their identity fingerprints or nicknames. When two servers both declare that they are in the same 'family', Tor clients will not use them in the same circuit. (Each server only needs to list the other servers in its family; it doesn’t need to list itself, but it won’t hurt.) Do not list any bridge relay as it would compromise its concealment.
When listing a node, it’s better to list it by fingerprint than by nickname: fingerprints are more reliable.

Nickname name

Set the server’s nickname to 'name'. Nicknames must be between 1 and 19 characters inclusive, and must contain only the characters [a-zA-Z0-9].

NumCPUs num

How many processes to use at once for decrypting onionskins and other parallelizable operations. If this is set to 0, Tor will try to detect how many CPUs you have, defaulting to 1 if it can’t tell. (Default: 0)

ORPort [address:]PORT|auto [flags]

Advertise this port to listen for connections from Tor clients and servers. This option is required to be a Tor server. Set it to "auto" to have Tor pick a port for you. Set it to 0 to not run an ORPort at all. This option can occur more than once. (Default: 0)

Tor recognizes these flags on each ORPort:
**NoAdvertise**::
    By default, we bind to a port and tell our users about it. If
    NoAdvertise is specified, we don't advertise, but listen anyway.  This
    can be useful if the port everybody will be connecting to (for
    example, one that's opened on our firewall) is somewhere else.
**NoListen**::
    By default, we bind to a port and tell our users about it. If
    NoListen is specified, we don't bind, but advertise anyway.  This
    can be useful if something else  (for example, a firewall's port
    forwarding configuration) is causing connections to reach us.
**IPv4Only**::
    If the address is absent, or resolves to both an IPv4 and an IPv6
    address, only listen to the IPv4 address.
**IPv6Only**::
    If the address is absent, or resolves to both an IPv4 and an IPv6
    address, only listen to the IPv6 address.
For obvious reasons, NoAdvertise and NoListen are mutually exclusive, and
IPv4Only and IPv6Only are mutually exclusive.
ORListenAddress IP[:PORT]

Bind to this IP address to listen for connections from Tor clients and servers. If you specify a port, bind to this port rather than the one specified in ORPort. (Default: 0.0.0.0) This directive can be specified multiple times to bind to multiple addresses/ports.

This option is deprecated; you can get the same behavior with ORPort now
that it supports NoAdvertise and explicit addresses.
PortForwarding 0|1

Attempt to automatically forward the DirPort and ORPort on a NAT router connecting this Tor server to the Internet. If set, Tor will try both NAT-PMP (common on Apple routers) and UPnP (common on routers from other manufacturers). (Default: 0)

PortForwardingHelper filename|pathname

If PortForwarding is set, use this executable to configure the forwarding. If set to a filename, the system path will be searched for the executable. If set to a path, only the specified path will be executed. (Default: tor-fw-helper)

PublishServerDescriptor 0|1|v1|v2|v3|bridge,

This option specifies which descriptors Tor will publish when acting as a relay. You can choose multiple arguments, separated by commas.
If this option is set to 0, Tor will not publish its descriptors to any directories. (This is useful if you’re testing out your server, or if you’re using a Tor controller that handles directory publishing for you.) Otherwise, Tor will publish its descriptors of all type(s) specified. The default is "1", which means "if running as a server, publish the appropriate descriptors to the authorities".

ShutdownWaitLength NUM

When we get a SIGINT and we’re a server, we begin shutting down: we close listeners and start refusing new circuits. After NUM seconds, we exit. If we get a second SIGINT, we exit immediately. (Default: 30 seconds)

SSLKeyLifetime N minutes|hours|days|weeks

When creating a link certificate for our outermost SSL handshake, set its lifetime to this amount of time. If set to 0, Tor will choose some reasonable random defaults. (Default: 0)

HeartbeatPeriod N minutes|hours|days|weeks

Log a heartbeat message every HeartbeatPeriod seconds. This is a log level notice message, designed to let you know your Tor server is still alive and doing useful things. Settings this to 0 will disable the heartbeat. (Default: 6 hours)

AccountingMax N bytes|KBytes|MBytes|GBytes|TBytes

Never send more than the specified number of bytes in a given accounting period, or receive more than that number in the period. For example, with AccountingMax set to 1 GByte, a server could send 900 MBytes and receive 800 MBytes and continue running. It will only hibernate once one of the two reaches 1 GByte. When the number of bytes gets low, Tor will stop accepting new connections and circuits. When the number of bytes is exhausted, Tor will hibernate until some time in the next accounting period. To prevent all servers from waking at the same time, Tor will also wait until a random point in each period before waking up. If you have bandwidth cost issues, enabling hibernation is preferable to setting a low bandwidth, since it provides users with a collection of fast servers that are up some of the time, which is more useful than a set of slow servers that are always "available".

AccountingStart day|week|month [day] HH:MM

Specify how long accounting periods last. If month is given, each accounting period runs from the time HH:MM on the dayth day of one month to the same day and time of the next. (The day must be between 1 and 28.) If week is given, each accounting period runs from the time HH:MM of the dayth day of one week to the same day and time of the next week, with Monday as day 1 and Sunday as day 7. If day is given, each accounting period runs from the time HH:MM each day to the same time on the next day. All times are local, and given in 24-hour time. (Default: "month 1 0:00")

RefuseUnknownExits 0|1|auto

Prevent nodes that don’t appear in the consensus from exiting using this relay. If the option is 1, we always block exit attempts from such nodes; if it’s 0, we never do, and if the option is "auto", then we do whatever the authorities suggest in the consensus (and block if the consensus is quiet on the issue). (Default: auto)

ServerDNSResolvConfFile filename

Overrides the default DNS configuration with the configuration in filename. The file format is the same as the standard Unix "resolv.conf" file (7). This option, like all other ServerDNS options, only affects name lookups that your server does on behalf of clients. (Defaults to use the system DNS configuration.)

ServerDNSAllowBrokenConfig 0|1

If this option is false, Tor exits immediately if there are problems parsing the system DNS configuration or connecting to nameservers. Otherwise, Tor continues to periodically retry the system nameservers until it eventually succeeds. (Default: 1)

ServerDNSSearchDomains 0|1

If set to 1, then we will search for addresses in the local search domain. For example, if this system is configured to believe it is in "example.com", and a client tries to connect to "www", the client will be connected to "www.example.com". This option only affects name lookups that your server does on behalf of clients. (Default: 0)

ServerDNSDetectHijacking 0|1

When this option is set to 1, we will test periodically to determine whether our local nameservers have been configured to hijack failing DNS requests (usually to an advertising site). If they are, we will attempt to correct this. This option only affects name lookups that your server does on behalf of clients. (Default: 1)

ServerDNSTestAddresses address,address,

When we’re detecting DNS hijacking, make sure that these valid addresses aren’t getting redirected. If they are, then our DNS is completely useless, and we’ll reset our exit policy to "reject :". This option only affects name lookups that your server does on behalf of clients. (Default: "www.google.com, www.mit.edu, www.yahoo.com, www.slashdot.org")

ServerDNSAllowNonRFC953Hostnames 0|1

When this option is disabled, Tor does not try to resolve hostnames containing illegal characters (like @ and :) rather than sending them to an exit node to be resolved. This helps trap accidental attempts to resolve URLs and so on. This option only affects name lookups that your server does on behalf of clients. (Default: 0)

BridgeRecordUsageByCountry 0|1

When this option is enabled and BridgeRelay is also enabled, and we have GeoIP data, Tor keeps a keep a per-country count of how many client addresses have contacted it so that it can help the bridge authority guess which countries have blocked access to it. (Default: 1)

ServerDNSRandomizeCase 0|1

When this option is set, Tor sets the case of each character randomly in outgoing DNS requests, and makes sure that the case matches in DNS replies. This so-called "0x20 hack" helps resist some types of DNS poisoning attack. For more information, see "Increased DNS Forgery Resistance through 0x20-Bit Encoding". This option only affects name lookups that your server does on behalf of clients. (Default: 1)

GeoIPFile filename

A filename containing IPv4 GeoIP data, for use with by-country statistics.

GeoIPv6File filename

A filename containing IPv6 GeoIP data, for use with by-country statistics.

TLSECGroup P224|P256

What EC group should we try to use for incoming TLS connections? P224 is faster, but makes us stand out more. Has no effect if we’re a client, or if our OpenSSL version lacks support for ECDHE. (Default: P256)

CellStatistics 0|1

When this option is enabled, Tor writes statistics on the mean time that cells spend in circuit queues to disk every 24 hours. (Default: 0)

DirReqStatistics 0|1

When this option is enabled, a Tor directory writes statistics on the number and response time of network status requests to disk every 24 hours. (Default: 1)

EntryStatistics 0|1

When this option is enabled, Tor writes statistics on the number of directly connecting clients to disk every 24 hours. (Default: 0)

ExitPortStatistics 0|1

When this option is enabled, Tor writes statistics on the number of relayed bytes and opened stream per exit port to disk every 24 hours. (Default: 0)

ConnDirectionStatistics 0|1

When this option is enabled, Tor writes statistics on the bidirectional use of connections to disk every 24 hours. (Default: 0)

ExtraInfoStatistics 0|1

When this option is enabled, Tor includes previously gathered statistics in its extra-info documents that it uploads to the directory authorities. (Default: 1)

ExtendAllowPrivateAddresses 0|1

When this option is enabled, Tor routers allow EXTEND request to localhost, RFC1918 addresses, and so on. This can create security issues; you should probably leave it off. (Default: 0)

MaxMemInCellQueues N bytes|KB|MB|GB

This option configures a threshold above which Tor will assume that it needs to stop queueing cells because it’s about to run out of memory. If it hits this threshold, it will begin killing circuits until it has recovered at least 10% of this memory. Do not set this option too low, or your relay may be unreliable under load. This option only affects circuit queues, so the actual process size will be larger than this. (Default: 8GB)

DIRECTORY SERVER OPTIONS

The following options are useful only for directory servers (that is, if DirPort is non-zero):

AuthoritativeDirectory 0|1

When this option is set to 1, Tor operates as an authoritative directory server. Instead of caching the directory, it generates its own list of good servers, signs it, and sends that to the clients. Unless the clients already have you listed as a trusted directory, you probably do not want to set this option. Please coordinate with the other admins at tor-ops@torproject.org if you think you should be a directory.

DirPortFrontPage FILENAME

When this option is set, it takes an HTML file and publishes it as "/" on the DirPort. Now relay operators can provide a disclaimer without needing to set up a separate webserver. There’s a sample disclaimer in contrib/tor-exit-notice.html.

V1AuthoritativeDirectory 0|1

When this option is set in addition to AuthoritativeDirectory, Tor generates version 1 directory and running-routers documents (for legacy Tor clients up to 0.1.0.x).

V2AuthoritativeDirectory 0|1

When this option is set in addition to AuthoritativeDirectory, Tor generates version 2 network statuses and serves descriptors, etc as described in doc/spec/dir-spec-v2.txt (for Tor clients and servers running 0.1.1.x and 0.1.2.x).

V3AuthoritativeDirectory 0|1

When this option is set in addition to AuthoritativeDirectory, Tor generates version 3 network statuses and serves descriptors, etc as described in doc/spec/dir-spec.txt (for Tor clients and servers running at least 0.2.0.x).

VersioningAuthoritativeDirectory 0|1

When this option is set to 1, Tor adds information on which versions of Tor are still believed safe for use to the published directory. Each version 1 authority is automatically a versioning authority; version 2 authorities provide this service optionally. See RecommendedVersions, RecommendedClientVersions, and RecommendedServerVersions.

NamingAuthoritativeDirectory 0|1

When this option is set to 1, then the server advertises that it has opinions about nickname-to-fingerprint bindings. It will include these opinions in its published network-status pages, by listing servers with the flag "Named" if a correct binding between that nickname and fingerprint has been registered with the dirserver. Naming dirservers will refuse to accept or publish descriptors that contradict a registered binding. See approved-routers in the FILES section below.

HSAuthoritativeDir 0|1

When this option is set in addition to AuthoritativeDirectory, Tor also accepts and serves v0 hidden service descriptors, which are produced and used by Tor 0.2.1.x and older. (Default: 0)

HidServDirectoryV2 0|1

When this option is set, Tor accepts and serves v2 hidden service descriptors. Setting DirPort is not required for this, because clients connect via the ORPort by default. (Default: 1)

BridgeAuthoritativeDir 0|1

When this option is set in addition to AuthoritativeDirectory, Tor accepts and serves router descriptors, but it caches and serves the main networkstatus documents rather than generating its own. (Default: 0)

MinUptimeHidServDirectoryV2 N seconds|minutes|hours|days|weeks

Minimum uptime of a v2 hidden service directory to be accepted as such by authoritative directories. (Default: 25 hours)

DirPort [address:]PORT|auto [flags]

If this option is nonzero, advertise the directory service on this port. Set it to "auto" to have Tor pick a port for you. This option can occur more than once. (Default: 0)

The same flags are supported here as are supported by ORPort.
DirListenAddress IP[:PORT]

Bind the directory service to this address. If you specify a port, bind to this port rather than the one specified in DirPort. (Default: 0.0.0.0) This directive can be specified multiple times to bind to multiple addresses/ports.

This option is deprecated; you can get the same behavior with DirPort now
that it supports NoAdvertise and explicit addresses.
DirPolicy policy,policy,

Set an entrance policy for this server, to limit who can connect to the directory ports. The policies have the same form as exit policies above.

FetchV2Networkstatus 0|1

If set, we try to fetch the (obsolete, unused) version 2 network status consensus documents from the directory authorities. No currently supported Tor version uses them. (Default: 0)

DIRECTORY AUTHORITY SERVER OPTIONS

RecommendedVersions STRING

STRING is a comma-separated list of Tor versions currently believed to be safe. The list is included in each directory, and nodes which pull down the directory learn whether they need to upgrade. This option can appear multiple times: the values from multiple lines are spliced together. When this is set then VersioningAuthoritativeDirectory should be set too.

RecommendedClientVersions STRING

STRING is a comma-separated list of Tor versions currently believed to be safe for clients to use. This information is included in version 2 directories. If this is not set then the value of RecommendedVersions is used. When this is set then VersioningAuthoritativeDirectory should be set too.

RecommendedServerVersions STRING

STRING is a comma-separated list of Tor versions currently believed to be safe for servers to use. This information is included in version 2 directories. If this is not set then the value of RecommendedVersions is used. When this is set then VersioningAuthoritativeDirectory should be set too.

ConsensusParams STRING

STRING is a space-separated list of key=value pairs that Tor will include in the "params" line of its networkstatus vote.

DirAllowPrivateAddresses 0|1

If set to 1, Tor will accept router descriptors with arbitrary "Address" elements. Otherwise, if the address is not an IP address or is a private IP address, it will reject the router descriptor. (Default: 0)

AuthDirBadDir AddressPattern…

Authoritative directories only. A set of address patterns for servers that will be listed as bad directories in any network status document this authority publishes, if AuthDirListBadDirs is set.

AuthDirBadExit AddressPattern…

Authoritative directories only. A set of address patterns for servers that will be listed as bad exits in any network status document this authority publishes, if AuthDirListBadExits is set.

AuthDirInvalid AddressPattern…

Authoritative directories only. A set of address patterns for servers that will never be listed as "valid" in any network status document that this authority publishes.

AuthDirReject AddressPattern

Authoritative directories only. A set of address patterns for servers that will never be listed at all in any network status document that this authority publishes, or accepted as an OR address in any descriptor submitted for publication by this authority.

AuthDirBadDirCCs CC,…

AuthDirBadExitCCs CC,…

AuthDirInvalidCCs CC,…

AuthDirRejectCCs CC,…

Authoritative directories only. These options contain a comma-separated list of country codes such that any server in one of those country codes will be marked as a bad directory/bad exit/invalid for use, or rejected entirely.

AuthDirListBadDirs 0|1

Authoritative directories only. If set to 1, this directory has some opinion about which nodes are unsuitable as directory caches. (Do not set this to 1 unless you plan to list non-functioning directories as bad; otherwise, you are effectively voting in favor of every declared directory.)

AuthDirListBadExits 0|1

Authoritative directories only. If set to 1, this directory has some opinion about which nodes are unsuitable as exit nodes. (Do not set this to 1 unless you plan to list non-functioning exits as bad; otherwise, you are effectively voting in favor of every declared exit as an exit.)

AuthDirRejectUnlisted 0|1

Authoritative directories only. If set to 1, the directory server rejects all uploaded server descriptors that aren’t explicitly listed in the fingerprints file. This acts as a "panic button" if we get hit with a Sybil attack. (Default: 0)

AuthDirMaxServersPerAddr NUM

Authoritative directories only. The maximum number of servers that we will list as acceptable on a single IP address. Set this to "0" for "no limit". (Default: 2)

AuthDirMaxServersPerAuthAddr NUM

Authoritative directories only. Like AuthDirMaxServersPerAddr, but applies to addresses shared with directory authorities. (Default: 5)

AuthDirFastGuarantee N bytes|KBytes|MBytes|GBytes

Authoritative directories only. If non-zero, always vote the Fast flag for any relay advertising this amount of capacity or more. (Default: 100 KBytes)

AuthDirGuardBWGuarantee N bytes|KBytes|MBytes|GBytes

Authoritative directories only. If non-zero, this advertised capacity or more is always sufficient to satisfy the bandwidth requirement for the Guard flag. (Default: 250 KBytes)

BridgePassword Password

If set, contains an HTTP authenticator that tells a bridge authority to serve all requested bridge information. Used by the (only partially implemented) "bridge community" design, where a community of bridge relay operators all use an alternate bridge directory authority, and their target user audience can periodically fetch the list of available community bridges to stay up-to-date. (Default: not set)

V3AuthVotingInterval N minutes|hours

V3 authoritative directories only. Configures the server’s preferred voting interval. Note that voting will actually happen at an interval chosen by consensus from all the authorities' preferred intervals. This time SHOULD divide evenly into a day. (Default: 1 hour)

V3AuthVoteDelay N minutes|hours

V3 authoritative directories only. Configures the server’s preferred delay between publishing its vote and assuming it has all the votes from all the other authorities. Note that the actual time used is not the server’s preferred time, but the consensus of all preferences. (Default: 5 minutes)

V3AuthDistDelay N minutes|hours

V3 authoritative directories only. Configures the server’s preferred delay between publishing its consensus and signature and assuming it has all the signatures from all the other authorities. Note that the actual time used is not the server’s preferred time, but the consensus of all preferences. (Default: 5 minutes)

V3AuthNIntervalsValid NUM

V3 authoritative directories only. Configures the number of VotingIntervals for which each consensus should be valid for. Choosing high numbers increases network partitioning risks; choosing low numbers increases directory traffic. Note that the actual number of intervals used is not the server’s preferred number, but the consensus of all preferences. Must be at least 2. (Default: 3)

V3BandwidthsFile FILENAME

V3 authoritative directories only. Configures the location of the bandwidth-authority generated file storing information on relays' measured bandwidth capacities. (Default: unset)

V3AuthUseLegacyKey 0|1

If set, the directory authority will sign consensuses not only with its own signing key, but also with a "legacy" key and certificate with a different identity. This feature is used to migrate directory authority keys in the event of a compromise. (Default: 0)

RephistTrackTime N seconds|minutes|hours|days|weeks

Tells an authority, or other node tracking node reliability and history, that fine-grained information about nodes can be discarded when it hasn’t changed for a given amount of time. (Default: 24 hours)

VoteOnHidServDirectoriesV2 0|1

When this option is set in addition to AuthoritativeDirectory, Tor votes on whether to accept relays as hidden service directories. (Default: 1)

AuthDirHasIPv6Connectivity 0|1

Authoritative directories only. When set to 0, OR ports with an IPv6 address are being accepted without reachability testing. When set to 1, IPv6 OR ports are being tested just like IPv4 OR ports. (Default: 0)

HIDDEN SERVICE OPTIONS

The following options are used to configure a hidden service.

HiddenServiceDir DIRECTORY

Store data files for a hidden service in DIRECTORY. Every hidden service must have a separate directory. You may use this option multiple times to specify multiple services. DIRECTORY must be an existing directory.

HiddenServicePort VIRTPORT [TARGET]

Configure a virtual port VIRTPORT for a hidden service. You may use this option multiple times; each time applies to the service using the most recent hiddenservicedir. By default, this option maps the virtual port to the same port on 127.0.0.1 over TCP. You may override the target port, address, or both by specifying a target of addr, port, or addr:port. You may also have multiple lines with the same VIRTPORT: when a user connects to that VIRTPORT, one of the TARGETs from those lines will be chosen at random.

PublishHidServDescriptors 0|1

If set to 0, Tor will run any hidden services you configure, but it won’t advertise them to the rendezvous directory. This option is only useful if you’re using a Tor controller that handles hidserv publishing for you. (Default: 1)

HiddenServiceVersion version,version,

A list of rendezvous service descriptor versions to publish for the hidden service. Currently, only version 2 is supported. (Default: 2)

HiddenServiceAuthorizeClient auth-type client-name,client-name,

If configured, the hidden service is accessible for authorized clients only. The auth-type can either be 'basic' for a general-purpose authorization protocol or 'stealth' for a less scalable protocol that also hides service activity from unauthorized clients. Only clients that are listed here are authorized to access the hidden service. Valid client names are 1 to 19 characters long and only use characters in A-Za-z0-9+-_ (no spaces). If this option is set, the hidden service is not accessible for clients without authorization any more. Generated authorization data can be found in the hostname file. Clients need to put this authorization data in their configuration file using HidServAuth.

RendPostPeriod N seconds|minutes|hours|days|weeks

Every time the specified period elapses, Tor uploads any rendezvous service descriptors to the directory servers. This information is also uploaded whenever it changes. (Default: 1 hour)

TESTING NETWORK OPTIONS

The following options are used for running a testing Tor network.

TestingTorNetwork 0|1

If set to 1, Tor adjusts default values of the configuration options below, so that it is easier to set up a testing Tor network. May only be set if non-default set of DirAuthorities is set. Cannot be unset while Tor is running. (Default: 0)

ServerDNSAllowBrokenConfig 1
DirAllowPrivateAddresses 1
EnforceDistinctSubnets 0
AssumeReachable 1
AuthDirMaxServersPerAddr 0
AuthDirMaxServersPerAuthAddr 0
ClientDNSRejectInternalAddresses 0
ClientRejectInternalAddresses 0
CountPrivateBandwidth 1
ExitPolicyRejectPrivate 0
ExtendAllowPrivateAddresses 1
V3AuthVotingInterval 5 minutes
V3AuthVoteDelay 20 seconds
V3AuthDistDelay 20 seconds
MinUptimeHidServDirectoryV2 0 seconds
TestingV3AuthInitialVotingInterval 5 minutes
TestingV3AuthInitialVoteDelay 20 seconds
TestingV3AuthInitialDistDelay 20 seconds
TestingAuthDirTimeToLearnReachability 0 minutes
TestingEstimatedDescriptorPropagationTime 0 minutes
TestingV3AuthInitialVotingInterval N minutes|hours

Like V3AuthVotingInterval, but for initial voting interval before the first consensus has been created. Changing this requires that TestingTorNetwork is set. (Default: 30 minutes)

TestingV3AuthInitialVoteDelay N minutes|hours

Like V3AuthVoteDelay, but for initial voting interval before the first consensus has been created. Changing this requires that TestingTorNetwork is set. (Default: 5 minutes)

TestingV3AuthInitialDistDelay N minutes|hours

Like V3AuthDistDelay, but for initial voting interval before the first consensus has been created. Changing this requires that TestingTorNetwork is set. (Default: 5 minutes)

TestingAuthDirTimeToLearnReachability N minutes|hours

After starting as an authority, do not make claims about whether routers are Running until this much time has passed. Changing this requires that TestingTorNetwork is set. (Default: 30 minutes)

TestingEstimatedDescriptorPropagationTime N minutes|hours

Clients try downloading router descriptors from directory caches after this time. Changing this requires that TestingTorNetwork is set. (Default: 10 minutes)

TestingMinFastFlagThreshold N bytes|KBytes|MBytes|GBytes

Minimum value for the Fast flag. Overrides the ordinary minimum taken from the consensus when TestingTorNetwork is set. (Default: 0.)

SIGNALS

Tor catches the following signals:

SIGTERM

Tor will catch this, clean up and sync to disk if necessary, and exit.

SIGINT

Tor clients behave as with SIGTERM; but Tor servers will do a controlled slow shutdown, closing listeners and waiting 30 seconds before exiting. (The delay can be configured with the ShutdownWaitLength config option.)

SIGHUP

The signal instructs Tor to reload its configuration (including closing and reopening logs), and kill and restart its helper processes if applicable.

SIGUSR1

Log statistics about current connections, past connections, and throughput.

SIGUSR2

Switch all logs to loglevel debug. You can go back to the old loglevels by sending a SIGHUP.

SIGCHLD

Tor receives this signal when one of its helper processes has exited, so it can clean up.

SIGPIPE

Tor catches this signal and ignores it.

SIGXFSZ

If this signal exists on your platform, Tor catches and ignores it.

FILES

@CONFDIR@/torrc

The configuration file, which contains "option value" pairs.

@LOCALSTATEDIR@/lib/tor/

The tor process stores keys and other data here.

DataDirectory/cached-status/

The most recently downloaded network status document for each authority. Each file holds one such document; the filenames are the hexadecimal identity key fingerprints of the directory authorities. Mostly obsolete.

DataDirectory/cached-consensus and/or cached-microdesc-consensus

The most recent consensus network status document we’ve downloaded.

DataDirectory/cached-descriptors and cached-descriptors.new

These files hold downloaded router statuses. Some routers may appear more than once; if so, the most recently published descriptor is used. Lines beginning with @-signs are annotations that contain more information about a given router. The ".new" file is an append-only journal; when it gets too large, all entries are merged into a new cached-descriptors file.

DataDirectory/cached-microdescs and cached-microdescs.new

These files hold downloaded microdescriptors. Lines beginning with @-signs are annotations that contain more information about a given router. The ".new" file is an append-only journal; when it gets too large, all entries are merged into a new cached-microdescs file.

DataDirectory/cached-routers and cached-routers.new

Obsolete versions of cached-descriptors and cached-descriptors.new. When Tor can’t find the newer files, it looks here instead.

DataDirectory/state

A set of persistent key-value mappings. These are documented in the file. These include:

  • The current entry guards and their status.

  • The current bandwidth accounting values (unused so far; see below).

  • When the file was last written

  • What version of Tor generated the state file

  • A short history of bandwidth usage, as produced in the router descriptors.

DataDirectory/bw_accounting

Used to track bandwidth accounting values (when the current period starts and ends; how much has been read and written so far this period). This file is obsolete, and the data is now stored in the 'state' file as well. Only used when bandwidth accounting is enabled.

DataDirectory/control_auth_cookie

Used for cookie authentication with the controller. Location can be overridden by the CookieAuthFile config option. Regenerated on startup. See control-spec.txt for details. Only used when cookie authentication is enabled.

DataDirectory/keys/*

Only used by servers. Holds identity keys and onion keys.

DataDirectory/fingerprint

Only used by servers. Holds the fingerprint of the server’s identity key.

DataDirectory/approved-routers

Only for naming authoritative directory servers (see NamingAuthoritativeDirectory). This file lists nickname to identity bindings. Each line lists a nickname and a fingerprint separated by whitespace. See your fingerprint file in the DataDirectory for an example line. If the nickname is !reject then descriptors from the given identity (fingerprint) are rejected by this server. If it is !invalid then descriptors are accepted but marked in the directory as not valid, that is, not recommended.

DataDirectory/router-stability

Only used by authoritative directory servers. Tracks measurements for router mean-time-between-failures so that authorities have a good idea of how to set their Stable flags.

HiddenServiceDirectory/hostname

The <base32-encoded-fingerprint>.onion domain name for this hidden service. If the hidden service is restricted to authorized clients only, this file also contains authorization data for all clients.

HiddenServiceDirectory/private_key

The private key for this hidden service.

HiddenServiceDirectory/client_keys

Authorization data for a hidden service that is only accessible by authorized clients.

SEE ALSO

privoxy(1), torsocks(1), torify(1)

https://www.torproject.org/

BUGS

Plenty, probably. Tor is still in development. Please report them.

AUTHORS

Roger Dingledine [arma at mit.edu], Nick Mathewson [nickm at alum.mit.edu].


tor-0.2.4.20/Doxyfile.in0000644000175000017500000016412612120436355011610 00000000000000# Doxyfile 1.5.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = tor # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION@ # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = ./doc/doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, # and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = NO # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. # DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = src/common \ src/or # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.c \ *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = tree.h # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs for Tor" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.torproject.Tor # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to FRAME, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. Other possible values # for this tag are: HIERARCHIES, which will generate the Groups, Directories, # and Class Hiererachy pages using a tree view instead of an ordered list; # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # disables this behavior completely. For backwards compatibility with previous # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # respectively. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is enabled by default, which results in a transparent # background. Warning: Depending on the platform used, enabling this option # may lead to badly anti-aliased labels on the edges of a graph (i.e. they # become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO tor-0.2.4.20/micro-revision.i0000644000175000017500000000002312255753105012601 00000000000000"3cb5c70beec5bf46" tor-0.2.4.20/missing0000755000175000017500000002415212255745723011101 00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2012-01-06.13; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # 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, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: tor-0.2.4.20/src/0000755000175000017500000000000012255753764010351 500000000000000tor-0.2.4.20/src/include.am0000644000175000017500000000030712166112776012224 00000000000000include src/ext/include.am include src/common/include.am include src/or/include.am include src/test/include.am include src/tools/include.am include src/win32/include.am include src/config/include.am tor-0.2.4.20/src/test/0000755000175000017500000000000012255753765011331 500000000000000tor-0.2.4.20/src/test/bench.c0000644000175000017500000003474012255745673012503 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Ordinarily defined in tor_main.c; this bit is just here to provide one * since we're not linking to tor_main.c */ const char tor_git_revision[] = ""; /** * \file bench.c * \brief Benchmarks for lower level Tor modules. **/ #include "orconfig.h" #define RELAY_PRIVATE #define CONFIG_PRIVATE #include "or.h" #include "onion_tap.h" #include "relay.h" #include #include #ifndef OPENSSL_NO_EC #include #include #include #endif #include "config.h" #ifdef CURVE25519_ENABLED #include "crypto_curve25519.h" #include "onion_ntor.h" #endif #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) static uint64_t nanostart; static inline uint64_t timespec_to_nsec(const struct timespec *ts) { return ((uint64_t)ts->tv_sec)*1000000000 + ts->tv_nsec; } static void reset_perftime(void) { struct timespec ts; int r; r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); tor_assert(r == 0); nanostart = timespec_to_nsec(&ts); } static uint64_t perftime(void) { struct timespec ts; int r; r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); tor_assert(r == 0); return timespec_to_nsec(&ts) - nanostart; } #else static struct timeval tv_start = { 0, 0 }; static void reset_perftime(void) { tor_gettimeofday(&tv_start); } static uint64_t perftime(void) { struct timeval now, out; tor_gettimeofday(&now); timersub(&now, &tv_start, &out); return ((uint64_t)out.tv_sec)*1000000000 + out.tv_usec*1000; } #endif #define NANOCOUNT(start,end,iters) \ ( ((double)((end)-(start))) / (iters) ) /** Run AES performance benchmarks. */ static void bench_aes(void) { int len, i; char *b1, *b2; crypto_cipher_t *c; uint64_t start, end; const int bytes_per_iter = (1<<24); reset_perftime(); c = crypto_cipher_new(NULL); for (len = 1; len <= 8192; len *= 2) { int iters = bytes_per_iter / len; b1 = tor_malloc_zero(len); b2 = tor_malloc_zero(len); start = perftime(); for (i = 0; i < iters; ++i) { crypto_cipher_encrypt(c, b1, b2, len); } end = perftime(); tor_free(b1); tor_free(b2); printf("%d bytes: %.2f nsec per byte\n", len, NANOCOUNT(start, end, iters*len)); } crypto_cipher_free(c); } static void bench_onion_TAP(void) { const int iters = 1<<9; int i; crypto_pk_t *key, *key2; uint64_t start, end; char os[TAP_ONIONSKIN_CHALLENGE_LEN]; char or[TAP_ONIONSKIN_REPLY_LEN]; crypto_dh_t *dh_out; key = crypto_pk_new(); key2 = crypto_pk_new(); if (crypto_pk_generate_key_with_bits(key, 1024) < 0) goto done; if (crypto_pk_generate_key_with_bits(key2, 1024) < 0) goto done; reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { onion_skin_TAP_create(key, &dh_out, os); crypto_dh_free(dh_out); } end = perftime(); printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); onion_skin_TAP_create(key, &dh_out, os); start = perftime(); for (i = 0; i < iters; ++i) { char key_out[CPATH_KEY_MATERIAL_LEN]; onion_skin_TAP_server_handshake(os, key, NULL, or, key_out, sizeof(key_out)); } end = perftime(); printf("Server-side, key guessed right: %f usec\n", NANOCOUNT(start, end, iters)/1e3); start = perftime(); for (i = 0; i < iters; ++i) { char key_out[CPATH_KEY_MATERIAL_LEN]; onion_skin_TAP_server_handshake(os, key2, key, or, key_out, sizeof(key_out)); } end = perftime(); printf("Server-side, key guessed wrong: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); start = perftime(); for (i = 0; i < iters; ++i) { crypto_dh_t *dh; char key_out[CPATH_KEY_MATERIAL_LEN]; int s; dh = crypto_dh_dup(dh_out); s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out)); crypto_dh_free(dh); tor_assert(s == 0); } end = perftime(); printf("Client-side, part 2: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); done: crypto_pk_free(key); crypto_pk_free(key2); } #ifdef CURVE25519_ENABLED static void bench_onion_ntor(void) { const int iters = 1<<10; int i; curve25519_keypair_t keypair1, keypair2; uint64_t start, end; uint8_t os[NTOR_ONIONSKIN_LEN]; uint8_t or[NTOR_REPLY_LEN]; ntor_handshake_state_t *state = NULL; uint8_t nodeid[DIGEST_LEN]; di_digest256_map_t *keymap = NULL; curve25519_secret_key_generate(&keypair1.seckey, 0); curve25519_public_key_generate(&keypair1.pubkey, &keypair1.seckey); curve25519_secret_key_generate(&keypair2.seckey, 0); curve25519_public_key_generate(&keypair2.pubkey, &keypair2.seckey); dimap_add_entry(&keymap, keypair1.pubkey.public_key, &keypair1); dimap_add_entry(&keymap, keypair2.pubkey.public_key, &keypair2); reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os); ntor_handshake_state_free(state); } end = perftime(); printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); state = NULL; onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os); start = perftime(); for (i = 0; i < iters; ++i) { uint8_t key_out[CPATH_KEY_MATERIAL_LEN]; onion_skin_ntor_server_handshake(os, keymap, NULL, nodeid, or, key_out, sizeof(key_out)); } end = perftime(); printf("Server-side: %f usec\n", NANOCOUNT(start, end, iters)/1e3); start = perftime(); for (i = 0; i < iters; ++i) { uint8_t key_out[CPATH_KEY_MATERIAL_LEN]; int s; s = onion_skin_ntor_client_handshake(state, or, key_out, sizeof(key_out)); tor_assert(s == 0); } end = perftime(); printf("Client-side, part 2: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); ntor_handshake_state_free(state); dimap_free(keymap, NULL); } #endif static void bench_cell_aes(void) { uint64_t start, end; const int len = 509; const int iters = (1<<16); const int max_misalign = 15; char *b = tor_malloc(len+max_misalign); crypto_cipher_t *c; int i, misalign; c = crypto_cipher_new(NULL); reset_perftime(); for (misalign = 0; misalign <= max_misalign; ++misalign) { start = perftime(); for (i = 0; i < iters; ++i) { crypto_cipher_crypt_inplace(c, b+misalign, len); } end = perftime(); printf("%d bytes, misaligned by %d: %.2f nsec per byte\n", len, misalign, NANOCOUNT(start, end, iters*len)); } crypto_cipher_free(c); tor_free(b); } /** Run digestmap_t performance benchmarks. */ static void bench_dmap(void) { smartlist_t *sl = smartlist_new(); smartlist_t *sl2 = smartlist_new(); uint64_t start, end, pt2, pt3, pt4; int iters = 8192; const int elts = 4000; const int fpostests = 100000; char d[20]; int i,n=0, fp = 0; digestmap_t *dm = digestmap_new(); digestset_t *ds = digestset_new(elts); for (i = 0; i < elts; ++i) { crypto_rand(d, 20); smartlist_add(sl, tor_memdup(d, 20)); } for (i = 0; i < elts; ++i) { crypto_rand(d, 20); smartlist_add(sl2, tor_memdup(d, 20)); } printf("nbits=%d\n", ds->mask+1); reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { SMARTLIST_FOREACH(sl, const char *, cp, digestmap_set(dm, cp, (void*)1)); } pt2 = perftime(); printf("digestmap_set: %.2f ns per element\n", NANOCOUNT(start, pt2, iters*elts)); for (i = 0; i < iters; ++i) { SMARTLIST_FOREACH(sl, const char *, cp, digestmap_get(dm, cp)); SMARTLIST_FOREACH(sl2, const char *, cp, digestmap_get(dm, cp)); } pt3 = perftime(); printf("digestmap_get: %.2f ns per element\n", NANOCOUNT(pt2, pt3, iters*elts*2)); for (i = 0; i < iters; ++i) { SMARTLIST_FOREACH(sl, const char *, cp, digestset_add(ds, cp)); } pt4 = perftime(); printf("digestset_add: %.2f ns per element\n", NANOCOUNT(pt3, pt4, iters*elts)); for (i = 0; i < iters; ++i) { SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_contains(ds, cp)); SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_contains(ds, cp)); } end = perftime(); printf("digestset_contains: %.2f ns per element.\n", NANOCOUNT(pt4, end, iters*elts*2)); /* We need to use this, or else the whole loop gets optimized out. */ printf("Hits == %d\n", n); for (i = 0; i < fpostests; ++i) { crypto_rand(d, 20); if (digestset_contains(ds, d)) ++fp; } printf("False positive rate on digestset: %.2f%%\n", (fp/(double)fpostests)*100); digestmap_free(dm, NULL); digestset_free(ds); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp)); smartlist_free(sl); smartlist_free(sl2); } static void bench_cell_ops(void) { const int iters = 1<<16; int i; /* benchmarks for cell ops at relay. */ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t)); cell_t *cell = tor_malloc(sizeof(cell_t)); int outbound; uint64_t start, end; crypto_rand((char*)cell->payload, sizeof(cell->payload)); /* Mock-up or_circuit_t */ or_circ->base_.magic = OR_CIRCUIT_MAGIC; or_circ->base_.purpose = CIRCUIT_PURPOSE_OR; /* Initialize crypto */ or_circ->p_crypto = crypto_cipher_new(NULL); or_circ->n_crypto = crypto_cipher_new(NULL); or_circ->p_digest = crypto_digest_new(); or_circ->n_digest = crypto_digest_new(); reset_perftime(); for (outbound = 0; outbound <= 1; ++outbound) { cell_direction_t d = outbound ? CELL_DIRECTION_OUT : CELL_DIRECTION_IN; start = perftime(); for (i = 0; i < iters; ++i) { char recognized = 0; crypt_path_t *layer_hint = NULL; relay_crypt(TO_CIRCUIT(or_circ), cell, d, &layer_hint, &recognized); } end = perftime(); printf("%sbound cells: %.2f ns per cell. (%.2f ns per byte of payload)\n", outbound?"Out":" In", NANOCOUNT(start,end,iters), NANOCOUNT(start,end,iters*CELL_PAYLOAD_SIZE)); } crypto_digest_free(or_circ->p_digest); crypto_digest_free(or_circ->n_digest); crypto_cipher_free(or_circ->p_crypto); crypto_cipher_free(or_circ->n_crypto); tor_free(or_circ); tor_free(cell); } static void bench_dh(void) { const int iters = 1<<10; int i; uint64_t start, end; reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { char dh_pubkey_a[DH_BYTES], dh_pubkey_b[DH_BYTES]; char secret_a[DH_BYTES], secret_b[DH_BYTES]; ssize_t slen_a, slen_b; crypto_dh_t *dh_a = crypto_dh_new(DH_TYPE_TLS); crypto_dh_t *dh_b = crypto_dh_new(DH_TYPE_TLS); crypto_dh_generate_public(dh_a); crypto_dh_generate_public(dh_b); crypto_dh_get_public(dh_a, dh_pubkey_a, sizeof(dh_pubkey_a)); crypto_dh_get_public(dh_b, dh_pubkey_b, sizeof(dh_pubkey_b)); slen_a = crypto_dh_compute_secret(LOG_NOTICE, dh_a, dh_pubkey_b, sizeof(dh_pubkey_b), secret_a, sizeof(secret_a)); slen_b = crypto_dh_compute_secret(LOG_NOTICE, dh_b, dh_pubkey_a, sizeof(dh_pubkey_a), secret_b, sizeof(secret_b)); tor_assert(slen_a == slen_b); tor_assert(!memcmp(secret_a, secret_b, slen_a)); crypto_dh_free(dh_a); crypto_dh_free(dh_b); } end = perftime(); printf("Complete DH handshakes (1024 bit, public and private ops):\n" " %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6); } #if (!defined(OPENSSL_NO_EC) \ && OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)) #define HAVE_EC_BENCHMARKS static void bench_ecdh_impl(int nid, const char *name) { const int iters = 1<<10; int i; uint64_t start, end; reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { char secret_a[DH_BYTES], secret_b[DH_BYTES]; ssize_t slen_a, slen_b; EC_KEY *dh_a = EC_KEY_new_by_curve_name(nid); EC_KEY *dh_b = EC_KEY_new_by_curve_name(nid); EC_KEY_generate_key(dh_a); EC_KEY_generate_key(dh_b); slen_a = ECDH_compute_key(secret_a, DH_BYTES, EC_KEY_get0_public_key(dh_b), dh_a, NULL); slen_b = ECDH_compute_key(secret_b, DH_BYTES, EC_KEY_get0_public_key(dh_a), dh_b, NULL); tor_assert(slen_a == slen_b); tor_assert(!memcmp(secret_a, secret_b, slen_a)); EC_KEY_free(dh_a); EC_KEY_free(dh_b); } end = perftime(); printf("Complete ECDH %s handshakes (2 public and 2 private ops):\n" " %f millisec each.\n", name, NANOCOUNT(start, end, iters)/1e6); } static void bench_ecdh_p256(void) { bench_ecdh_impl(NID_X9_62_prime256v1, "P-256"); } static void bench_ecdh_p224(void) { bench_ecdh_impl(NID_secp224r1, "P-224"); } #endif typedef void (*bench_fn)(void); typedef struct benchmark_t { const char *name; bench_fn fn; int enabled; } benchmark_t; #define ENT(s) { #s , bench_##s, 0 } static struct benchmark_t benchmarks[] = { ENT(dmap), ENT(aes), ENT(onion_TAP), #ifdef CURVE25519_ENABLED ENT(onion_ntor), #endif ENT(cell_aes), ENT(cell_ops), ENT(dh), #ifdef HAVE_EC_BENCHMARKS ENT(ecdh_p256), ENT(ecdh_p224), #endif {NULL,NULL,0} }; static benchmark_t * find_benchmark(const char *name) { benchmark_t *b; for (b = benchmarks; b->name; ++b) { if (!strcmp(name, b->name)) { return b; } } return NULL; } /** Main entry point for benchmark code: parse the command line, and run * some benchmarks. */ int main(int argc, const char **argv) { int i; int list=0, n_enabled=0; benchmark_t *b; char *errmsg; or_options_t *options; tor_threads_init(); for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "--list")) { list = 1; } else { benchmark_t *b = find_benchmark(argv[i]); ++n_enabled; if (b) { b->enabled = 1; } else { printf("No such benchmark as %s\n", argv[i]); } } } reset_perftime(); crypto_seed_rng(1); options = options_new(); init_logging(); options->command = CMD_RUN_UNITTESTS; options->DataDirectory = tor_strdup(""); options_init(options); if (set_options(options, &errmsg) < 0) { printf("Failed to set initial options: %s\n", errmsg); tor_free(errmsg); return 1; } for (b = benchmarks; b->name; ++b) { if (b->enabled || n_enabled == 0) { printf("===== %s =====\n", b->name); if (!list) b->fn(); } } return 0; } tor-0.2.4.20/src/test/include.am0000644000175000017500000000430512255745673013214 00000000000000TESTS+= src/test/test noinst_PROGRAMS+= src/test/test src/test/test-child src/test/bench src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" \ -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on Windows, but I assure you that it # matters a lot there, and is quite hard to debug if you forget to do it. src_test_test_SOURCES = \ src/test/test.c \ src/test/test_addr.c \ src/test/test_cell_formats.c \ src/test/test_containers.c \ src/test/test_crypto.c \ src/test/test_data.c \ src/test/test_dir.c \ src/test/test_introduce.c \ src/test/test_microdesc.c \ src/test/test_pt.c \ src/test/test_replay.c \ src/test/test_util.c \ src/test/test_config.c \ src/ext/tinytest.c src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS) src_test_bench_SOURCES = \ src/test/bench.c src_test_bench_CPPFLAGS= $(src_test_AM_CPPFLAGS) src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ src_test_test_LDADD = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(LIBDONNA) \ src/common/libor-event.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(LIBDONNA) \ src/common/libor-event.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ noinst_HEADERS+= \ src/test/test.h if CURVE25519_ENABLED noinst_PROGRAMS+= src/test/test-ntor-cl src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(LIBDONNA) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ src_test_test_ntor_cl_AM_CPPFLAGS = \ -I"$(top_srcdir)/src/or" endif tor-0.2.4.20/src/test/test_containers.c0000644000175000017500000007255012255745673014631 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #include "or.h" #include "fp_pair.h" #include "test.h" /** Helper: return a tristate based on comparing the strings in *a and * *b. */ static int compare_strs_(const void **a, const void **b) { const char *s1 = *a, *s2 = *b; return strcmp(s1, s2); } /** Helper: return a tristate based on comparing the strings in a and * *b. */ static int compare_strs_for_bsearch_(const void *a, const void **b) { const char *s1 = a, *s2 = *b; return strcmp(s1, s2); } /** Helper: return a tristate based on comparing the strings in *a and * *b, excluding a's first character, and ignoring case. */ static int compare_without_first_ch_(const void *a, const void **b) { const char *s1 = a, *s2 = *b; return strcasecmp(s1+1, s2); } /** Run unit tests for basic dynamic-sized array functionality. */ static void test_container_smartlist_basic(void) { smartlist_t *sl; /* XXXX test sort_digests, uniq_strings, uniq_digests */ /* Test smartlist add, del_keeporder, insert, get. */ sl = smartlist_new(); smartlist_add(sl, (void*)1); smartlist_add(sl, (void*)2); smartlist_add(sl, (void*)3); smartlist_add(sl, (void*)4); smartlist_del_keeporder(sl, 1); smartlist_insert(sl, 1, (void*)22); smartlist_insert(sl, 0, (void*)0); smartlist_insert(sl, 5, (void*)555); test_eq_ptr((void*)0, smartlist_get(sl,0)); test_eq_ptr((void*)1, smartlist_get(sl,1)); test_eq_ptr((void*)22, smartlist_get(sl,2)); test_eq_ptr((void*)3, smartlist_get(sl,3)); test_eq_ptr((void*)4, smartlist_get(sl,4)); test_eq_ptr((void*)555, smartlist_get(sl,5)); /* Try deleting in the middle. */ smartlist_del(sl, 1); test_eq_ptr((void*)555, smartlist_get(sl, 1)); /* Try deleting at the end. */ smartlist_del(sl, 4); test_eq(4, smartlist_len(sl)); /* test isin. */ test_assert(smartlist_contains(sl, (void*)3)); test_assert(!smartlist_contains(sl, (void*)99)); done: smartlist_free(sl); } /** Run unit tests for smartlist-of-strings functionality. */ static void test_container_smartlist_strings(void) { smartlist_t *sl = smartlist_new(); char *cp=NULL, *cp_alloc=NULL; size_t sz; /* Test split and join */ test_eq(0, smartlist_len(sl)); smartlist_split_string(sl, "abc", ":", 0, 0); test_eq(1, smartlist_len(sl)); test_streq("abc", smartlist_get(sl, 0)); smartlist_split_string(sl, "a::bc::", "::", 0, 0); test_eq(4, smartlist_len(sl)); test_streq("a", smartlist_get(sl, 1)); test_streq("bc", smartlist_get(sl, 2)); test_streq("", smartlist_get(sl, 3)); cp_alloc = smartlist_join_strings(sl, "", 0, NULL); test_streq(cp_alloc, "abcabc"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "!", 0, NULL); test_streq(cp_alloc, "abc!a!bc!"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); test_streq(cp_alloc, "abcXYaXYbcXY"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); test_streq(cp_alloc, "abcXYaXYbcXYXY"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "", 1, NULL); test_streq(cp_alloc, "abcabc"); tor_free(cp_alloc); smartlist_split_string(sl, "/def/ /ghijk", "/", 0, 0); test_eq(8, smartlist_len(sl)); test_streq("", smartlist_get(sl, 4)); test_streq("def", smartlist_get(sl, 5)); test_streq(" ", smartlist_get(sl, 6)); test_streq("ghijk", smartlist_get(sl, 7)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "a,bbd,cdef", ",", SPLIT_SKIP_SPACE, 0); test_eq(3, smartlist_len(sl)); test_streq("a", smartlist_get(sl,0)); test_streq("bbd", smartlist_get(sl,1)); test_streq("cdef", smartlist_get(sl,2)); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE, 0); test_eq(8, smartlist_len(sl)); test_streq("z", smartlist_get(sl,3)); test_streq("zhasd", smartlist_get(sl,4)); test_streq("", smartlist_get(sl,5)); test_streq("bnud", smartlist_get(sl,6)); test_streq("", smartlist_get(sl,7)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, " ab\tc \td ef ", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(4, smartlist_len(sl)); test_streq("ab", smartlist_get(sl,0)); test_streq("c", smartlist_get(sl,1)); test_streq("d", smartlist_get(sl,2)); test_streq("ef", smartlist_get(sl,3)); smartlist_split_string(sl, "ghi\tj", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(6, smartlist_len(sl)); test_streq("ghi", smartlist_get(sl,4)); test_streq("j", smartlist_get(sl,5)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); test_streq(cp_alloc, ""); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); test_streq(cp_alloc, "XY"); tor_free(cp_alloc); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(3, smartlist_len(sl)); test_streq("z", smartlist_get(sl, 0)); test_streq("zhasd", smartlist_get(sl, 1)); test_streq("bnud", smartlist_get(sl, 2)); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); test_eq(5, smartlist_len(sl)); test_streq("z", smartlist_get(sl, 3)); test_streq("zhasd <> <> bnud<>", smartlist_get(sl, 4)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "abcd\n", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(1, smartlist_len(sl)); test_streq("abcd", smartlist_get(sl, 0)); smartlist_split_string(sl, "efgh", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(2, smartlist_len(sl)); test_streq("efgh", smartlist_get(sl, 1)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Test swapping, shuffling, and sorting. */ smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0); test_eq(7, smartlist_len(sl)); smartlist_sort(sl, compare_strs_); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"and,arma,by,nickm,onion,router,the"); tor_free(cp_alloc); smartlist_swap(sl, 1, 5); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"and,router,by,nickm,onion,arma,the"); tor_free(cp_alloc); smartlist_shuffle(sl); test_eq(7, smartlist_len(sl)); test_assert(smartlist_contains_string(sl, "and")); test_assert(smartlist_contains_string(sl, "router")); test_assert(smartlist_contains_string(sl, "by")); test_assert(smartlist_contains_string(sl, "nickm")); test_assert(smartlist_contains_string(sl, "onion")); test_assert(smartlist_contains_string(sl, "arma")); test_assert(smartlist_contains_string(sl, "the")); /* Test bsearch. */ smartlist_sort(sl, compare_strs_); test_streq("nickm", smartlist_bsearch(sl, "zNicKM", compare_without_first_ch_)); test_streq("and", smartlist_bsearch(sl, " AND", compare_without_first_ch_)); test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", compare_without_first_ch_)); /* Test bsearch_idx */ { int f; smartlist_t *tmp = NULL; test_eq(0, smartlist_bsearch_idx(sl," aaa",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(sl," and",compare_without_first_ch_,&f)); test_eq(f, 1); test_eq(1, smartlist_bsearch_idx(sl," arm",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(1, smartlist_bsearch_idx(sl," arma",compare_without_first_ch_,&f)); test_eq(f, 1); test_eq(2, smartlist_bsearch_idx(sl," armb",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(7, smartlist_bsearch_idx(sl," zzzz",compare_without_first_ch_,&f)); test_eq(f, 0); /* Test trivial cases for list of length 0 or 1 */ tmp = smartlist_new(); test_eq(0, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); smartlist_insert(tmp, 0, (void *)("bar")); test_eq(1, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(tmp, "aaa", compare_strs_for_bsearch_, &f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(tmp, "bar", compare_strs_for_bsearch_, &f)); test_eq(f, 1); /* ... and one for length 2 */ smartlist_insert(tmp, 1, (void *)("foo")); test_eq(1, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 1); test_eq(2, smartlist_bsearch_idx(tmp, "goo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); smartlist_free(tmp); } /* Test reverse() and pop_last() */ smartlist_reverse(sl); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"the,router,onion,nickm,by,arma,and"); tor_free(cp_alloc); cp_alloc = smartlist_pop_last(sl); test_streq(cp_alloc, "and"); tor_free(cp_alloc); test_eq(smartlist_len(sl), 6); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); cp_alloc = smartlist_pop_last(sl); test_eq_ptr(cp_alloc, NULL); /* Test uniq() */ smartlist_split_string(sl, "50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50", ",", 0, 0); smartlist_sort(sl, compare_strs_); smartlist_uniq(sl, compare_strs_, tor_free_); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc, "50,a,canal,man,noon,panama,plan,radar"); tor_free(cp_alloc); /* Test contains_string, contains_string_case and contains_int_as_string */ test_assert(smartlist_contains_string(sl, "noon")); test_assert(!smartlist_contains_string(sl, "noonoon")); test_assert(smartlist_contains_string_case(sl, "nOOn")); test_assert(!smartlist_contains_string_case(sl, "nooNooN")); test_assert(smartlist_contains_int_as_string(sl, 50)); test_assert(!smartlist_contains_int_as_string(sl, 60)); /* Test smartlist_choose */ { int i; int allsame = 1; int allin = 1; void *first = smartlist_choose(sl); test_assert(smartlist_contains(sl, first)); for (i = 0; i < 100; ++i) { void *second = smartlist_choose(sl); if (second != first) allsame = 0; if (!smartlist_contains(sl, second)) allin = 0; } test_assert(!allsame); test_assert(allin); } SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Test string_remove and remove and join_strings2 */ smartlist_split_string(sl, "Some say the Earth will end in ice and some in fire", " ", 0, 0); cp = smartlist_get(sl, 4); test_streq(cp, "will"); smartlist_add(sl, cp); smartlist_remove(sl, cp); tor_free(cp); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc, "Some,say,the,Earth,fire,end,in,ice,and,some,in"); tor_free(cp_alloc); smartlist_string_remove(sl, "in"); cp_alloc = smartlist_join_strings2(sl, "+XX", 1, 0, &sz); test_streq(cp_alloc, "Some+say+the+Earth+fire+end+some+ice+and"); test_eq((int)sz, 40); done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); tor_free(cp_alloc); } /** Run unit tests for smartlist set manipulation functions. */ static void test_container_smartlist_overlap(void) { smartlist_t *sl = smartlist_new(); smartlist_t *ints = smartlist_new(); smartlist_t *odds = smartlist_new(); smartlist_t *evens = smartlist_new(); smartlist_t *primes = smartlist_new(); int i; for (i=1; i < 10; i += 2) smartlist_add(odds, (void*)(uintptr_t)i); for (i=0; i < 10; i += 2) smartlist_add(evens, (void*)(uintptr_t)i); /* add_all */ smartlist_add_all(ints, odds); smartlist_add_all(ints, evens); test_eq(smartlist_len(ints), 10); smartlist_add(primes, (void*)2); smartlist_add(primes, (void*)3); smartlist_add(primes, (void*)5); smartlist_add(primes, (void*)7); /* overlap */ test_assert(smartlist_overlap(ints, odds)); test_assert(smartlist_overlap(odds, primes)); test_assert(smartlist_overlap(evens, primes)); test_assert(!smartlist_overlap(odds, evens)); /* intersect */ smartlist_add_all(sl, odds); smartlist_intersect(sl, primes); test_eq(smartlist_len(sl), 3); test_assert(smartlist_contains(sl, (void*)3)); test_assert(smartlist_contains(sl, (void*)5)); test_assert(smartlist_contains(sl, (void*)7)); /* subtract */ smartlist_add_all(sl, primes); smartlist_subtract(sl, odds); test_eq(smartlist_len(sl), 1); test_assert(smartlist_contains(sl, (void*)2)); done: smartlist_free(odds); smartlist_free(evens); smartlist_free(ints); smartlist_free(primes); smartlist_free(sl); } /** Run unit tests for smartlist-of-digests functions. */ static void test_container_smartlist_digests(void) { smartlist_t *sl = smartlist_new(); /* contains_digest */ smartlist_add(sl, tor_memdup("AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN)); smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN)); smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN)); test_eq(0, smartlist_contains_digest(NULL, "AAAAAAAAAAAAAAAAAAAA")); test_assert(smartlist_contains_digest(sl, "AAAAAAAAAAAAAAAAAAAA")); test_assert(smartlist_contains_digest(sl, "\00090AAB2AAAAaasdAAAAA")); test_eq(0, smartlist_contains_digest(sl, "\00090AAB2AAABaasdAAAAA")); /* sort digests */ smartlist_sort_digests(sl); test_memeq(smartlist_get(sl, 0), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN); test_memeq(smartlist_get(sl, 1), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN); test_memeq(smartlist_get(sl, 2), "AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN); test_eq(3, smartlist_len(sl)); /* uniq_digests */ smartlist_uniq_digests(sl); test_eq(2, smartlist_len(sl)); test_memeq(smartlist_get(sl, 0), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN); test_memeq(smartlist_get(sl, 1), "AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN); done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); } /** Run unit tests for concatenate-a-smartlist-of-strings functions. */ static void test_container_smartlist_join(void) { smartlist_t *sl = smartlist_new(); smartlist_t *sl2 = smartlist_new(), *sl3 = smartlist_new(), *sl4 = smartlist_new(); char *joined=NULL; /* unique, sorted. */ smartlist_split_string(sl, "Abashments Ambush Anchorman Bacon Banks Borscht " "Bunks Inhumane Insurance Knish Know Manners " "Maraschinos Stamina Sunbonnets Unicorns Wombats", " ", 0, 0); /* non-unique, sorted. */ smartlist_split_string(sl2, "Ambush Anchorman Anchorman Anemias Anemias Bacon " "Crossbowmen Inhumane Insurance Knish Know Manners " "Manners Maraschinos Wombats Wombats Work", " ", 0, 0); SMARTLIST_FOREACH_JOIN(sl, char *, cp1, sl2, char *, cp2, strcmp(cp1,cp2), smartlist_add(sl3, cp2)) { test_streq(cp1, cp2); smartlist_add(sl4, cp1); } SMARTLIST_FOREACH_JOIN_END(cp1, cp2); SMARTLIST_FOREACH(sl3, const char *, cp, test_assert(smartlist_contains(sl2, cp) && !smartlist_contains_string(sl, cp))); SMARTLIST_FOREACH(sl4, const char *, cp, test_assert(smartlist_contains(sl, cp) && smartlist_contains_string(sl2, cp))); joined = smartlist_join_strings(sl3, ",", 0, NULL); test_streq(joined, "Anemias,Anemias,Crossbowmen,Work"); tor_free(joined); joined = smartlist_join_strings(sl4, ",", 0, NULL); test_streq(joined, "Ambush,Anchorman,Anchorman,Bacon,Inhumane,Insurance," "Knish,Know,Manners,Manners,Maraschinos,Wombats,Wombats"); tor_free(joined); done: smartlist_free(sl4); smartlist_free(sl3); SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp)); smartlist_free(sl2); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); tor_free(joined); } /** Run unit tests for bitarray code */ static void test_container_bitarray(void) { bitarray_t *ba = NULL; int i, j, ok=1; ba = bitarray_init_zero(1); test_assert(ba); test_assert(! bitarray_is_set(ba, 0)); bitarray_set(ba, 0); test_assert(bitarray_is_set(ba, 0)); bitarray_clear(ba, 0); test_assert(! bitarray_is_set(ba, 0)); bitarray_free(ba); ba = bitarray_init_zero(1023); for (i = 1; i < 64; ) { for (j = 0; j < 1023; ++j) { if (j % i) bitarray_set(ba, j); else bitarray_clear(ba, j); } for (j = 0; j < 1023; ++j) { if (!bool_eq(bitarray_is_set(ba, j), j%i)) ok = 0; } test_assert(ok); if (i < 7) ++i; else if (i == 28) i = 32; else i += 7; } done: if (ba) bitarray_free(ba); } /** Run unit tests for digest set code (implemented as a hashtable or as a * bloom filter) */ static void test_container_digestset(void) { smartlist_t *included = smartlist_new(); char d[DIGEST_LEN]; int i; int ok = 1; int false_positives = 0; digestset_t *set = NULL; for (i = 0; i < 1000; ++i) { crypto_rand(d, DIGEST_LEN); smartlist_add(included, tor_memdup(d, DIGEST_LEN)); } set = digestset_new(1000); SMARTLIST_FOREACH(included, const char *, cp, if (digestset_contains(set, cp)) ok = 0); test_assert(ok); SMARTLIST_FOREACH(included, const char *, cp, digestset_add(set, cp)); SMARTLIST_FOREACH(included, const char *, cp, if (!digestset_contains(set, cp)) ok = 0); test_assert(ok); for (i = 0; i < 1000; ++i) { crypto_rand(d, DIGEST_LEN); if (digestset_contains(set, d)) ++false_positives; } test_assert(false_positives < 50); /* Should be far lower. */ done: if (set) digestset_free(set); SMARTLIST_FOREACH(included, char *, cp, tor_free(cp)); smartlist_free(included); } typedef struct pq_entry_t { const char *val; int idx; } pq_entry_t; /** Helper: return a tristate based on comparing two pq_entry_t values. */ static int compare_strings_for_pqueue_(const void *p1, const void *p2) { const pq_entry_t *e1=p1, *e2=p2; return strcmp(e1->val, e2->val); } /** Run unit tests for heap-based priority queue functions. */ static void test_container_pqueue(void) { smartlist_t *sl = smartlist_new(); int (*cmp)(const void *, const void*); const int offset = STRUCT_OFFSET(pq_entry_t, idx); #define ENTRY(s) pq_entry_t s = { #s, -1 } ENTRY(cows); ENTRY(zebras); ENTRY(fish); ENTRY(frogs); ENTRY(apples); ENTRY(squid); ENTRY(daschunds); ENTRY(eggplants); ENTRY(weissbier); ENTRY(lobsters); ENTRY(roquefort); ENTRY(chinchillas); ENTRY(fireflies); #define OK() smartlist_pqueue_assert_ok(sl, cmp, offset) cmp = compare_strings_for_pqueue_; smartlist_pqueue_add(sl, cmp, offset, &cows); smartlist_pqueue_add(sl, cmp, offset, &zebras); smartlist_pqueue_add(sl, cmp, offset, &fish); smartlist_pqueue_add(sl, cmp, offset, &frogs); smartlist_pqueue_add(sl, cmp, offset, &apples); smartlist_pqueue_add(sl, cmp, offset, &squid); smartlist_pqueue_add(sl, cmp, offset, &daschunds); smartlist_pqueue_add(sl, cmp, offset, &eggplants); smartlist_pqueue_add(sl, cmp, offset, &weissbier); smartlist_pqueue_add(sl, cmp, offset, &lobsters); smartlist_pqueue_add(sl, cmp, offset, &roquefort); OK(); test_eq(smartlist_len(sl), 11); test_eq_ptr(smartlist_get(sl, 0), &apples); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &apples); test_eq(smartlist_len(sl), 10); OK(); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &cows); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &daschunds); smartlist_pqueue_add(sl, cmp, offset, &chinchillas); OK(); smartlist_pqueue_add(sl, cmp, offset, &fireflies); OK(); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &chinchillas); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &eggplants); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fireflies); OK(); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fish); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &frogs); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &lobsters); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &roquefort); OK(); test_eq(smartlist_len(sl), 3); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &squid); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &weissbier); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &zebras); test_eq(smartlist_len(sl), 0); OK(); /* Now test remove. */ smartlist_pqueue_add(sl, cmp, offset, &cows); smartlist_pqueue_add(sl, cmp, offset, &fish); smartlist_pqueue_add(sl, cmp, offset, &frogs); smartlist_pqueue_add(sl, cmp, offset, &apples); smartlist_pqueue_add(sl, cmp, offset, &squid); smartlist_pqueue_add(sl, cmp, offset, &zebras); test_eq(smartlist_len(sl), 6); OK(); smartlist_pqueue_remove(sl, cmp, offset, &zebras); test_eq(smartlist_len(sl), 5); OK(); smartlist_pqueue_remove(sl, cmp, offset, &cows); test_eq(smartlist_len(sl), 4); OK(); smartlist_pqueue_remove(sl, cmp, offset, &apples); test_eq(smartlist_len(sl), 3); OK(); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fish); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &frogs); test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &squid); test_eq(smartlist_len(sl), 0); OK(); #undef OK done: smartlist_free(sl); } /** Run unit tests for string-to-void* map functions */ static void test_container_strmap(void) { strmap_t *map; strmap_iter_t *iter; const char *k; void *v; char *visited = NULL; smartlist_t *found_keys = NULL; map = strmap_new(); test_assert(map); test_eq(strmap_size(map), 0); test_assert(strmap_isempty(map)); v = strmap_set(map, "K1", (void*)99); test_eq_ptr(v, NULL); test_assert(!strmap_isempty(map)); v = strmap_set(map, "K2", (void*)101); test_eq_ptr(v, NULL); v = strmap_set(map, "K1", (void*)100); test_eq_ptr(v, (void*)99); test_eq_ptr(strmap_get(map,"K1"), (void*)100); test_eq_ptr(strmap_get(map,"K2"), (void*)101); test_eq_ptr(strmap_get(map,"K-not-there"), NULL); strmap_assert_ok(map); v = strmap_remove(map,"K2"); strmap_assert_ok(map); test_eq_ptr(v, (void*)101); test_eq_ptr(strmap_get(map,"K2"), NULL); test_eq_ptr(strmap_remove(map,"K2"), NULL); strmap_set(map, "K2", (void*)101); strmap_set(map, "K3", (void*)102); strmap_set(map, "K4", (void*)103); test_eq(strmap_size(map), 4); strmap_assert_ok(map); strmap_set(map, "K5", (void*)104); strmap_set(map, "K6", (void*)105); strmap_assert_ok(map); /* Test iterator. */ iter = strmap_iter_init(map); found_keys = smartlist_new(); while (!strmap_iter_done(iter)) { strmap_iter_get(iter,&k,&v); smartlist_add(found_keys, tor_strdup(k)); test_eq_ptr(v, strmap_get(map, k)); if (!strcmp(k, "K2")) { iter = strmap_iter_next_rmv(map,iter); } else { iter = strmap_iter_next(map,iter); } } /* Make sure we removed K2, but not the others. */ test_eq_ptr(strmap_get(map, "K2"), NULL); test_eq_ptr(strmap_get(map, "K5"), (void*)104); /* Make sure we visited everyone once */ smartlist_sort_strings(found_keys); visited = smartlist_join_strings(found_keys, ":", 0, NULL); test_streq(visited, "K1:K2:K3:K4:K5:K6"); strmap_assert_ok(map); /* Clean up after ourselves. */ strmap_free(map, NULL); map = NULL; /* Now try some lc functions. */ map = strmap_new(); strmap_set_lc(map,"Ab.C", (void*)1); test_eq_ptr(strmap_get(map,"ab.c"), (void*)1); strmap_assert_ok(map); test_eq_ptr(strmap_get_lc(map,"AB.C"), (void*)1); test_eq_ptr(strmap_get(map,"AB.C"), NULL); test_eq_ptr(strmap_remove_lc(map,"aB.C"), (void*)1); strmap_assert_ok(map); test_eq_ptr(strmap_get_lc(map,"AB.C"), NULL); done: if (map) strmap_free(map,NULL); if (found_keys) { SMARTLIST_FOREACH(found_keys, char *, cp, tor_free(cp)); smartlist_free(found_keys); } tor_free(visited); } /** Run unit tests for getting the median of a list. */ static void test_container_order_functions(void) { int lst[25], n = 0; // int a=12,b=24,c=25,d=60,e=77; #define median() median_int(lst, n) lst[n++] = 12; test_eq(12, median()); /* 12 */ lst[n++] = 77; //smartlist_shuffle(sl); test_eq(12, median()); /* 12, 77 */ lst[n++] = 77; //smartlist_shuffle(sl); test_eq(77, median()); /* 12, 77, 77 */ lst[n++] = 24; test_eq(24, median()); /* 12,24,77,77 */ lst[n++] = 60; lst[n++] = 12; lst[n++] = 25; //smartlist_shuffle(sl); test_eq(25, median()); /* 12,12,24,25,60,77,77 */ #undef median done: ; } static void test_di_map(void *arg) { di_digest256_map_t *map = NULL; const uint8_t key1[] = "In view of the fact that it was "; const uint8_t key2[] = "superficially convincing, being "; const uint8_t key3[] = "properly enciphered in a one-tim"; const uint8_t key4[] = "e cipher scheduled for use today"; char *v1 = tor_strdup(", it came close to causing a disaster..."); char *v2 = tor_strdup("I regret to have to advise you that the mission"); char *v3 = tor_strdup("was actually initiated..."); /* -- John Brunner, _The Shockwave Rider_ */ (void)arg; /* Try searching on an empty map. */ tt_ptr_op(NULL, ==, dimap_search(map, key1, NULL)); tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL)); tt_ptr_op(v3, ==, dimap_search(map, key2, v3)); dimap_free(map, NULL); map = NULL; /* Add a single entry. */ dimap_add_entry(&map, key1, v1); tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL)); tt_ptr_op(v3, ==, dimap_search(map, key2, v3)); tt_ptr_op(v1, ==, dimap_search(map, key1, NULL)); /* Now try it with three entries in the map. */ dimap_add_entry(&map, key2, v2); dimap_add_entry(&map, key3, v3); tt_ptr_op(v1, ==, dimap_search(map, key1, NULL)); tt_ptr_op(v2, ==, dimap_search(map, key2, NULL)); tt_ptr_op(v3, ==, dimap_search(map, key3, NULL)); tt_ptr_op(NULL, ==, dimap_search(map, key4, NULL)); tt_ptr_op(v1, ==, dimap_search(map, key4, v1)); done: tor_free(v1); tor_free(v2); tor_free(v3); dimap_free(map, NULL); } /** Run unit tests for fp_pair-to-void* map functions */ static void test_container_fp_pair_map(void) { fp_pair_map_t *map; fp_pair_t fp1, fp2, fp3, fp4, fp5, fp6; void *v; fp_pair_map_iter_t *iter; fp_pair_t k; map = fp_pair_map_new(); test_assert(map); test_eq(fp_pair_map_size(map), 0); test_assert(fp_pair_map_isempty(map)); memset(fp1.first, 0x11, DIGEST_LEN); memset(fp1.second, 0x12, DIGEST_LEN); memset(fp2.first, 0x21, DIGEST_LEN); memset(fp2.second, 0x22, DIGEST_LEN); memset(fp3.first, 0x31, DIGEST_LEN); memset(fp3.second, 0x32, DIGEST_LEN); memset(fp4.first, 0x41, DIGEST_LEN); memset(fp4.second, 0x42, DIGEST_LEN); memset(fp5.first, 0x51, DIGEST_LEN); memset(fp5.second, 0x52, DIGEST_LEN); memset(fp6.first, 0x61, DIGEST_LEN); memset(fp6.second, 0x62, DIGEST_LEN); v = fp_pair_map_set(map, &fp1, (void*)99); test_eq(v, NULL); test_assert(!fp_pair_map_isempty(map)); v = fp_pair_map_set(map, &fp2, (void*)101); test_eq(v, NULL); v = fp_pair_map_set(map, &fp1, (void*)100); test_eq(v, (void*)99); test_eq_ptr(fp_pair_map_get(map, &fp1), (void*)100); test_eq_ptr(fp_pair_map_get(map, &fp2), (void*)101); test_eq_ptr(fp_pair_map_get(map, &fp3), NULL); fp_pair_map_assert_ok(map); v = fp_pair_map_remove(map, &fp2); fp_pair_map_assert_ok(map); test_eq_ptr(v, (void*)101); test_eq_ptr(fp_pair_map_get(map, &fp2), NULL); test_eq_ptr(fp_pair_map_remove(map, &fp2), NULL); fp_pair_map_set(map, &fp2, (void*)101); fp_pair_map_set(map, &fp3, (void*)102); fp_pair_map_set(map, &fp4, (void*)103); test_eq(fp_pair_map_size(map), 4); fp_pair_map_assert_ok(map); fp_pair_map_set(map, &fp5, (void*)104); fp_pair_map_set(map, &fp6, (void*)105); fp_pair_map_assert_ok(map); /* Test iterator. */ iter = fp_pair_map_iter_init(map); while (!fp_pair_map_iter_done(iter)) { fp_pair_map_iter_get(iter, &k, &v); test_eq_ptr(v, fp_pair_map_get(map, &k)); if (tor_memeq(&fp2, &k, sizeof(fp2))) { iter = fp_pair_map_iter_next_rmv(map, iter); } else { iter = fp_pair_map_iter_next(map, iter); } } /* Make sure we removed fp2, but not the others. */ test_eq_ptr(fp_pair_map_get(map, &fp2), NULL); test_eq_ptr(fp_pair_map_get(map, &fp5), (void*)104); fp_pair_map_assert_ok(map); /* Clean up after ourselves. */ fp_pair_map_free(map, NULL); map = NULL; done: if (map) fp_pair_map_free(map, NULL); } #define CONTAINER_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name } struct testcase_t container_tests[] = { CONTAINER_LEGACY(smartlist_basic), CONTAINER_LEGACY(smartlist_strings), CONTAINER_LEGACY(smartlist_overlap), CONTAINER_LEGACY(smartlist_digests), CONTAINER_LEGACY(smartlist_join), CONTAINER_LEGACY(bitarray), CONTAINER_LEGACY(digestset), CONTAINER_LEGACY(strmap), CONTAINER_LEGACY(pqueue), CONTAINER_LEGACY(order_functions), { "di_map", test_di_map, 0, NULL, NULL }, CONTAINER_LEGACY(fp_pair_map), END_OF_TESTCASES }; tor-0.2.4.20/src/test/test_config.c0000644000175000017500000001614212255745673013724 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #include "or.h" #include "addressmap.h" #include "config.h" #include "confparse.h" #include "connection_edge.h" #include "test.h" static void test_config_addressmap(void *arg) { char buf[1024]; char address[256]; time_t expires = TIME_MAX; (void)arg; strlcpy(buf, "MapAddress .invalidwildcard.com *.torserver.exit\n" // invalid "MapAddress *invalidasterisk.com *.torserver.exit\n" // invalid "MapAddress *.google.com *.torserver.exit\n" "MapAddress *.yahoo.com *.google.com.torserver.exit\n" "MapAddress *.cn.com www.cnn.com\n" "MapAddress *.cnn.com www.cnn.com\n" "MapAddress ex.com www.cnn.com\n" "MapAddress ey.com *.cnn.com\n" "MapAddress www.torproject.org 1.1.1.1\n" "MapAddress other.torproject.org " "this.torproject.org.otherserver.exit\n" "MapAddress test.torproject.org 2.2.2.2\n" "MapAddress www.google.com 3.3.3.3\n" "MapAddress www.example.org 4.4.4.4\n" "MapAddress 4.4.4.4 7.7.7.7\n" "MapAddress 4.4.4.4 5.5.5.5\n" "MapAddress www.infiniteloop.org 6.6.6.6\n" "MapAddress 6.6.6.6 www.infiniteloop.org\n" , sizeof(buf)); config_get_lines(buf, &(get_options_mutable()->AddressMap), 0); config_register_addressmaps(get_options()); /* Use old interface for now, so we don't need to rewrite the unit tests */ #define addressmap_rewrite(a,s,eo,ao) \ addressmap_rewrite((a),(s),AMR_FLAG_USE_IPV4_DNS|AMR_FLAG_USE_IPV6_DNS, \ (eo),(ao)) /* MapAddress .invalidwildcard.com .torserver.exit - no match */ strlcpy(address, "www.invalidwildcard.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* MapAddress *invalidasterisk.com .torserver.exit - no match */ strlcpy(address, "www.invalidasterisk.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* Where no mapping for FQDN match on top-level domain */ /* MapAddress .google.com .torserver.exit */ strlcpy(address, "reader.google.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "reader.torserver.exit"); /* MapAddress *.yahoo.com *.google.com.torserver.exit */ strlcpy(address, "reader.yahoo.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "reader.google.com.torserver.exit"); /*MapAddress *.cnn.com www.cnn.com */ strlcpy(address, "cnn.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.cnn.com"); /* MapAddress .cn.com www.cnn.com */ strlcpy(address, "www.cn.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.cnn.com"); /* MapAddress ex.com www.cnn.com - no match */ strlcpy(address, "www.ex.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* MapAddress ey.com *.cnn.com - invalid expression */ strlcpy(address, "ey.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* Where mapping for FQDN match on FQDN */ strlcpy(address, "www.google.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "3.3.3.3"); strlcpy(address, "www.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "1.1.1.1"); strlcpy(address, "other.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "this.torproject.org.otherserver.exit"); strlcpy(address, "test.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "2.2.2.2"); /* Test a chain of address mappings and the order in which they were added: "MapAddress www.example.org 4.4.4.4" "MapAddress 4.4.4.4 7.7.7.7" "MapAddress 4.4.4.4 5.5.5.5" */ strlcpy(address, "www.example.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "5.5.5.5"); /* Test infinite address mapping results in no change */ strlcpy(address, "www.infiniteloop.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.infiniteloop.org"); /* Test we don't find false positives */ strlcpy(address, "www.example.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); /* Test top-level-domain matching a bit harder */ addressmap_clear_configured(); strlcpy(buf, "MapAddress *.com *.torserver.exit\n" "MapAddress *.torproject.org 1.1.1.1\n" "MapAddress *.net 2.2.2.2\n" , sizeof(buf)); config_get_lines(buf, &(get_options_mutable()->AddressMap), 0); config_register_addressmaps(get_options()); strlcpy(address, "www.abc.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.abc.torserver.exit"); strlcpy(address, "www.def.com", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "www.def.torserver.exit"); strlcpy(address, "www.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "1.1.1.1"); strlcpy(address, "test.torproject.org", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "1.1.1.1"); strlcpy(address, "torproject.net", sizeof(address)); test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL)); test_streq(address, "2.2.2.2"); /* We don't support '*' as a mapping directive */ addressmap_clear_configured(); strlcpy(buf, "MapAddress * *.torserver.exit\n", sizeof(buf)); config_get_lines(buf, &(get_options_mutable()->AddressMap), 0); config_register_addressmaps(get_options()); strlcpy(address, "www.abc.com", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); strlcpy(address, "www.def.net", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); strlcpy(address, "www.torproject.org", sizeof(address)); test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL)); #undef addressmap_rewrite done: ; } #define CONFIG_TEST(name, flags) \ { #name, test_config_ ## name, flags, NULL, NULL } struct testcase_t config_tests[] = { CONFIG_TEST(addressmap, 0), END_OF_TESTCASES }; tor-0.2.4.20/src/test/test.h0000644000175000017500000000630112166112777012372 00000000000000/* Copyright (c) 2001-2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_H #define TOR_TEST_H /** * \file test.h * \brief Macros and functions used by unit tests. */ #include "compat.h" #include "tinytest.h" #define TT_EXIT_TEST_FUNCTION STMT_BEGIN goto done; STMT_END #include "tinytest_macros.h" #ifdef __GNUC__ #define PRETTY_FUNCTION __PRETTY_FUNCTION__ #else #define PRETTY_FUNCTION "" #endif #define test_fail_msg(msg) TT_DIE((msg)) #define test_fail() test_fail_msg("Assertion failed.") #define test_assert(expr) tt_assert(expr) #define test_eq(expr1, expr2) tt_int_op((expr1), ==, (expr2)) #define test_eq_ptr(expr1, expr2) tt_ptr_op((expr1), ==, (expr2)) #define test_neq(expr1, expr2) tt_int_op((expr1), !=, (expr2)) #define test_neq_ptr(expr1, expr2) tt_ptr_op((expr1), !=, (expr2)) #define test_streq(expr1, expr2) tt_str_op((expr1), ==, (expr2)) #define test_strneq(expr1, expr2) tt_str_op((expr1), !=, (expr2)) #define test_mem_op(expr1, op, expr2, len) \ tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \ const char *, \ (memcmp(val1_, val2_, len) op 0), \ char *, "%s", \ { size_t printlen = (len)*2+1; \ print_ = tor_malloc(printlen); \ base16_encode(print_, printlen, value_, \ (len)); }, \ { tor_free(print_); }, \ TT_EXIT_TEST_FUNCTION \ ); #define test_memeq(expr1, expr2, len) test_mem_op((expr1), ==, (expr2), len) #define test_memneq(expr1, expr2, len) test_mem_op((expr1), !=, (expr2), len) /* As test_mem_op, but decodes 'hex' before comparing. There must be a * local char* variable called mem_op_hex_tmp for this to work. */ #define test_mem_op_hex(expr1, op, hex) \ STMT_BEGIN \ size_t length = strlen(hex); \ tor_free(mem_op_hex_tmp); \ mem_op_hex_tmp = tor_malloc(length/2); \ tor_assert((length&1)==0); \ base16_decode(mem_op_hex_tmp, length/2, hex, length); \ test_mem_op(expr1, op, mem_op_hex_tmp, length/2); \ STMT_END #define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, ==, hex) #define tt_double_op(a,op,b) \ tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%f", \ TT_EXIT_TEST_FUNCTION) const char *get_fname(const char *name); crypto_pk_t *pk_generate(int idx); void legacy_test_helper(void *data); extern const struct testcase_setup_t legacy_setup; #endif tor-0.2.4.20/src/test/test_dir.c0000644000175000017500000024665212255745673013250 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #include #define DIRSERV_PRIVATE #define DIRVOTE_PRIVATE #define ROUTER_PRIVATE #define ROUTERLIST_PRIVATE #define HIBERNATE_PRIVATE #include "or.h" #include "config.h" #include "directory.h" #include "dirserv.h" #include "dirvote.h" #include "hibernate.h" #include "networkstatus.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" #include "test.h" static void test_dir_nicknames(void) { test_assert( is_legal_nickname("a")); test_assert(!is_legal_nickname("")); test_assert(!is_legal_nickname("abcdefghijklmnopqrst")); /* 20 chars */ test_assert(!is_legal_nickname("hyphen-")); /* bad char */ test_assert( is_legal_nickname("abcdefghijklmnopqrs")); /* 19 chars */ test_assert(!is_legal_nickname("$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA")); /* valid */ test_assert( is_legal_nickname_or_hexdigest( "$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA")); test_assert( is_legal_nickname_or_hexdigest( "$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA=fred")); test_assert( is_legal_nickname_or_hexdigest( "$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA~fred")); /* too short */ test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); /* illegal char */ test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); /* hex part too long */ test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=fred")); /* Bad nickname */ test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")); test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~")); test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~hyphen-")); test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~" "abcdefghijklmnoppqrst")); /* Bad extra char. */ test_assert(!is_legal_nickname_or_hexdigest( "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!")); test_assert(is_legal_nickname_or_hexdigest("xyzzy")); test_assert(is_legal_nickname_or_hexdigest("abcdefghijklmnopqrs")); test_assert(!is_legal_nickname_or_hexdigest("abcdefghijklmnopqrst")); done: ; } /** Run unit tests for router descriptor generation logic. */ static void test_dir_formats(void) { char *buf = NULL; char buf2[8192]; char platform[256]; char fingerprint[FINGERPRINT_LEN+1]; char *pk1_str = NULL, *pk2_str = NULL, *cp; size_t pk1_str_len, pk2_str_len; routerinfo_t *r1=NULL, *r2=NULL; crypto_pk_t *pk1 = NULL, *pk2 = NULL; routerinfo_t *rp1 = NULL, *rp2 = NULL; addr_policy_t *ex1, *ex2; routerlist_t *dir1 = NULL, *dir2 = NULL; or_options_t *options = get_options_mutable(); const addr_policy_t *p; pk1 = pk_generate(0); pk2 = pk_generate(1); test_assert(pk1 && pk2); hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE); get_platform_str(platform, sizeof(platform)); r1 = tor_malloc_zero(sizeof(routerinfo_t)); r1->address = tor_strdup("18.244.0.1"); r1->addr = 0xc0a80001u; /* 192.168.0.1 */ r1->cache_info.published_on = 0; r1->or_port = 9000; r1->dir_port = 9003; tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::"); r1->ipv6_orport = 9999; r1->onion_pkey = crypto_pk_dup_key(pk1); r1->identity_pkey = crypto_pk_dup_key(pk2); r1->bandwidthrate = 1000; r1->bandwidthburst = 5000; r1->bandwidthcapacity = 10000; r1->exit_policy = NULL; r1->nickname = tor_strdup("Magri"); r1->platform = tor_strdup(platform); ex1 = tor_malloc_zero(sizeof(addr_policy_t)); ex2 = tor_malloc_zero(sizeof(addr_policy_t)); ex1->policy_type = ADDR_POLICY_ACCEPT; tor_addr_from_ipv4h(&ex1->addr, 0); ex1->maskbits = 0; ex1->prt_min = ex1->prt_max = 80; ex2->policy_type = ADDR_POLICY_REJECT; tor_addr_from_ipv4h(&ex2->addr, 18<<24); ex2->maskbits = 8; ex2->prt_min = ex2->prt_max = 24; r2 = tor_malloc_zero(sizeof(routerinfo_t)); r2->address = tor_strdup("1.1.1.1"); r2->addr = 0x0a030201u; /* 10.3.2.1 */ r2->platform = tor_strdup(platform); r2->cache_info.published_on = 5; r2->or_port = 9005; r2->dir_port = 0; r2->onion_pkey = crypto_pk_dup_key(pk2); r2->onion_curve25519_pkey = tor_malloc_zero(sizeof(curve25519_public_key_t)); curve25519_public_from_base64(r2->onion_curve25519_pkey, "skyinAnvardNostarsNomoonNowindormistsorsnow"); r2->identity_pkey = crypto_pk_dup_key(pk1); r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000; r2->exit_policy = smartlist_new(); smartlist_add(r2->exit_policy, ex1); smartlist_add(r2->exit_policy, ex2); r2->nickname = tor_strdup("Fred"); test_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str, &pk1_str_len)); test_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str, &pk2_str_len)); /* XXXX025 router_dump_to_string should really take this from ri.*/ options->ContactInfo = tor_strdup("Magri White " ""); buf = router_dump_router_to_string(r1, pk2); tor_free(options->ContactInfo); test_assert(buf); strlcpy(buf2, "router Magri 18.244.0.1 9000 0 9003\n" "or-address [1:2:3:4::]:9999\n" "platform Tor "VERSION" on ", sizeof(buf2)); strlcat(buf2, get_uname(), sizeof(buf2)); strlcat(buf2, "\n" "protocols Link 1 2 Circuit 1\n" "published 1970-01-01 00:00:00\n" "fingerprint ", sizeof(buf2)); test_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1)); strlcat(buf2, fingerprint, sizeof(buf2)); strlcat(buf2, "\nuptime 0\n" /* XXX the "0" above is hard-coded, but even if we made it reflect * uptime, that still wouldn't make it right, because the two * descriptors might be made on different seconds... hm. */ "bandwidth 1000 5000 10000\n" "onion-key\n", sizeof(buf2)); strlcat(buf2, pk1_str, sizeof(buf2)); strlcat(buf2, "signing-key\n", sizeof(buf2)); strlcat(buf2, pk2_str, sizeof(buf2)); strlcat(buf2, "hidden-service-dir\n", sizeof(buf2)); strlcat(buf2, "contact Magri White \n", sizeof(buf2)); strlcat(buf2, "reject *:*\nrouter-signature\n", sizeof(buf2)); buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same * twice */ test_streq(buf, buf2); tor_free(buf); buf = router_dump_router_to_string(r1, pk2); test_assert(buf); cp = buf; rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL); test_assert(rp1); test_streq(rp1->address, r1->address); test_eq(rp1->or_port, r1->or_port); //test_eq(rp1->dir_port, r1->dir_port); test_eq(rp1->bandwidthrate, r1->bandwidthrate); test_eq(rp1->bandwidthburst, r1->bandwidthburst); test_eq(rp1->bandwidthcapacity, r1->bandwidthcapacity); test_assert(crypto_pk_cmp_keys(rp1->onion_pkey, pk1) == 0); test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0); //test_assert(rp1->exit_policy == NULL); strlcpy(buf2, "router Fred 1.1.1.1 9005 0 0\n" "platform Tor "VERSION" on ", sizeof(buf2)); strlcat(buf2, get_uname(), sizeof(buf2)); strlcat(buf2, "\n" "protocols Link 1 2 Circuit 1\n" "published 1970-01-01 00:00:05\n" "fingerprint ", sizeof(buf2)); test_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1)); strlcat(buf2, fingerprint, sizeof(buf2)); strlcat(buf2, "\nuptime 0\n" "bandwidth 3000 3000 3000\n", sizeof(buf2)); strlcat(buf2, "onion-key\n", sizeof(buf2)); strlcat(buf2, pk2_str, sizeof(buf2)); strlcat(buf2, "signing-key\n", sizeof(buf2)); strlcat(buf2, pk1_str, sizeof(buf2)); strlcat(buf2, "hidden-service-dir\n", sizeof(buf2)); strlcat(buf2, "ntor-onion-key " "skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2)); strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2)); strlcat(buf2, "router-signature\n", sizeof(buf2)); buf = router_dump_router_to_string(r2, pk1); buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same * twice */ test_streq(buf, buf2); tor_free(buf); buf = router_dump_router_to_string(r2, pk1); cp = buf; rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL); test_assert(rp2); test_streq(rp2->address, r2->address); test_eq(rp2->or_port, r2->or_port); test_eq(rp2->dir_port, r2->dir_port); test_eq(rp2->bandwidthrate, r2->bandwidthrate); test_eq(rp2->bandwidthburst, r2->bandwidthburst); test_eq(rp2->bandwidthcapacity, r2->bandwidthcapacity); test_memeq(rp2->onion_curve25519_pkey->public_key, r2->onion_curve25519_pkey->public_key, CURVE25519_PUBKEY_LEN); test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0); test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0); test_eq(smartlist_len(rp2->exit_policy), 2); p = smartlist_get(rp2->exit_policy, 0); test_eq(p->policy_type, ADDR_POLICY_ACCEPT); test_assert(tor_addr_is_null(&p->addr)); test_eq(p->maskbits, 0); test_eq(p->prt_min, 80); test_eq(p->prt_max, 80); p = smartlist_get(rp2->exit_policy, 1); test_eq(p->policy_type, ADDR_POLICY_REJECT); test_assert(tor_addr_eq(&p->addr, &ex2->addr)); test_eq(p->maskbits, 8); test_eq(p->prt_min, 24); test_eq(p->prt_max, 24); #if 0 /* Okay, now for the directories. */ { fingerprint_list = smartlist_new(); crypto_pk_get_fingerprint(pk2, buf, 1); add_fingerprint_to_dir("Magri", buf, fingerprint_list); crypto_pk_get_fingerprint(pk1, buf, 1); add_fingerprint_to_dir("Fred", buf, fingerprint_list); } #endif dirserv_free_fingerprint_list(); done: if (r1) routerinfo_free(r1); if (r2) routerinfo_free(r2); tor_free(buf); tor_free(pk1_str); tor_free(pk2_str); if (pk1) crypto_pk_free(pk1); if (pk2) crypto_pk_free(pk2); if (rp1) routerinfo_free(rp1); tor_free(dir1); /* XXXX And more !*/ tor_free(dir2); /* And more !*/ } static void test_dir_versions(void) { tor_version_t ver1; /* Try out version parsing functionality */ test_eq(0, tor_version_parse("0.3.4pre2-cvs", &ver1)); test_eq(0, ver1.major); test_eq(3, ver1.minor); test_eq(4, ver1.micro); test_eq(VER_PRE, ver1.status); test_eq(2, ver1.patchlevel); test_eq(0, tor_version_parse("0.3.4rc1", &ver1)); test_eq(0, ver1.major); test_eq(3, ver1.minor); test_eq(4, ver1.micro); test_eq(VER_RC, ver1.status); test_eq(1, ver1.patchlevel); test_eq(0, tor_version_parse("1.3.4", &ver1)); test_eq(1, ver1.major); test_eq(3, ver1.minor); test_eq(4, ver1.micro); test_eq(VER_RELEASE, ver1.status); test_eq(0, ver1.patchlevel); test_eq(0, tor_version_parse("1.3.4.999", &ver1)); test_eq(1, ver1.major); test_eq(3, ver1.minor); test_eq(4, ver1.micro); test_eq(VER_RELEASE, ver1.status); test_eq(999, ver1.patchlevel); test_eq(0, tor_version_parse("0.1.2.4-alpha", &ver1)); test_eq(0, ver1.major); test_eq(1, ver1.minor); test_eq(2, ver1.micro); test_eq(4, ver1.patchlevel); test_eq(VER_RELEASE, ver1.status); test_streq("alpha", ver1.status_tag); test_eq(0, tor_version_parse("0.1.2.4", &ver1)); test_eq(0, ver1.major); test_eq(1, ver1.minor); test_eq(2, ver1.micro); test_eq(4, ver1.patchlevel); test_eq(VER_RELEASE, ver1.status); test_streq("", ver1.status_tag); #define tt_versionstatus_op(vs1, op, vs2) \ tt_assert_test_type(vs1,vs2,#vs1" "#op" "#vs2,version_status_t, \ (val1_ op val2_),"%d",TT_EXIT_TEST_FUNCTION) #define test_v_i_o(val, ver, lst) \ tt_versionstatus_op(val, ==, tor_version_is_obsolete(ver, lst)) /* make sure tor_version_is_obsolete() works */ test_v_i_o(VS_OLD, "0.0.1", "Tor 0.0.2"); test_v_i_o(VS_OLD, "0.0.1", "0.0.2, Tor 0.0.3"); test_v_i_o(VS_OLD, "0.0.1", "0.0.2,Tor 0.0.3"); test_v_i_o(VS_OLD, "0.0.1","0.0.3,BetterTor 0.0.1"); test_v_i_o(VS_RECOMMENDED, "0.0.2", "Tor 0.0.2,Tor 0.0.3"); test_v_i_o(VS_NEW_IN_SERIES, "0.0.2", "Tor 0.0.2pre1,Tor 0.0.3"); test_v_i_o(VS_OLD, "0.0.2", "Tor 0.0.2.1,Tor 0.0.3"); test_v_i_o(VS_NEW, "0.1.0", "Tor 0.0.2,Tor 0.0.3"); test_v_i_o(VS_RECOMMENDED, "0.0.7rc2", "0.0.7,Tor 0.0.7rc2,Tor 0.0.8"); test_v_i_o(VS_OLD, "0.0.5.0", "0.0.5.1-cvs"); test_v_i_o(VS_NEW_IN_SERIES, "0.0.5.1-cvs", "0.0.5, 0.0.6"); /* Not on list, but newer than any in same series. */ test_v_i_o(VS_NEW_IN_SERIES, "0.1.0.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"); /* Series newer than any on list. */ test_v_i_o(VS_NEW, "0.1.2.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"); /* Series older than any on list. */ test_v_i_o(VS_OLD, "0.0.1.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"); /* Not on list, not newer than any on same series. */ test_v_i_o(VS_UNRECOMMENDED, "0.1.0.1", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"); /* On list, not newer than any on same series. */ test_v_i_o(VS_UNRECOMMENDED, "0.1.0.1", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"); test_eq(0, tor_version_as_new_as("Tor 0.0.5", "0.0.9pre1-cvs")); test_eq(1, tor_version_as_new_as( "Tor 0.0.8 on Darwin 64-121-192-100.c3-0." "sfpo-ubr1.sfrn-sfpo.ca.cable.rcn.com Power Macintosh", "0.0.8rc2")); test_eq(0, tor_version_as_new_as( "Tor 0.0.8 on Darwin 64-121-192-100.c3-0." "sfpo-ubr1.sfrn-sfpo.ca.cable.rcn.com Power Macintosh", "0.0.8.2")); /* Now try svn revisions. */ test_eq(1, tor_version_as_new_as("Tor 0.2.1.0-dev (r100)", "Tor 0.2.1.0-dev (r99)")); test_eq(1, tor_version_as_new_as("Tor 0.2.1.0-dev (r100) on Banana Jr", "Tor 0.2.1.0-dev (r99) on Hal 9000")); test_eq(1, tor_version_as_new_as("Tor 0.2.1.0-dev (r100)", "Tor 0.2.1.0-dev on Colossus")); test_eq(0, tor_version_as_new_as("Tor 0.2.1.0-dev (r99)", "Tor 0.2.1.0-dev (r100)")); test_eq(0, tor_version_as_new_as("Tor 0.2.1.0-dev (r99) on MCP", "Tor 0.2.1.0-dev (r100) on AM")); test_eq(0, tor_version_as_new_as("Tor 0.2.1.0-dev", "Tor 0.2.1.0-dev (r99)")); test_eq(1, tor_version_as_new_as("Tor 0.2.1.1", "Tor 0.2.1.0-dev (r99)")); /* Now try git revisions */ test_eq(0, tor_version_parse("0.5.6.7 (git-ff00ff)", &ver1)); test_eq(0, ver1.major); test_eq(5, ver1.minor); test_eq(6, ver1.micro); test_eq(7, ver1.patchlevel); test_eq(3, ver1.git_tag_len); test_memeq(ver1.git_tag, "\xff\x00\xff", 3); test_eq(-1, tor_version_parse("0.5.6.7 (git-ff00xx)", &ver1)); test_eq(-1, tor_version_parse("0.5.6.7 (git-ff00fff)", &ver1)); test_eq(0, tor_version_parse("0.5.6.7 (git ff00fff)", &ver1)); done: ; } /** Run unit tests for directory fp_pair functions. */ static void test_dir_fp_pairs(void) { smartlist_t *sl = smartlist_new(); fp_pair_t *pair; dir_split_resource_into_fingerprint_pairs( /* Two pairs, out of order, with one duplicate. */ "73656372657420646174612E0000000000FFFFFF-" "557365204145532d32353620696e73746561642e+" "73656372657420646174612E0000000000FFFFFF-" "557365204145532d32353620696e73746561642e+" "48657861646563696d616c2069736e277420736f-" "676f6f6420666f7220686964696e6720796f7572.z", sl); test_eq(smartlist_len(sl), 2); pair = smartlist_get(sl, 0); test_memeq(pair->first, "Hexadecimal isn't so", DIGEST_LEN); test_memeq(pair->second, "good for hiding your", DIGEST_LEN); pair = smartlist_get(sl, 1); test_memeq(pair->first, "secret data.\0\0\0\0\0\xff\xff\xff", DIGEST_LEN); test_memeq(pair->second, "Use AES-256 instead.", DIGEST_LEN); done: SMARTLIST_FOREACH(sl, fp_pair_t *, pair, tor_free(pair)); smartlist_free(sl); } static void test_dir_split_fps(void *testdata) { smartlist_t *sl = smartlist_new(); char *mem_op_hex_tmp = NULL; (void)testdata; /* Some example hex fingerprints and their base64 equivalents */ #define HEX1 "Fe0daff89127389bc67558691231234551193EEE" #define HEX2 "Deadbeef99999991111119999911111111f00ba4" #define HEX3 "b33ff00db33ff00db33ff00db33ff00db33ff00d" #define HEX256_1 \ "f3f3f3f3fbbbbf3f3f3f3fbbbf3f3f3f3fbbbbf3f3f3f3fbbbf3f3f3f3fbbbbf" #define HEX256_2 \ "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccCCc" #define HEX256_3 \ "0123456789ABCdef0123456789ABCdef0123456789ABCdef0123456789ABCdef" #define B64_1 "/g2v+JEnOJvGdVhpEjEjRVEZPu4" #define B64_2 "3q2+75mZmZERERmZmRERERHwC6Q" #define B64_256_1 "8/Pz8/u7vz8/Pz+7vz8/Pz+7u/Pz8/P7u/Pz8/P7u78" #define B64_256_2 "zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMw" /* no flags set */ dir_split_resource_into_fingerprints("A+C+B", sl, NULL, 0); tt_int_op(smartlist_len(sl), ==, 3); tt_str_op(smartlist_get(sl, 0), ==, "A"); tt_str_op(smartlist_get(sl, 1), ==, "C"); tt_str_op(smartlist_get(sl, 2), ==, "B"); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* uniq strings. */ dir_split_resource_into_fingerprints("A+C+B+A+B+B", sl, NULL, DSR_SORT_UNIQ); tt_int_op(smartlist_len(sl), ==, 3); tt_str_op(smartlist_get(sl, 0), ==, "A"); tt_str_op(smartlist_get(sl, 1), ==, "B"); tt_str_op(smartlist_get(sl, 2), ==, "C"); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Decode hex. */ dir_split_resource_into_fingerprints(HEX1"+"HEX2, sl, NULL, DSR_HEX); tt_int_op(smartlist_len(sl), ==, 2); test_mem_op_hex(smartlist_get(sl, 0), ==, HEX1); test_mem_op_hex(smartlist_get(sl, 1), ==, HEX2); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* decode hex and drop weirdness. */ dir_split_resource_into_fingerprints(HEX1"+bogus+"HEX2"+"HEX256_1, sl, NULL, DSR_HEX); tt_int_op(smartlist_len(sl), ==, 2); test_mem_op_hex(smartlist_get(sl, 0), ==, HEX1); test_mem_op_hex(smartlist_get(sl, 1), ==, HEX2); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Decode long hex */ dir_split_resource_into_fingerprints(HEX256_1"+"HEX256_2"+"HEX2"+"HEX256_3, sl, NULL, DSR_HEX|DSR_DIGEST256); tt_int_op(smartlist_len(sl), ==, 3); test_mem_op_hex(smartlist_get(sl, 0), ==, HEX256_1); test_mem_op_hex(smartlist_get(sl, 1), ==, HEX256_2); test_mem_op_hex(smartlist_get(sl, 2), ==, HEX256_3); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Decode hex and sort. */ dir_split_resource_into_fingerprints(HEX1"+"HEX2"+"HEX3"+"HEX2, sl, NULL, DSR_HEX|DSR_SORT_UNIQ); tt_int_op(smartlist_len(sl), ==, 3); test_mem_op_hex(smartlist_get(sl, 0), ==, HEX3); test_mem_op_hex(smartlist_get(sl, 1), ==, HEX2); test_mem_op_hex(smartlist_get(sl, 2), ==, HEX1); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Decode long hex and sort */ dir_split_resource_into_fingerprints(HEX256_1"+"HEX256_2"+"HEX256_3 "+"HEX256_1, sl, NULL, DSR_HEX|DSR_DIGEST256|DSR_SORT_UNIQ); tt_int_op(smartlist_len(sl), ==, 3); test_mem_op_hex(smartlist_get(sl, 0), ==, HEX256_3); test_mem_op_hex(smartlist_get(sl, 1), ==, HEX256_2); test_mem_op_hex(smartlist_get(sl, 2), ==, HEX256_1); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Decode base64 */ dir_split_resource_into_fingerprints(B64_1"-"B64_2, sl, NULL, DSR_BASE64); tt_int_op(smartlist_len(sl), ==, 2); test_mem_op_hex(smartlist_get(sl, 0), ==, HEX1); test_mem_op_hex(smartlist_get(sl, 1), ==, HEX2); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Decode long base64 */ dir_split_resource_into_fingerprints(B64_256_1"-"B64_256_2, sl, NULL, DSR_BASE64|DSR_DIGEST256); tt_int_op(smartlist_len(sl), ==, 2); test_mem_op_hex(smartlist_get(sl, 0), ==, HEX256_1); test_mem_op_hex(smartlist_get(sl, 1), ==, HEX256_2); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); dir_split_resource_into_fingerprints(B64_256_1, sl, NULL, DSR_BASE64|DSR_DIGEST256); tt_int_op(smartlist_len(sl), ==, 1); test_mem_op_hex(smartlist_get(sl, 0), ==, HEX256_1); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); tor_free(mem_op_hex_tmp); } static void test_dir_measured_bw_kb(void) { measured_bw_line_t mbwl; int i; const char *lines_pass[] = { "node_id=$557365204145532d32353620696e73746561642e bw=1024\n", "node_id=$557365204145532d32353620696e73746561642e\t bw=1024 \n", " node_id=$557365204145532d32353620696e73746561642e bw=1024\n", "\tnoise\tnode_id=$557365204145532d32353620696e73746561642e " "bw=1024 junk=007\n", "misc=junk node_id=$557365204145532d32353620696e73746561642e " "bw=1024 junk=007\n", "end" }; const char *lines_fail[] = { /* Test possible python stupidity on input */ "node_id=None bw=1024\n", "node_id=$None bw=1024\n", "node_id=$557365204145532d32353620696e73746561642e bw=None\n", "node_id=$557365204145532d32353620696e73746561642e bw=1024.0\n", "node_id=$557365204145532d32353620696e73746561642e bw=.1024\n", "node_id=$557365204145532d32353620696e73746561642e bw=1.024\n", "node_id=$557365204145532d32353620696e73746561642e bw=1024 bw=0\n", "node_id=$557365204145532d32353620696e73746561642e bw=1024 bw=None\n", "node_id=$557365204145532d32353620696e73746561642e bw=-1024\n", /* Test incomplete writes due to race conditions, partial copies, etc */ "node_i", "node_i\n", "node_id=", "node_id=\n", "node_id=$557365204145532d32353620696e73746561642e bw=", "node_id=$557365204145532d32353620696e73746561642e bw=1024", "node_id=$557365204145532d32353620696e73746561642e bw=\n", "node_id=$557365204145532d32353620696e7374", "node_id=$557365204145532d32353620696e7374\n", "", "\n", " \n ", " \n\n", /* Test assorted noise */ " node_id= ", "node_id==$557365204145532d32353620696e73746561642e bw==1024\n", "node_id=$55736520414552d32353620696e73746561642e bw=1024\n", "node_id=557365204145532d32353620696e73746561642e bw=1024\n", "node_id= $557365204145532d32353620696e73746561642e bw=0.23\n", "end" }; for (i = 0; strcmp(lines_fail[i], "end"); i++) { //fprintf(stderr, "Testing: %s\n", lines_fail[i]); test_assert(measured_bw_line_parse(&mbwl, lines_fail[i]) == -1); } for (i = 0; strcmp(lines_pass[i], "end"); i++) { //fprintf(stderr, "Testing: %s %d\n", lines_pass[i], TOR_ISSPACE('\n')); test_assert(measured_bw_line_parse(&mbwl, lines_pass[i]) == 0); test_assert(mbwl.bw_kb == 1024); test_assert(strcmp(mbwl.node_hex, "557365204145532d32353620696e73746561642e") == 0); } done: return; } #define MBWC_INIT_TIME 1000 /** Do the measured bandwidth cache unit test */ static void test_dir_measured_bw_kb_cache(void) { /* Initial fake time_t for testing */ time_t curr = MBWC_INIT_TIME; /* Some measured_bw_line_ts */ measured_bw_line_t mbwl[3]; /* For receiving output on cache queries */ long bw; time_t as_of; /* First, clear the cache and assert that it's empty */ dirserv_clear_measured_bw_cache(); test_eq(dirserv_get_measured_bw_cache_size(), 0); /* * Set up test mbwls; none of the dirserv_cache_*() functions care about * the node_hex field. */ memset(mbwl[0].node_id, 0x01, DIGEST_LEN); mbwl[0].bw_kb = 20; memset(mbwl[1].node_id, 0x02, DIGEST_LEN); mbwl[1].bw_kb = 40; memset(mbwl[2].node_id, 0x03, DIGEST_LEN); mbwl[2].bw_kb = 80; /* Try caching something */ dirserv_cache_measured_bw(&(mbwl[0]), curr); test_eq(dirserv_get_measured_bw_cache_size(), 1); /* Okay, let's see if we can retrieve it */ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, &as_of)); test_eq(bw, 20); test_eq(as_of, MBWC_INIT_TIME); /* Try retrieving it without some outputs */ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL, NULL)); test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, NULL)); test_eq(bw, 20); test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL,&as_of)); test_eq(as_of, MBWC_INIT_TIME); /* Now expire it */ curr += MAX_MEASUREMENT_AGE + 1; dirserv_expire_measured_bw_cache(curr); /* Check that the cache is empty */ test_eq(dirserv_get_measured_bw_cache_size(), 0); /* Check that we can't retrieve it */ test_assert(!dirserv_query_measured_bw_cache_kb(mbwl[0].node_id, NULL,NULL)); /* Try caching a few things now */ dirserv_cache_measured_bw(&(mbwl[0]), curr); test_eq(dirserv_get_measured_bw_cache_size(), 1); curr += MAX_MEASUREMENT_AGE / 4; dirserv_cache_measured_bw(&(mbwl[1]), curr); test_eq(dirserv_get_measured_bw_cache_size(), 2); curr += MAX_MEASUREMENT_AGE / 4; dirserv_cache_measured_bw(&(mbwl[2]), curr); test_eq(dirserv_get_measured_bw_cache_size(), 3); curr += MAX_MEASUREMENT_AGE / 4 + 1; /* Do an expire that's too soon to get any of them */ dirserv_expire_measured_bw_cache(curr); test_eq(dirserv_get_measured_bw_cache_size(), 3); /* Push the oldest one off the cliff */ curr += MAX_MEASUREMENT_AGE / 4; dirserv_expire_measured_bw_cache(curr); test_eq(dirserv_get_measured_bw_cache_size(), 2); /* And another... */ curr += MAX_MEASUREMENT_AGE / 4; dirserv_expire_measured_bw_cache(curr); test_eq(dirserv_get_measured_bw_cache_size(), 1); /* This should empty it out again */ curr += MAX_MEASUREMENT_AGE / 4; dirserv_expire_measured_bw_cache(curr); test_eq(dirserv_get_measured_bw_cache_size(), 0); done: return; } static void test_dir_param_voting(void) { networkstatus_t vote1, vote2, vote3, vote4; smartlist_t *votes = smartlist_new(); char *res = NULL; /* dirvote_compute_params only looks at the net_params field of the votes, so that's all we need to set. */ memset(&vote1, 0, sizeof(vote1)); memset(&vote2, 0, sizeof(vote2)); memset(&vote3, 0, sizeof(vote3)); memset(&vote4, 0, sizeof(vote4)); vote1.net_params = smartlist_new(); vote2.net_params = smartlist_new(); vote3.net_params = smartlist_new(); vote4.net_params = smartlist_new(); smartlist_split_string(vote1.net_params, "ab=90 abcd=20 cw=50 x-yz=-99", NULL, 0, 0); smartlist_split_string(vote2.net_params, "ab=27 cw=5 x-yz=88", NULL, 0, 0); smartlist_split_string(vote3.net_params, "abcd=20 c=60 cw=500 x-yz=-9 zzzzz=101", NULL, 0, 0); smartlist_split_string(vote4.net_params, "ab=900 abcd=200 c=1 cw=51 x-yz=100", NULL, 0, 0); test_eq(100, networkstatus_get_param(&vote4, "x-yz", 50, 0, 300)); test_eq(222, networkstatus_get_param(&vote4, "foobar", 222, 0, 300)); test_eq(80, networkstatus_get_param(&vote4, "ab", 12, 0, 80)); test_eq(-8, networkstatus_get_param(&vote4, "ab", -12, -100, -8)); test_eq(0, networkstatus_get_param(&vote4, "foobar", 0, -100, 8)); smartlist_add(votes, &vote1); /* Do the first tests without adding all the other votes, for * networks without many dirauths. */ res = dirvote_compute_params(votes, 11, 6); test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-99"); tor_free(res); res = dirvote_compute_params(votes, 12, 2); test_streq(res, ""); tor_free(res); res = dirvote_compute_params(votes, 12, 1); test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-99"); tor_free(res); smartlist_add(votes, &vote2); res = dirvote_compute_params(votes, 11, 2); test_streq(res, "ab=27 abcd=20 cw=5 x-yz=-99"); tor_free(res); res = dirvote_compute_params(votes, 12, 2); test_streq(res, "ab=27 cw=5 x-yz=-99"); tor_free(res); res = dirvote_compute_params(votes, 12, 3); test_streq(res, "ab=27 cw=5 x-yz=-99"); tor_free(res); res = dirvote_compute_params(votes, 12, 6); test_streq(res, ""); tor_free(res); smartlist_add(votes, &vote3); res = dirvote_compute_params(votes, 11, 3); test_streq(res, "ab=27 abcd=20 c=60 cw=50 x-yz=-9 zzzzz=101"); tor_free(res); res = dirvote_compute_params(votes, 12, 3); test_streq(res, "ab=27 abcd=20 cw=50 x-yz=-9"); tor_free(res); res = dirvote_compute_params(votes, 12, 5); test_streq(res, "cw=50 x-yz=-9"); tor_free(res); res = dirvote_compute_params(votes, 12, 9); test_streq(res, "cw=50 x-yz=-9"); tor_free(res); smartlist_add(votes, &vote4); res = dirvote_compute_params(votes, 11, 4); test_streq(res, "ab=90 abcd=20 c=1 cw=50 x-yz=-9 zzzzz=101"); tor_free(res); res = dirvote_compute_params(votes, 12, 4); test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9"); tor_free(res); res = dirvote_compute_params(votes, 12, 5); test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9"); tor_free(res); /* Test that the special-cased "at least three dirauths voted for * this param" logic works as expected. */ res = dirvote_compute_params(votes, 12, 6); test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9"); tor_free(res); res = dirvote_compute_params(votes, 12, 10); test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9"); tor_free(res); done: tor_free(res); SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(vote2.net_params, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(vote3.net_params, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(vote4.net_params, char *, cp, tor_free(cp)); smartlist_free(vote1.net_params); smartlist_free(vote2.net_params); smartlist_free(vote3.net_params); smartlist_free(vote4.net_params); smartlist_free(votes); return; } extern const char AUTHORITY_CERT_1[]; extern const char AUTHORITY_SIGNKEY_1[]; extern const char AUTHORITY_CERT_2[]; extern const char AUTHORITY_SIGNKEY_2[]; extern const char AUTHORITY_CERT_3[]; extern const char AUTHORITY_SIGNKEY_3[]; /** Helper: Test that two networkstatus_voter_info_t do in fact represent the * same voting authority, and that they do in fact have all the same * information. */ static void test_same_voter(networkstatus_voter_info_t *v1, networkstatus_voter_info_t *v2) { test_streq(v1->nickname, v2->nickname); test_memeq(v1->identity_digest, v2->identity_digest, DIGEST_LEN); test_streq(v1->address, v2->address); test_eq(v1->addr, v2->addr); test_eq(v1->dir_port, v2->dir_port); test_eq(v1->or_port, v2->or_port); test_streq(v1->contact, v2->contact); test_memeq(v1->vote_digest, v2->vote_digest, DIGEST_LEN); done: ; } /** Helper: Make a new routerinfo containing the right information for a * given vote_routerstatus_t. */ static routerinfo_t * generate_ri_from_rs(const vote_routerstatus_t *vrs) { routerinfo_t *r; const routerstatus_t *rs = &vrs->status; static time_t published = 0; r = tor_malloc_zero(sizeof(routerinfo_t)); memcpy(r->cache_info.identity_digest, rs->identity_digest, DIGEST_LEN); memcpy(r->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN); r->cache_info.do_not_cache = 1; r->cache_info.routerlist_index = -1; r->cache_info.signed_descriptor_body = tor_strdup("123456789012345678901234567890123"); r->cache_info.signed_descriptor_len = strlen(r->cache_info.signed_descriptor_body); r->exit_policy = smartlist_new(); r->cache_info.published_on = ++published + time(NULL); if (rs->has_bandwidth) { /* * Multiply by 1000 because the routerinfo_t and the routerstatus_t * seem to use different units (*sigh*) and because we seem stuck on * icky and perverse decimal kilobytes (*double sigh*) - see * router_get_advertised_bandwidth_capped() of routerlist.c and * routerstatus_format_entry() of dirserv.c. */ r->bandwidthrate = rs->bandwidth_kb * 1000; r->bandwidthcapacity = rs->bandwidth_kb * 1000; } return r; } /** Helper: get a detached signatures document for one or two * consensuses. */ static char * get_detached_sigs(networkstatus_t *ns, networkstatus_t *ns2) { char *r; smartlist_t *sl; tor_assert(ns && ns->flavor == FLAV_NS); sl = smartlist_new(); smartlist_add(sl,ns); if (ns2) smartlist_add(sl,ns2); r = networkstatus_get_detached_signatures(sl); smartlist_free(sl); return r; } /** * Generate a routerstatus for v3_networkstatus test */ static vote_routerstatus_t * gen_routerstatus_for_v3ns(int idx, time_t now) { vote_routerstatus_t *vrs=NULL; routerstatus_t *rs; tor_addr_t addr_ipv6; switch (idx) { case 0: /* Generate the first routerstatus. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.2.14"); rs->published_on = now-1500; strlcpy(rs->nickname, "router2", sizeof(rs->nickname)); memset(rs->identity_digest, 3, DIGEST_LEN); memset(rs->descriptor_digest, 78, DIGEST_LEN); rs->addr = 0x99008801; rs->or_port = 443; rs->dir_port = 8000; /* all flags but running cleared */ rs->is_flagged_running = 1; break; case 1: /* Generate the second routerstatus. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.2.0.5"); rs->published_on = now-1000; strlcpy(rs->nickname, "router1", sizeof(rs->nickname)); memset(rs->identity_digest, 5, DIGEST_LEN); memset(rs->descriptor_digest, 77, DIGEST_LEN); rs->addr = 0x99009901; rs->or_port = 443; rs->dir_port = 0; tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); tor_addr_copy(&rs->ipv6_addr, &addr_ipv6); rs->ipv6_orport = 4711; rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1; break; case 2: /* Generate the third routerstatus. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.0.3"); rs->published_on = now-1000; strlcpy(rs->nickname, "router3", sizeof(rs->nickname)); memset(rs->identity_digest, 33, DIGEST_LEN); memset(rs->descriptor_digest, 79, DIGEST_LEN); rs->addr = 0xAA009901; rs->or_port = 400; rs->dir_port = 9999; rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1; break; case 3: /* Generate a fourth routerstatus that is not running. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.6.3"); rs->published_on = now-1000; strlcpy(rs->nickname, "router4", sizeof(rs->nickname)); memset(rs->identity_digest, 34, DIGEST_LEN); memset(rs->descriptor_digest, 47, DIGEST_LEN); rs->addr = 0xC0000203; rs->or_port = 500; rs->dir_port = 1999; /* Running flag (and others) cleared */ break; case 4: /* No more for this test; return NULL */ vrs = NULL; break; default: /* Shouldn't happen */ test_assert(0); } if (vrs) { vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t)); tor_asprintf(&vrs->microdesc->microdesc_hash_line, "m 9,10,11,12,13,14,15,16,17 " "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n", idx); } done: return vrs; } /** Apply tweaks to the vote list for each voter */ static int vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now) { vote_routerstatus_t *vrs; const char *msg = NULL; test_assert(v); (void)now; if (voter == 1) { measured_bw_line_t mbw; memset(mbw.node_id, 33, sizeof(mbw.node_id)); mbw.bw_kb = 1024; test_assert(measured_bw_line_apply(&mbw, v->routerstatus_list) == 1); } else if (voter == 2 || voter == 3) { /* Monkey around with the list a bit */ vrs = smartlist_get(v->routerstatus_list, 2); smartlist_del_keeporder(v->routerstatus_list, 2); tor_free(vrs->version); tor_free(vrs); vrs = smartlist_get(v->routerstatus_list, 0); vrs->status.is_fast = 1; if (voter == 3) { vrs = smartlist_get(v->routerstatus_list, 0); smartlist_del_keeporder(v->routerstatus_list, 0); tor_free(vrs->version); tor_free(vrs); vrs = smartlist_get(v->routerstatus_list, 0); memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN); test_assert(router_add_to_routerlist( generate_ri_from_rs(vrs), &msg,0,0) >= 0); } } done: return 0; } /** * Test a parsed vote_routerstatus_t for v3_networkstatus test */ static void test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now) { routerstatus_t *rs; tor_addr_t addr_ipv6; test_assert(vrs); rs = &(vrs->status); test_assert(rs); /* Split out by digests to test */ if (tor_memeq(rs->identity_digest, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" "\x3\x3\x3\x3", DIGEST_LEN) && (voter == 1)) { /* Check the first routerstatus. */ test_streq(vrs->version, "0.1.2.14"); test_eq(rs->published_on, now-1500); test_streq(rs->nickname, "router2"); test_memeq(rs->identity_digest, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" "\x3\x3\x3\x3", DIGEST_LEN); test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); test_eq(rs->addr, 0x99008801); test_eq(rs->or_port, 443); test_eq(rs->dir_port, 8000); test_eq(vrs->flags, U64_LITERAL(16)); // no flags except "running" } else if (tor_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" "\x5\x5\x5\x5", DIGEST_LEN) && (voter == 1 || voter == 2)) { test_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" "\x5\x5\x5\x5", DIGEST_LEN); if (voter == 1) { /* Check the second routerstatus. */ test_streq(vrs->version, "0.2.0.5"); test_eq(rs->published_on, now-1000); test_streq(rs->nickname, "router1"); } test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); test_eq(rs->addr, 0x99009901); test_eq(rs->or_port, 443); test_eq(rs->dir_port, 0); tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); test_eq(rs->ipv6_orport, 4711); if (voter == 1) { test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority." } else { /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */ test_eq(vrs->flags, U64_LITERAL(974)); } } else if (tor_memeq(rs->identity_digest, "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33" "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33", DIGEST_LEN) && (voter == 1 || voter == 2)) { /* Check the measured bandwidth bits */ test_assert(vrs->has_measured_bw && vrs->measured_bw_kb == 1024); } else { /* * Didn't expect this, but the old unit test only checked some of them, * so don't assert. */ /* test_assert(0); */ } done: return; } /** * Test a consensus for v3_networkstatus_test */ static void test_consensus_for_v3ns(networkstatus_t *con, time_t now) { (void)now; test_assert(con); test_assert(!con->cert); test_eq(2, smartlist_len(con->routerstatus_list)); /* There should be two listed routers: one with identity 3, one with * identity 5. */ done: return; } /** * Test a router list entry for v3_networkstatus test */ static void test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now) { tor_addr_t addr_ipv6; test_assert(rs); /* There should be two listed routers: one with identity 3, one with * identity 5. */ /* This one showed up in 2 digests. */ if (tor_memeq(rs->identity_digest, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" "\x3\x3", DIGEST_LEN)) { test_memeq(rs->identity_digest, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", DIGEST_LEN); test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); test_assert(!rs->is_authority); test_assert(!rs->is_exit); test_assert(!rs->is_fast); test_assert(!rs->is_possible_guard); test_assert(!rs->is_stable); /* (If it wasn't running it wouldn't be here) */ test_assert(rs->is_flagged_running); test_assert(!rs->is_v2_dir); test_assert(!rs->is_valid); test_assert(!rs->is_named); /* XXXX check version */ } else if (tor_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" "\x5\x5\x5\x5", DIGEST_LEN)) { /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */ test_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", DIGEST_LEN); test_streq(rs->nickname, "router1"); test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); test_eq(rs->published_on, now-1000); test_eq(rs->addr, 0x99009901); test_eq(rs->or_port, 443); test_eq(rs->dir_port, 0); tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); test_eq(rs->ipv6_orport, 4711); test_assert(!rs->is_authority); test_assert(rs->is_exit); test_assert(rs->is_fast); test_assert(rs->is_possible_guard); test_assert(rs->is_stable); test_assert(rs->is_flagged_running); test_assert(rs->is_v2_dir); test_assert(rs->is_valid); test_assert(!rs->is_named); /* XXXX check version */ } else { /* Weren't expecting this... */ test_assert(0); } done: return; } /** Run a unit tests for generating and parsing networkstatuses, with * the supply test fns. */ static void test_a_networkstatus( vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), int (*vote_tweaks)(networkstatus_t *v, int voter, time_t now), void (*vrs_test)(vote_routerstatus_t *vrs, int voter, time_t now), void (*consensus_test)(networkstatus_t *con, time_t now), void (*rs_test)(routerstatus_t *rs, time_t now)) { authority_cert_t *cert1=NULL, *cert2=NULL, *cert3=NULL; crypto_pk_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL; crypto_pk_t *sign_skey_leg1=NULL; const char *msg=NULL; /* * Sum the non-zero returns from vote_tweaks() we've seen; if vote_tweaks() * returns non-zero, it changed net_params and we should skip the tests for * that later as they will fail. */ int params_tweaked = 0; time_t now = time(NULL); networkstatus_voter_info_t *voter; document_signature_t *sig; networkstatus_t *vote=NULL, *v1=NULL, *v2=NULL, *v3=NULL, *con=NULL, *con_md=NULL; vote_routerstatus_t *vrs; routerstatus_t *rs; int idx, n_rs, n_vrs; char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, *cp; smartlist_t *votes = smartlist_new(); /* For generating the two other consensuses. */ char *detached_text1=NULL, *detached_text2=NULL; char *consensus_text2=NULL, *consensus_text3=NULL; char *consensus_text_md2=NULL, *consensus_text_md3=NULL; char *consensus_text_md=NULL; networkstatus_t *con2=NULL, *con_md2=NULL, *con3=NULL, *con_md3=NULL; ns_detached_signatures_t *dsig1=NULL, *dsig2=NULL; test_assert(vrs_gen); test_assert(rs_test); test_assert(vrs_test); /* Parse certificates and keys. */ cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL); test_assert(cert1); test_assert(cert1->is_cross_certified); cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL); test_assert(cert2); cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL); test_assert(cert3); sign_skey_1 = crypto_pk_new(); sign_skey_2 = crypto_pk_new(); sign_skey_3 = crypto_pk_new(); sign_skey_leg1 = pk_generate(4); test_assert(!crypto_pk_read_private_key_from_string(sign_skey_1, AUTHORITY_SIGNKEY_1, -1)); test_assert(!crypto_pk_read_private_key_from_string(sign_skey_2, AUTHORITY_SIGNKEY_2, -1)); test_assert(!crypto_pk_read_private_key_from_string(sign_skey_3, AUTHORITY_SIGNKEY_3, -1)); test_assert(!crypto_pk_cmp_keys(sign_skey_1, cert1->signing_key)); test_assert(!crypto_pk_cmp_keys(sign_skey_2, cert2->signing_key)); /* * Set up a vote; generate it; try to parse it. */ vote = tor_malloc_zero(sizeof(networkstatus_t)); vote->type = NS_TYPE_VOTE; vote->published = now; vote->valid_after = now+1000; vote->fresh_until = now+2000; vote->valid_until = now+3000; vote->vote_seconds = 100; vote->dist_seconds = 200; vote->supported_methods = smartlist_new(); smartlist_split_string(vote->supported_methods, "1 2 3", NULL, 0, -1); vote->client_versions = tor_strdup("0.1.2.14,0.1.2.15"); vote->server_versions = tor_strdup("0.1.2.14,0.1.2.15,0.1.2.16"); vote->known_flags = smartlist_new(); smartlist_split_string(vote->known_flags, "Authority Exit Fast Guard Running Stable V2Dir Valid", 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); vote->voters = smartlist_new(); voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); voter->nickname = tor_strdup("Voter1"); voter->address = tor_strdup("1.2.3.4"); voter->addr = 0x01020304; voter->dir_port = 80; voter->or_port = 9000; voter->contact = tor_strdup("voter@example.com"); crypto_pk_get_digest(cert1->identity_key, voter->identity_digest); smartlist_add(vote->voters, voter); vote->cert = authority_cert_dup(cert1); vote->net_params = smartlist_new(); smartlist_split_string(vote->net_params, "circuitwindow=101 foo=990", NULL, 0, 0); vote->routerstatus_list = smartlist_new(); /* add routerstatuses */ idx = 0; do { vrs = vrs_gen(idx, now); if (vrs) { smartlist_add(vote->routerstatus_list, vrs); test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0); ++idx; } } while (vrs); n_vrs = idx; /* dump the vote and try to parse it. */ v1_text = format_networkstatus_vote(sign_skey_1, vote); test_assert(v1_text); v1 = networkstatus_parse_vote_from_string(v1_text, NULL, NS_TYPE_VOTE); test_assert(v1); /* Make sure the parsed thing was right. */ test_eq(v1->type, NS_TYPE_VOTE); test_eq(v1->published, vote->published); test_eq(v1->valid_after, vote->valid_after); test_eq(v1->fresh_until, vote->fresh_until); test_eq(v1->valid_until, vote->valid_until); test_eq(v1->vote_seconds, vote->vote_seconds); test_eq(v1->dist_seconds, vote->dist_seconds); test_streq(v1->client_versions, vote->client_versions); test_streq(v1->server_versions, vote->server_versions); test_assert(v1->voters && smartlist_len(v1->voters)); voter = smartlist_get(v1->voters, 0); test_streq(voter->nickname, "Voter1"); test_streq(voter->address, "1.2.3.4"); test_eq(voter->addr, 0x01020304); test_eq(voter->dir_port, 80); test_eq(voter->or_port, 9000); test_streq(voter->contact, "voter@example.com"); test_assert(v1->cert); test_assert(!crypto_pk_cmp_keys(sign_skey_1, v1->cert->signing_key)); cp = smartlist_join_strings(v1->known_flags, ":", 0, NULL); test_streq(cp, "Authority:Exit:Fast:Guard:Running:Stable:V2Dir:Valid"); tor_free(cp); test_eq(smartlist_len(v1->routerstatus_list), n_vrs); if (vote_tweaks) params_tweaked += vote_tweaks(v1, 1, now); /* Check the routerstatuses. */ for (idx = 0; idx < n_vrs; ++idx) { vrs = smartlist_get(v1->routerstatus_list, idx); test_assert(vrs); vrs_test(vrs, 1, now); } /* Generate second vote. It disagrees on some of the times, * and doesn't list versions, and knows some crazy flags */ vote->published = now+1; vote->fresh_until = now+3005; vote->dist_seconds = 300; authority_cert_free(vote->cert); vote->cert = authority_cert_dup(cert2); vote->net_params = smartlist_new(); smartlist_split_string(vote->net_params, "bar=2000000000 circuitwindow=20", NULL, 0, 0); tor_free(vote->client_versions); tor_free(vote->server_versions); voter = smartlist_get(vote->voters, 0); tor_free(voter->nickname); tor_free(voter->address); voter->nickname = tor_strdup("Voter2"); voter->address = tor_strdup("2.3.4.5"); voter->addr = 0x02030405; crypto_pk_get_digest(cert2->identity_key, voter->identity_digest); smartlist_add(vote->known_flags, tor_strdup("MadeOfCheese")); smartlist_add(vote->known_flags, tor_strdup("MadeOfTin")); smartlist_sort_strings(vote->known_flags); /* generate and parse v2. */ v2_text = format_networkstatus_vote(sign_skey_2, vote); test_assert(v2_text); v2 = networkstatus_parse_vote_from_string(v2_text, NULL, NS_TYPE_VOTE); test_assert(v2); if (vote_tweaks) params_tweaked += vote_tweaks(v2, 2, now); /* Check that flags come out right.*/ cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL); test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:" "Running:Stable:V2Dir:Valid"); tor_free(cp); /* Check the routerstatuses. */ n_vrs = smartlist_len(v2->routerstatus_list); for (idx = 0; idx < n_vrs; ++idx) { vrs = smartlist_get(v2->routerstatus_list, idx); test_assert(vrs); vrs_test(vrs, 2, now); } /* Generate the third vote. */ vote->published = now; vote->fresh_until = now+2003; vote->dist_seconds = 250; authority_cert_free(vote->cert); vote->cert = authority_cert_dup(cert3); vote->net_params = smartlist_new(); smartlist_split_string(vote->net_params, "circuitwindow=80 foo=660", NULL, 0, 0); smartlist_add(vote->supported_methods, tor_strdup("4")); vote->client_versions = tor_strdup("0.1.2.14,0.1.2.17"); vote->server_versions = tor_strdup("0.1.2.10,0.1.2.15,0.1.2.16"); voter = smartlist_get(vote->voters, 0); tor_free(voter->nickname); tor_free(voter->address); voter->nickname = tor_strdup("Voter3"); voter->address = tor_strdup("3.4.5.6"); voter->addr = 0x03040506; crypto_pk_get_digest(cert3->identity_key, voter->identity_digest); /* This one has a legacy id. */ memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN); v3_text = format_networkstatus_vote(sign_skey_3, vote); test_assert(v3_text); v3 = networkstatus_parse_vote_from_string(v3_text, NULL, NS_TYPE_VOTE); test_assert(v3); if (vote_tweaks) params_tweaked += vote_tweaks(v3, 3, now); /* Compute a consensus as voter 3. */ smartlist_add(votes, v3); smartlist_add(votes, v1); smartlist_add(votes, v2); consensus_text = networkstatus_compute_consensus(votes, 3, cert3->identity_key, sign_skey_3, "AAAAAAAAAAAAAAAAAAAA", sign_skey_leg1, FLAV_NS); test_assert(consensus_text); con = networkstatus_parse_vote_from_string(consensus_text, NULL, NS_TYPE_CONSENSUS); test_assert(con); //log_notice(LD_GENERAL, "<<%s>>\n<<%s>>\n<<%s>>\n", // v1_text, v2_text, v3_text); consensus_text_md = networkstatus_compute_consensus(votes, 3, cert3->identity_key, sign_skey_3, "AAAAAAAAAAAAAAAAAAAA", sign_skey_leg1, FLAV_MICRODESC); test_assert(consensus_text_md); con_md = networkstatus_parse_vote_from_string(consensus_text_md, NULL, NS_TYPE_CONSENSUS); test_assert(con_md); test_eq(con_md->flavor, FLAV_MICRODESC); /* Check consensus contents. */ test_assert(con->type == NS_TYPE_CONSENSUS); test_eq(con->published, 0); /* this field only appears in votes. */ test_eq(con->valid_after, now+1000); test_eq(con->fresh_until, now+2003); /* median */ test_eq(con->valid_until, now+3000); test_eq(con->vote_seconds, 100); test_eq(con->dist_seconds, 250); /* median */ test_streq(con->client_versions, "0.1.2.14"); test_streq(con->server_versions, "0.1.2.15,0.1.2.16"); cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL); test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:" "Running:Stable:V2Dir:Valid"); tor_free(cp); if (!params_tweaked) { /* Skip this one if vote_tweaks() messed with the param lists */ cp = smartlist_join_strings(con->net_params, ":", 0, NULL); test_streq(cp, "circuitwindow=80:foo=660"); tor_free(cp); } test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/ /* The voter id digests should be in this order. */ test_assert(memcmp(cert2->cache_info.identity_digest, cert1->cache_info.identity_digest,DIGEST_LEN)<0); test_assert(memcmp(cert1->cache_info.identity_digest, cert3->cache_info.identity_digest,DIGEST_LEN)<0); test_same_voter(smartlist_get(con->voters, 1), smartlist_get(v2->voters, 0)); test_same_voter(smartlist_get(con->voters, 2), smartlist_get(v1->voters, 0)); test_same_voter(smartlist_get(con->voters, 3), smartlist_get(v3->voters, 0)); consensus_test(con, now); /* Check the routerstatuses. */ n_rs = smartlist_len(con->routerstatus_list); for (idx = 0; idx < n_rs; ++idx) { rs = smartlist_get(con->routerstatus_list, idx); test_assert(rs); rs_test(rs, now); } /* Check signatures. the first voter is a pseudo-entry with a legacy key. * The second one hasn't signed. The fourth one has signed: validate it. */ voter = smartlist_get(con->voters, 1); test_eq(smartlist_len(voter->sigs), 0); voter = smartlist_get(con->voters, 3); test_eq(smartlist_len(voter->sigs), 1); sig = smartlist_get(voter->sigs, 0); test_assert(sig->signature); test_assert(!sig->good_signature); test_assert(!sig->bad_signature); test_assert(!networkstatus_check_document_signature(con, sig, cert3)); test_assert(sig->signature); test_assert(sig->good_signature); test_assert(!sig->bad_signature); { const char *msg=NULL; /* Compute the other two signed consensuses. */ smartlist_shuffle(votes); consensus_text2 = networkstatus_compute_consensus(votes, 3, cert2->identity_key, sign_skey_2, NULL,NULL, FLAV_NS); consensus_text_md2 = networkstatus_compute_consensus(votes, 3, cert2->identity_key, sign_skey_2, NULL,NULL, FLAV_MICRODESC); smartlist_shuffle(votes); consensus_text3 = networkstatus_compute_consensus(votes, 3, cert1->identity_key, sign_skey_1, NULL,NULL, FLAV_NS); consensus_text_md3 = networkstatus_compute_consensus(votes, 3, cert1->identity_key, sign_skey_1, NULL,NULL, FLAV_MICRODESC); test_assert(consensus_text2); test_assert(consensus_text3); test_assert(consensus_text_md2); test_assert(consensus_text_md3); con2 = networkstatus_parse_vote_from_string(consensus_text2, NULL, NS_TYPE_CONSENSUS); con3 = networkstatus_parse_vote_from_string(consensus_text3, NULL, NS_TYPE_CONSENSUS); con_md2 = networkstatus_parse_vote_from_string(consensus_text_md2, NULL, NS_TYPE_CONSENSUS); con_md3 = networkstatus_parse_vote_from_string(consensus_text_md3, NULL, NS_TYPE_CONSENSUS); test_assert(con2); test_assert(con3); test_assert(con_md2); test_assert(con_md3); /* All three should have the same digest. */ test_memeq(&con->digests, &con2->digests, sizeof(digests_t)); test_memeq(&con->digests, &con3->digests, sizeof(digests_t)); test_memeq(&con_md->digests, &con_md2->digests, sizeof(digests_t)); test_memeq(&con_md->digests, &con_md3->digests, sizeof(digests_t)); /* Extract a detached signature from con3. */ detached_text1 = get_detached_sigs(con3, con_md3); tt_assert(detached_text1); /* Try to parse it. */ dsig1 = networkstatus_parse_detached_signatures(detached_text1, NULL); tt_assert(dsig1); /* Are parsed values as expected? */ test_eq(dsig1->valid_after, con3->valid_after); test_eq(dsig1->fresh_until, con3->fresh_until); test_eq(dsig1->valid_until, con3->valid_until); { digests_t *dsig_digests = strmap_get(dsig1->digests, "ns"); test_assert(dsig_digests); test_memeq(dsig_digests->d[DIGEST_SHA1], con3->digests.d[DIGEST_SHA1], DIGEST_LEN); dsig_digests = strmap_get(dsig1->digests, "microdesc"); test_assert(dsig_digests); test_memeq(dsig_digests->d[DIGEST_SHA256], con_md3->digests.d[DIGEST_SHA256], DIGEST256_LEN); } { smartlist_t *dsig_signatures = strmap_get(dsig1->signatures, "ns"); test_assert(dsig_signatures); test_eq(1, smartlist_len(dsig_signatures)); sig = smartlist_get(dsig_signatures, 0); test_memeq(sig->identity_digest, cert1->cache_info.identity_digest, DIGEST_LEN); test_eq(sig->alg, DIGEST_SHA1); dsig_signatures = strmap_get(dsig1->signatures, "microdesc"); test_assert(dsig_signatures); test_eq(1, smartlist_len(dsig_signatures)); sig = smartlist_get(dsig_signatures, 0); test_memeq(sig->identity_digest, cert1->cache_info.identity_digest, DIGEST_LEN); test_eq(sig->alg, DIGEST_SHA256); } /* Try adding it to con2. */ detached_text2 = get_detached_sigs(con2,con_md2); test_eq(1, networkstatus_add_detached_signatures(con2, dsig1, "test", LOG_INFO, &msg)); tor_free(detached_text2); test_eq(1, networkstatus_add_detached_signatures(con_md2, dsig1, "test", LOG_INFO, &msg)); tor_free(detached_text2); detached_text2 = get_detached_sigs(con2,con_md2); //printf("\n<%s>\n", detached_text2); dsig2 = networkstatus_parse_detached_signatures(detached_text2, NULL); test_assert(dsig2); /* printf("\n"); SMARTLIST_FOREACH(dsig2->signatures, networkstatus_voter_info_t *, vi, { char hd[64]; base16_encode(hd, sizeof(hd), vi->identity_digest, DIGEST_LEN); printf("%s\n", hd); }); */ test_eq(2, smartlist_len((smartlist_t*)strmap_get(dsig2->signatures, "ns"))); test_eq(2, smartlist_len((smartlist_t*)strmap_get(dsig2->signatures, "microdesc"))); /* Try adding to con2 twice; verify that nothing changes. */ test_eq(0, networkstatus_add_detached_signatures(con2, dsig1, "test", LOG_INFO, &msg)); /* Add to con. */ test_eq(2, networkstatus_add_detached_signatures(con, dsig2, "test", LOG_INFO, &msg)); /* Check signatures */ voter = smartlist_get(con->voters, 1); sig = smartlist_get(voter->sigs, 0); test_assert(sig); test_assert(!networkstatus_check_document_signature(con, sig, cert2)); voter = smartlist_get(con->voters, 2); sig = smartlist_get(voter->sigs, 0); test_assert(sig); test_assert(!networkstatus_check_document_signature(con, sig, cert1)); } done: smartlist_free(votes); tor_free(v1_text); tor_free(v2_text); tor_free(v3_text); tor_free(consensus_text); tor_free(consensus_text_md); if (vote) networkstatus_vote_free(vote); if (v1) networkstatus_vote_free(v1); if (v2) networkstatus_vote_free(v2); if (v3) networkstatus_vote_free(v3); if (con) networkstatus_vote_free(con); if (con_md) networkstatus_vote_free(con_md); if (sign_skey_1) crypto_pk_free(sign_skey_1); if (sign_skey_2) crypto_pk_free(sign_skey_2); if (sign_skey_3) crypto_pk_free(sign_skey_3); if (sign_skey_leg1) crypto_pk_free(sign_skey_leg1); if (cert1) authority_cert_free(cert1); if (cert2) authority_cert_free(cert2); if (cert3) authority_cert_free(cert3); tor_free(consensus_text2); tor_free(consensus_text3); tor_free(consensus_text_md2); tor_free(consensus_text_md3); tor_free(detached_text1); tor_free(detached_text2); if (con2) networkstatus_vote_free(con2); if (con3) networkstatus_vote_free(con3); if (con_md2) networkstatus_vote_free(con_md2); if (con_md3) networkstatus_vote_free(con_md3); if (dsig1) ns_detached_signatures_free(dsig1); if (dsig2) ns_detached_signatures_free(dsig2); } /** Run unit tests for generating and parsing V3 consensus networkstatus * documents. */ static void test_dir_v3_networkstatus(void) { test_a_networkstatus(gen_routerstatus_for_v3ns, vote_tweaks_for_v3ns, test_vrs_for_v3ns, test_consensus_for_v3ns, test_routerstatus_for_v3ns); } static void test_dir_scale_bw(void *testdata) { double v[8] = { 2.0/3, 7.0, 1.0, 3.0, 1.0/5, 1.0/7, 12.0, 24.0 }; u64_dbl_t vals[8]; uint64_t total; int i; (void) testdata; for (i=0; i<8; ++i) vals[i].dbl = v[i]; scale_array_elements_to_u64(vals, 8, &total); tt_int_op((int)total, ==, 48); total = 0; for (i=0; i<8; ++i) { total += vals[i].u64; } tt_assert(total >= (U64_LITERAL(1)<<60)); tt_assert(total <= (U64_LITERAL(1)<<62)); for (i=0; i<8; ++i) { double ratio = ((double)vals[i].u64) / vals[2].u64; tt_double_op(fabs(ratio - v[i]), <, .00001); } done: ; } static void test_dir_random_weighted(void *testdata) { int histogram[10]; uint64_t vals[10] = {3,1,2,4,6,0,7,5,8,9}, total=0; u64_dbl_t inp[10]; int i, choice; const int n = 50000; double max_sq_error; (void) testdata; /* Try a ten-element array with values from 0 through 10. The values are * in a scrambled order to make sure we don't depend on order. */ memset(histogram,0,sizeof(histogram)); for (i=0; i<10; ++i) { inp[i].u64 = vals[i]; total += vals[i]; } tt_int_op(total, ==, 45); for (i=0; i=, 0); tt_int_op(choice, <, 10); histogram[choice]++; } /* Now see if we chose things about frequently enough. */ max_sq_error = 0; for (i=0; i<10; ++i) { int expected = (int)(n*vals[i]/total); double frac_diff = 0, sq; TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected)); if (expected) frac_diff = (histogram[i] - expected) / ((double)expected); else tt_int_op(histogram[i], ==, 0); sq = frac_diff * frac_diff; if (sq > max_sq_error) max_sq_error = sq; } /* It should almost always be much much less than this. If you want to * figure out the odds, please feel free. */ tt_double_op(max_sq_error, <, .05); /* Now try a singleton; do we choose it? */ for (i = 0; i < 100; ++i) { choice = choose_array_element_by_weight(inp, 1); tt_int_op(choice, ==, 0); } /* Now try an array of zeros. We should choose randomly. */ memset(histogram,0,sizeof(histogram)); for (i = 0; i < 5; ++i) inp[i].u64 = 0; for (i = 0; i < n; ++i) { choice = choose_array_element_by_weight(inp, 5); tt_int_op(choice, >=, 0); tt_int_op(choice, <, 5); histogram[choice]++; } /* Now see if we chose things about frequently enough. */ max_sq_error = 0; for (i=0; i<5; ++i) { int expected = n/5; double frac_diff = 0, sq; TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected)); frac_diff = (histogram[i] - expected) / ((double)expected); sq = frac_diff * frac_diff; if (sq > max_sq_error) max_sq_error = sq; } /* It should almost always be much much less than this. If you want to * figure out the odds, please feel free. */ tt_double_op(max_sq_error, <, .05); done: ; } /* Function pointers for test_dir_clip_unmeasured_bw_kb() */ static uint32_t alternate_clip_bw = 0; /** * Generate a routerstatus for clip_unmeasured_bw_kb test; based on the * v3_networkstatus ones. */ static vote_routerstatus_t * gen_routerstatus_for_umbw(int idx, time_t now) { vote_routerstatus_t *vrs = NULL; routerstatus_t *rs; tor_addr_t addr_ipv6; uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ? alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB; switch (idx) { case 0: /* Generate the first routerstatus. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.2.14"); rs->published_on = now-1500; strlcpy(rs->nickname, "router2", sizeof(rs->nickname)); memset(rs->identity_digest, 3, DIGEST_LEN); memset(rs->descriptor_digest, 78, DIGEST_LEN); rs->addr = 0x99008801; rs->or_port = 443; rs->dir_port = 8000; /* all flags but running cleared */ rs->is_flagged_running = 1; /* * This one has measured bandwidth below the clip cutoff, and * so shouldn't be clipped; we'll have to test that it isn't * later. */ vrs->has_measured_bw = 1; rs->has_bandwidth = 1; vrs->measured_bw_kb = rs->bandwidth_kb = max_unmeasured_bw_kb / 2; break; case 1: /* Generate the second routerstatus. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.2.0.5"); rs->published_on = now-1000; strlcpy(rs->nickname, "router1", sizeof(rs->nickname)); memset(rs->identity_digest, 5, DIGEST_LEN); memset(rs->descriptor_digest, 77, DIGEST_LEN); rs->addr = 0x99009901; rs->or_port = 443; rs->dir_port = 0; tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); tor_addr_copy(&rs->ipv6_addr, &addr_ipv6); rs->ipv6_orport = 4711; rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1; /* * This one has measured bandwidth above the clip cutoff, and * so shouldn't be clipped; we'll have to test that it isn't * later. */ vrs->has_measured_bw = 1; rs->has_bandwidth = 1; vrs->measured_bw_kb = rs->bandwidth_kb = 2 * max_unmeasured_bw_kb; break; case 2: /* Generate the third routerstatus. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.0.3"); rs->published_on = now-1000; strlcpy(rs->nickname, "router3", sizeof(rs->nickname)); memset(rs->identity_digest, 0x33, DIGEST_LEN); memset(rs->descriptor_digest, 79, DIGEST_LEN); rs->addr = 0xAA009901; rs->or_port = 400; rs->dir_port = 9999; rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1; /* * This one has unmeasured bandwidth above the clip cutoff, and * so should be clipped; we'll have to test that it isn't * later. */ vrs->has_measured_bw = 0; rs->has_bandwidth = 1; vrs->measured_bw_kb = 0; rs->bandwidth_kb = 2 * max_unmeasured_bw_kb; break; case 3: /* Generate a fourth routerstatus that is not running. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; vrs->version = tor_strdup("0.1.6.3"); rs->published_on = now-1000; strlcpy(rs->nickname, "router4", sizeof(rs->nickname)); memset(rs->identity_digest, 0x34, DIGEST_LEN); memset(rs->descriptor_digest, 47, DIGEST_LEN); rs->addr = 0xC0000203; rs->or_port = 500; rs->dir_port = 1999; /* all flags but running cleared */ rs->is_flagged_running = 1; /* * This one has unmeasured bandwidth below the clip cutoff, and * so shouldn't be clipped; we'll have to test that it isn't * later. */ vrs->has_measured_bw = 0; rs->has_bandwidth = 1; vrs->measured_bw_kb = 0; rs->bandwidth_kb = max_unmeasured_bw_kb / 2; break; case 4: /* No more for this test; return NULL */ vrs = NULL; break; default: /* Shouldn't happen */ test_assert(0); } if (vrs) { vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t)); tor_asprintf(&vrs->microdesc->microdesc_hash_line, "m 9,10,11,12,13,14,15,16,17 " "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n", idx); } done: return vrs; } /** Apply tweaks to the vote list for each voter; for the umbw test this is * just adding the right consensus methods to let clipping happen */ static int vote_tweaks_for_umbw(networkstatus_t *v, int voter, time_t now) { char *maxbw_param = NULL; int rv = 0; test_assert(v); (void)voter; (void)now; test_assert(v->supported_methods); smartlist_clear(v->supported_methods); /* Method 17 is MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB */ smartlist_split_string(v->supported_methods, "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17", NULL, 0, -1); /* If we're using a non-default clip bandwidth, add it to net_params */ if (alternate_clip_bw > 0) { tor_asprintf(&maxbw_param, "maxunmeasuredbw=%u", alternate_clip_bw); test_assert(maxbw_param); if (maxbw_param) { smartlist_add(v->net_params, maxbw_param); rv = 1; } } done: return rv; } /** * Test a parsed vote_routerstatus_t for umbw test. */ static void test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now) { routerstatus_t *rs; tor_addr_t addr_ipv6; uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ? alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB; (void)voter; test_assert(vrs); rs = &(vrs->status); test_assert(rs); /* Split out by digests to test */ if (tor_memeq(rs->identity_digest, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", DIGEST_LEN)) { /* * Check the first routerstatus - measured bandwidth below the clip * cutoff. */ test_streq(vrs->version, "0.1.2.14"); test_eq(rs->published_on, now-1500); test_streq(rs->nickname, "router2"); test_memeq(rs->identity_digest, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", DIGEST_LEN); test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); test_eq(rs->addr, 0x99008801); test_eq(rs->or_port, 443); test_eq(rs->dir_port, 8000); test_assert(rs->has_bandwidth); test_assert(vrs->has_measured_bw); test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2); test_eq(vrs->measured_bw_kb, max_unmeasured_bw_kb / 2); } else if (tor_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", DIGEST_LEN)) { /* * Check the second routerstatus - measured bandwidth above the clip * cutoff. */ test_streq(vrs->version, "0.2.0.5"); test_eq(rs->published_on, now-1000); test_streq(rs->nickname, "router1"); test_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", DIGEST_LEN); test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); test_eq(rs->addr, 0x99009901); test_eq(rs->or_port, 443); test_eq(rs->dir_port, 0); tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); test_eq(rs->ipv6_orport, 4711); test_assert(rs->has_bandwidth); test_assert(vrs->has_measured_bw); test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2); test_eq(vrs->measured_bw_kb, max_unmeasured_bw_kb * 2); } else if (tor_memeq(rs->identity_digest, "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33" "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33", DIGEST_LEN)) { /* * Check the third routerstatus - unmeasured bandwidth above the clip * cutoff; this one should be clipped later on in the consensus, but * appears unclipped in the vote. */ test_assert(rs->has_bandwidth); test_assert(!(vrs->has_measured_bw)); test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2); test_eq(vrs->measured_bw_kb, 0); } else if (tor_memeq(rs->identity_digest, "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34" "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34", DIGEST_LEN)) { /* * Check the fourth routerstatus - unmeasured bandwidth below the clip * cutoff; this one should not be clipped. */ test_assert(rs->has_bandwidth); test_assert(!(vrs->has_measured_bw)); test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2); test_eq(vrs->measured_bw_kb, 0); } else { test_assert(0); } done: return; } /** * Test a consensus for v3_networkstatus_test */ static void test_consensus_for_umbw(networkstatus_t *con, time_t now) { (void)now; test_assert(con); test_assert(!con->cert); // test_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB); test_assert(con->consensus_method >= 16); test_eq(4, smartlist_len(con->routerstatus_list)); /* There should be four listed routers; all voters saw the same in this */ done: return; } /** * Test a router list entry for umbw test */ static void test_routerstatus_for_umbw(routerstatus_t *rs, time_t now) { tor_addr_t addr_ipv6; uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ? alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB; test_assert(rs); /* There should be four listed routers, as constructed above */ if (tor_memeq(rs->identity_digest, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", DIGEST_LEN)) { test_memeq(rs->identity_digest, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3" "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", DIGEST_LEN); test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN); test_assert(!rs->is_authority); test_assert(!rs->is_exit); test_assert(!rs->is_fast); test_assert(!rs->is_possible_guard); test_assert(!rs->is_stable); /* (If it wasn't running it wouldn't be here) */ test_assert(rs->is_flagged_running); test_assert(!rs->is_v2_dir); test_assert(!rs->is_valid); test_assert(!rs->is_named); /* This one should have measured bandwidth below the clip cutoff */ test_assert(rs->has_bandwidth); test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2); test_assert(!(rs->bw_is_unmeasured)); } else if (tor_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", DIGEST_LEN)) { /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */ test_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5", DIGEST_LEN); test_streq(rs->nickname, "router1"); test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN); test_eq(rs->published_on, now-1000); test_eq(rs->addr, 0x99009901); test_eq(rs->or_port, 443); test_eq(rs->dir_port, 0); tor_addr_parse(&addr_ipv6, "[1:2:3::4]"); test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6)); test_eq(rs->ipv6_orport, 4711); test_assert(!rs->is_authority); test_assert(rs->is_exit); test_assert(rs->is_fast); test_assert(rs->is_possible_guard); test_assert(rs->is_stable); test_assert(rs->is_flagged_running); test_assert(rs->is_v2_dir); test_assert(rs->is_valid); test_assert(!rs->is_named); /* This one should have measured bandwidth above the clip cutoff */ test_assert(rs->has_bandwidth); test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2); test_assert(!(rs->bw_is_unmeasured)); } else if (tor_memeq(rs->identity_digest, "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33" "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33", DIGEST_LEN)) { /* * This one should have unmeasured bandwidth above the clip cutoff, * and so should be clipped */ test_assert(rs->has_bandwidth); test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb); test_assert(rs->bw_is_unmeasured); } else if (tor_memeq(rs->identity_digest, "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34" "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34", DIGEST_LEN)) { /* * This one should have unmeasured bandwidth below the clip cutoff, * and so should not be clipped */ test_assert(rs->has_bandwidth); test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2); test_assert(rs->bw_is_unmeasured); } else { /* Weren't expecting this... */ test_assert(0); } done: return; } /** * Compute a consensus involving clipping unmeasured bandwidth with consensus * method 17; this uses the same test_a_networkstatus() function that the * v3_networkstatus test uses. */ static void test_dir_clip_unmeasured_bw_kb(void) { /* Run the test with the default clip bandwidth */ alternate_clip_bw = 0; test_a_networkstatus(gen_routerstatus_for_umbw, vote_tweaks_for_umbw, test_vrs_for_umbw, test_consensus_for_umbw, test_routerstatus_for_umbw); } /** * This version of test_dir_clip_unmeasured_bw_kb() uses a non-default choice * of clip bandwidth. */ static void test_dir_clip_unmeasured_bw_kb_alt(void) { /* * Try a different one; this value is chosen so that the below-the-cutoff * unmeasured nodes the test uses, at alternate_clip_bw / 2, will be above * DEFAULT_MAX_UNMEASURED_BW_KB and if the consensus incorrectly uses that * cutoff it will fail the test. */ alternate_clip_bw = 3 * DEFAULT_MAX_UNMEASURED_BW_KB; test_a_networkstatus(gen_routerstatus_for_umbw, vote_tweaks_for_umbw, test_vrs_for_umbw, test_consensus_for_umbw, test_routerstatus_for_umbw); } extern time_t time_of_process_start; /* from main.c */ static void test_dir_v2_dir(void *arg) { /* Runs in a forked process: acts like a v2 directory just enough to make and * sign a v2 networkstatus opinion */ cached_dir_t *v2 = NULL; or_options_t *options = get_options_mutable(); crypto_pk_t *id_key = pk_generate(4); (void) arg; options->ORPort_set = 1; /* So we believe we're a server. */ options->DirPort_set = 1; options->Address = tor_strdup("99.99.99.99"); options->Nickname = tor_strdup("TestV2Auth"); options->ContactInfo = tor_strdup("TestV2Auth "); { /* Give it a DirPort */ smartlist_t *ports = (smartlist_t *)get_configured_ports(); port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t)); port->type = CONN_TYPE_DIR_LISTENER; port->port = 9999; smartlist_add(ports, port); } set_server_identity_key(id_key); set_client_identity_key(id_key); /* Add a router. */ { was_router_added_t wra; const char *msg = NULL; routerinfo_t *r1 = tor_malloc_zero(sizeof(routerinfo_t)); r1->address = tor_strdup("18.244.0.1"); r1->addr = 0xc0a80001u; /* 192.168.0.1 */ r1->cache_info.published_on = time(NULL)-60; r1->or_port = 9000; r1->dir_port = 9003; tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::"); r1->ipv6_orport = 9999; r1->onion_pkey = pk_generate(1); r1->identity_pkey = pk_generate(2); r1->bandwidthrate = 1000; r1->bandwidthburst = 5000; r1->bandwidthcapacity = 10000; r1->exit_policy = NULL; r1->nickname = tor_strdup("Magri"); r1->platform = tor_strdup("Tor 0.2.7.7-gamma"); r1->cache_info.routerlist_index = -1; r1->cache_info.signed_descriptor_body = router_dump_router_to_string(r1, r1->identity_pkey); r1->cache_info.signed_descriptor_len = strlen(r1->cache_info.signed_descriptor_body); wra = router_add_to_routerlist(r1, &msg, 0, 0); tt_int_op(wra, ==, ROUTER_ADDED_SUCCESSFULLY); } /* Prevent call of rep_hist_note_router_unreachable(). */ time_of_process_start = time(NULL); /* Make a directory so there's somewhere to store the thing */ #ifdef _WIN32 mkdir(get_fname("cached-status")); #else mkdir(get_fname("cached-status"), 0700); #endif v2 = generate_v2_networkstatus_opinion(); tt_assert(v2); done: crypto_pk_free(id_key); cached_dir_decref(v2); } static void test_dir_fmt_control_ns(void *arg) { char *s = NULL; routerstatus_t rs; (void)arg; memset(&rs, 0, sizeof(rs)); rs.published_on = 1364925198; strlcpy(rs.nickname, "TetsuoMilk", sizeof(rs.nickname)); memcpy(rs.identity_digest, "Stately, plump Buck ", DIGEST_LEN); memcpy(rs.descriptor_digest, "Mulligan came up fro", DIGEST_LEN); rs.addr = 0x20304050; rs.or_port = 9001; rs.dir_port = 9002; rs.is_exit = 1; rs.is_fast = 1; rs.is_flagged_running = 1; rs.has_bandwidth = 1; rs.bandwidth_kb = 1000; s = networkstatus_getinfo_helper_single(&rs); tt_assert(s); tt_str_op(s, ==, "r TetsuoMilk U3RhdGVseSwgcGx1bXAgQnVjayA " "TXVsbGlnYW4gY2FtZSB1cCBmcm8 2013-04-02 17:53:18 " "32.48.64.80 9001 9002\n" "s Exit Fast Running\n" "w Bandwidth=1000\n"); done: tor_free(s); } #define DIR_LEGACY(name) \ { #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name } #define DIR(name,flags) \ { #name, test_dir_##name, (flags), NULL, NULL } struct testcase_t dir_tests[] = { DIR_LEGACY(nicknames), DIR_LEGACY(formats), DIR_LEGACY(versions), DIR_LEGACY(fp_pairs), DIR(split_fps, 0), DIR_LEGACY(measured_bw_kb), DIR_LEGACY(measured_bw_kb_cache), DIR_LEGACY(param_voting), DIR_LEGACY(v3_networkstatus), DIR(random_weighted, 0), DIR(scale_bw, 0), DIR_LEGACY(clip_unmeasured_bw_kb), DIR_LEGACY(clip_unmeasured_bw_kb_alt), DIR(v2_dir, TT_FORK), DIR(fmt_control_ns, 0), END_OF_TESTCASES }; tor-0.2.4.20/src/test/test_ntor_cl.c0000644000175000017500000001116212166113000014062 00000000000000/* Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #include #include #define ONION_NTOR_PRIVATE #include "or.h" #include "util.h" #include "compat.h" #include "crypto.h" #include "crypto_curve25519.h" #include "onion_ntor.h" #ifndef CURVE25519_ENABLED #error "This isn't going to work without curve25519." #endif #define N_ARGS(n) STMT_BEGIN { \ if (argc < (n)) { \ fprintf(stderr, "%s needs %d arguments.\n",argv[1],n); \ return 1; \ } \ } STMT_END #define BASE16(idx, var, n) STMT_BEGIN { \ const char *s = argv[(idx)]; \ if (base16_decode((char*)var, n, s, strlen(s)) < 0 ) { \ fprintf(stderr, "couldn't decode argument %d (%s)\n",idx,s); \ return 1; \ } \ } STMT_END #define INT(idx, var) STMT_BEGIN { \ var = atoi(argv[(idx)]); \ if (var <= 0) { \ fprintf(stderr, "bad integer argument %d (%s)\n",idx,argv[(idx)]); \ } \ } STMT_END static int client1(int argc, char **argv) { /* client1 nodeID B -> msg state */ curve25519_public_key_t B; uint8_t node_id[DIGEST_LEN]; ntor_handshake_state_t *state = NULL; uint8_t msg[NTOR_ONIONSKIN_LEN]; char buf[1024]; N_ARGS(4); BASE16(2, node_id, DIGEST_LEN); BASE16(3, B.public_key, CURVE25519_PUBKEY_LEN); if (onion_skin_ntor_create(node_id, &B, &state, msg)<0) { fprintf(stderr, "handshake failed"); return 2; } base16_encode(buf, sizeof(buf), (const char*)msg, sizeof(msg)); printf("%s\n", buf); base16_encode(buf, sizeof(buf), (void*)state, sizeof(*state)); printf("%s\n", buf); ntor_handshake_state_free(state); return 0; } static int server1(int argc, char **argv) { uint8_t msg_in[NTOR_ONIONSKIN_LEN]; curve25519_keypair_t kp; di_digest256_map_t *keymap=NULL; uint8_t node_id[DIGEST_LEN]; int keybytes; uint8_t msg_out[NTOR_REPLY_LEN]; uint8_t *keys = NULL; char *hexkeys = NULL; int result = 0; char buf[256]; /* server1: b nodeID msg N -> msg keys */ N_ARGS(6); BASE16(2, kp.seckey.secret_key, CURVE25519_SECKEY_LEN); BASE16(3, node_id, DIGEST_LEN); BASE16(4, msg_in, NTOR_ONIONSKIN_LEN); INT(5, keybytes); curve25519_public_key_generate(&kp.pubkey, &kp.seckey); dimap_add_entry(&keymap, kp.pubkey.public_key, &kp); keys = tor_malloc(keybytes); hexkeys = tor_malloc(keybytes*2+1); if (onion_skin_ntor_server_handshake( msg_in, keymap, NULL, node_id, msg_out, keys, (size_t)keybytes)<0) { fprintf(stderr, "handshake failed"); result = 2; goto done; } base16_encode(buf, sizeof(buf), (const char*)msg_out, sizeof(msg_out)); printf("%s\n", buf); base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes); printf("%s\n", hexkeys); done: tor_free(keys); tor_free(hexkeys); return result; } static int client2(int argc, char **argv) { struct ntor_handshake_state_t state; uint8_t msg[NTOR_REPLY_LEN]; int keybytes; uint8_t *keys; char *hexkeys; int result = 0; N_ARGS(5); BASE16(2, (&state), sizeof(state)); BASE16(3, msg, sizeof(msg)); INT(4, keybytes); keys = tor_malloc(keybytes); hexkeys = tor_malloc(keybytes*2+1); if (onion_skin_ntor_client_handshake(&state, msg, keys, keybytes)<0) { fprintf(stderr, "handshake failed"); result = 2; goto done; } base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes); printf("%s\n", hexkeys); done: tor_free(keys); tor_free(hexkeys); return result; } int main(int argc, char **argv) { /* client1: nodeID B -> msg state server1: b nodeID msg N -> msg keys client2: state msg N -> keys */ if (argc < 2) { fprintf(stderr, "I need arguments. Read source for more info.\n"); return 1; } else if (!strcmp(argv[1], "client1")) { return client1(argc, argv); } else if (!strcmp(argv[1], "server1")) { return server1(argc, argv); } else if (!strcmp(argv[1], "client2")) { return client2(argc, argv); } else { fprintf(stderr, "What's a %s?\n", argv[1]); return 1; } } tor-0.2.4.20/src/test/test_introduce.c0000644000175000017500000004247512166113000014431 00000000000000/* Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #include "crypto.h" #include "or.h" #include "test.h" #define RENDSERVICE_PRIVATE #include "rendservice.h" extern const char AUTHORITY_SIGNKEY_1[]; static uint8_t v0_test_plaintext[] = /* 20 bytes of rendezvous point nickname */ { 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20 bytes dummy rendezvous cookie */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 128 bytes dummy DH handshake data */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; static uint8_t v1_test_plaintext[] = /* Version byte */ { 0x01, /* 42 bytes of dummy rendezvous point hex digest */ 0x24, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38, 0x30, 0x39, 0x30, 0x41, 0x30, 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30, 0x46, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33, 0x00, /* 20 bytes dummy rendezvous cookie */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 128 bytes dummy DH handshake data */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; static uint8_t v2_test_plaintext[] = /* Version byte */ { 0x02, /* 4 bytes rendezvous point's IP address */ 0xc0, 0xa8, 0x00, 0x01, /* 2 bytes rendezvous point's OR port */ 0x23, 0x5a, /* 20 bytes dummy rendezvous point's identity digest */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 2 bytes length of onion key */ 0x00, 0x8c, /* Onion key (140 bytes taken from live test) */ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1, 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8, 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4, 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6, 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61, 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa, 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11, 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1, 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d, 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0, 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f, 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4, 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31, 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb, 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f, 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92, 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02, 0x03, 0x01, 0x00, 0x01, /* 20 bytes dummy rendezvous cookie */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 128 bytes dummy DH handshake data */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; static uint8_t v3_no_auth_test_plaintext[] = /* Version byte */ { 0x03, /* Auth type (0 for no auth len/auth data) */ 0x00, /* Timestamp */ 0x50, 0x0b, 0xb5, 0xaa, /* 4 bytes rendezvous point's IP address */ 0xc0, 0xa8, 0x00, 0x01, /* 2 bytes rendezvous point's OR port */ 0x23, 0x5a, /* 20 bytes dummy rendezvous point's identity digest */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 2 bytes length of onion key */ 0x00, 0x8c, /* Onion key (140 bytes taken from live test) */ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1, 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8, 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4, 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6, 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61, 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa, 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11, 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1, 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d, 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0, 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f, 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4, 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31, 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb, 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f, 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92, 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02, 0x03, 0x01, 0x00, 0x01, /* 20 bytes dummy rendezvous cookie */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 128 bytes dummy DH handshake data */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; static uint8_t v3_basic_auth_test_plaintext[] = /* Version byte */ { 0x03, /* Auth type (1 for REND_BASIC_AUTH) */ 0x01, /* Auth len (must be 16 bytes for REND_BASIC_AUTH) */ 0x00, 0x10, /* Auth data (a 16-byte dummy descriptor cookie) */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* Timestamp */ 0x50, 0x0b, 0xb5, 0xaa, /* 4 bytes rendezvous point's IP address */ 0xc0, 0xa8, 0x00, 0x01, /* 2 bytes rendezvous point's OR port */ 0x23, 0x5a, /* 20 bytes dummy rendezvous point's identity digest */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 2 bytes length of onion key */ 0x00, 0x8c, /* Onion key (140 bytes taken from live test) */ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1, 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8, 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4, 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6, 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61, 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa, 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11, 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1, 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d, 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0, 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f, 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4, 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31, 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb, 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f, 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92, 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02, 0x03, 0x01, 0x00, 0x01, /* 20 bytes dummy rendezvous cookie */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 128 bytes dummy DH handshake data */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; static void do_decrypt_test(uint8_t *plaintext, size_t plaintext_len); static void do_early_parse_test(uint8_t *plaintext, size_t plaintext_len); static void do_late_parse_test(uint8_t *plaintext, size_t plaintext_len); static void do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase); static ssize_t make_intro_from_plaintext( void *buf, size_t len, crypto_pk_t *key, void **cell_out); #define EARLY_PARSE_ONLY 1 #define DECRYPT_ONLY 2 #define ALL_PARSING 3 static void do_early_parse_test(uint8_t *plaintext, size_t plaintext_len) { do_parse_test(plaintext, plaintext_len, EARLY_PARSE_ONLY); } static void do_decrypt_test(uint8_t *plaintext, size_t plaintext_len) { do_parse_test(plaintext, plaintext_len, DECRYPT_ONLY); } static void do_late_parse_test(uint8_t *plaintext, size_t plaintext_len) { do_parse_test(plaintext, plaintext_len, ALL_PARSING); } /** Test utility function: checks that the plaintext_len-byte string at * plaintext is at least superficially parseable. */ static void do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase) { crypto_pk_t *k = NULL; ssize_t r; uint8_t *cell = NULL; size_t cell_len; rend_intro_cell_t *parsed_req = NULL; char *err_msg = NULL; char digest[DIGEST_LEN]; /* Get a key */ k = crypto_pk_new(); test_assert(k); r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1); test_assert(!r); /* Get digest for future comparison */ r = crypto_pk_get_digest(k, digest); test_assert(r >= 0); /* Make a cell out of it */ r = make_intro_from_plaintext( plaintext, plaintext_len, k, (void **)(&cell)); test_assert(r > 0); test_assert(cell); cell_len = r; /* Do early parsing */ parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg); test_assert(parsed_req); test_assert(!err_msg); test_memeq(parsed_req->pk, digest, DIGEST_LEN); test_assert(parsed_req->ciphertext); test_assert(parsed_req->ciphertext_len > 0); if (phase == EARLY_PARSE_ONLY) goto done; /* Do decryption */ r = rend_service_decrypt_intro(parsed_req, k, &err_msg); test_assert(!r); test_assert(!err_msg); test_assert(parsed_req->plaintext); test_assert(parsed_req->plaintext_len > 0); if (phase == DECRYPT_ONLY) goto done; /* Do late parsing */ r = rend_service_parse_intro_plaintext(parsed_req, &err_msg); test_assert(!r); test_assert(!err_msg); test_assert(parsed_req->parsed); done: tor_free(cell); crypto_pk_free(k); rend_service_free_intro(parsed_req); tor_free(err_msg); } /** Given the plaintext of the encrypted part of an INTRODUCE1/2 and a key, * construct the encrypted cell for testing. */ static ssize_t make_intro_from_plaintext( void *buf, size_t len, crypto_pk_t *key, void **cell_out) { char *cell = NULL; ssize_t cell_len = -1, r; /* Assemble key digest and ciphertext, then construct the cell */ ssize_t ciphertext_size; if (!(buf && key && len > 0 && cell_out)) goto done; /* * Figure out an upper bound on how big the ciphertext will be * (see crypto_pk_public_hybrid_encrypt()) */ ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD; ciphertext_size += crypto_pk_keysize(key); ciphertext_size += CIPHER_KEY_LEN; ciphertext_size += len; /* * Allocate space for the cell */ cell = tor_malloc(DIGEST_LEN + ciphertext_size); /* Compute key digest (will be first DIGEST_LEN octets of cell) */ r = crypto_pk_get_digest(key, cell); test_assert(r >= 0); /* Do encryption */ r = crypto_pk_public_hybrid_encrypt( key, cell + DIGEST_LEN, ciphertext_size, buf, len, PK_PKCS1_OAEP_PADDING, 0); test_assert(r >= 0); /* Figure out cell length */ cell_len = DIGEST_LEN + r; /* Output the cell */ *cell_out = cell; done: return cell_len; } /** Test v0 INTRODUCE2 parsing through decryption only */ static void test_introduce_decrypt_v0(void) { do_decrypt_test(v0_test_plaintext, sizeof(v0_test_plaintext)); } /** Test v1 INTRODUCE2 parsing through decryption only */ static void test_introduce_decrypt_v1(void) { do_decrypt_test(v1_test_plaintext, sizeof(v1_test_plaintext)); } /** Test v2 INTRODUCE2 parsing through decryption only */ static void test_introduce_decrypt_v2(void) { do_decrypt_test(v2_test_plaintext, sizeof(v2_test_plaintext)); } /** Test v3 INTRODUCE2 parsing through decryption only */ static void test_introduce_decrypt_v3(void) { do_decrypt_test( v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext)); do_decrypt_test( v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext)); } /** Test v0 INTRODUCE2 parsing through early parsing only */ static void test_introduce_early_parse_v0(void) { do_early_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext)); } /** Test v1 INTRODUCE2 parsing through early parsing only */ static void test_introduce_early_parse_v1(void) { do_early_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext)); } /** Test v2 INTRODUCE2 parsing through early parsing only */ static void test_introduce_early_parse_v2(void) { do_early_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext)); } /** Test v3 INTRODUCE2 parsing through early parsing only */ static void test_introduce_early_parse_v3(void) { do_early_parse_test( v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext)); do_early_parse_test( v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext)); } /** Test v0 INTRODUCE2 parsing */ static void test_introduce_late_parse_v0(void) { do_late_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext)); } /** Test v1 INTRODUCE2 parsing */ static void test_introduce_late_parse_v1(void) { do_late_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext)); } /** Test v2 INTRODUCE2 parsing */ static void test_introduce_late_parse_v2(void) { do_late_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext)); } /** Test v3 INTRODUCE2 parsing */ static void test_introduce_late_parse_v3(void) { do_late_parse_test( v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext)); do_late_parse_test( v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext)); } #define INTRODUCE_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_introduce_ ## name } struct testcase_t introduce_tests[] = { INTRODUCE_LEGACY(early_parse_v0), INTRODUCE_LEGACY(early_parse_v1), INTRODUCE_LEGACY(early_parse_v2), INTRODUCE_LEGACY(early_parse_v3), INTRODUCE_LEGACY(decrypt_v0), INTRODUCE_LEGACY(decrypt_v1), INTRODUCE_LEGACY(decrypt_v2), INTRODUCE_LEGACY(decrypt_v3), INTRODUCE_LEGACY(late_parse_v0), INTRODUCE_LEGACY(late_parse_v1), INTRODUCE_LEGACY(late_parse_v2), INTRODUCE_LEGACY(late_parse_v3), END_OF_TESTCASES }; tor-0.2.4.20/src/test/test.c0000644000175000017500000021630112255745673012376 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Ordinarily defined in tor_main.c; this bit is just here to provide one * since we're not linking to tor_main.c */ const char tor_git_revision[] = ""; /** * \file test.c * \brief Unit tests for many pieces of the lower level Tor modules. **/ #include "orconfig.h" #include #ifdef HAVE_FCNTL_H #include #endif #ifdef _WIN32 /* For mkdir() */ #include #else #include #endif /* These macros pull in declarations for some functions and structures that * are typically file-private. */ #define BUFFERS_PRIVATE #define CONFIG_PRIVATE #define GEOIP_PRIVATE #define ROUTER_PRIVATE #define CIRCUITSTATS_PRIVATE /* * Linux doesn't provide lround in math.h by default, but mac os does... * It's best just to leave math.h out of the picture entirely. */ //#include long int lround(double x); double fabs(double x); #include "or.h" #include "buffers.h" #include "circuitlist.h" #include "circuitstats.h" #include "config.h" #include "connection_edge.h" #include "geoip.h" #include "rendcommon.h" #include "test.h" #include "torgzip.h" #include "mempool.h" #include "memarea.h" #include "onion.h" #include "onion_tap.h" #include "policies.h" #include "rephist.h" #include "routerparse.h" #ifdef CURVE25519_ENABLED #include "crypto_curve25519.h" #include "onion_ntor.h" #endif #ifdef USE_DMALLOC #include #include #include "main.h" #endif /** Set to true if any unit test has failed. Mostly, this is set by the macros * in test.h */ int have_failed = 0; /** Temporary directory (set up by setup_directory) under which we store all * our files during testing. */ static char temp_dir[256]; #ifdef _WIN32 #define pid_t int #endif static pid_t temp_dir_setup_in_pid = 0; /** Select and create the temporary directory we'll use to run our unit tests. * Store it in temp_dir. Exit immediately if we can't create it. * idempotent. */ static void setup_directory(void) { static int is_setup = 0; int r; char rnd[256], rnd32[256]; if (is_setup) return; /* Due to base32 limitation needs to be a multiple of 5. */ #define RAND_PATH_BYTES 5 crypto_rand(rnd, RAND_PATH_BYTES); base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES); #ifdef _WIN32 { char buf[MAX_PATH]; const char *tmp = buf; /* If this fails, we're probably screwed anyway */ if (!GetTempPathA(sizeof(buf),buf)) tmp = "c:\\windows\\temp"; tor_snprintf(temp_dir, sizeof(temp_dir), "%s\\tor_test_%d_%s", tmp, (int)getpid(), rnd32); r = mkdir(temp_dir); } #else tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s", (int) getpid(), rnd32); r = mkdir(temp_dir, 0700); #endif if (r) { fprintf(stderr, "Can't create directory %s:", temp_dir); perror(""); exit(1); } is_setup = 1; temp_dir_setup_in_pid = getpid(); } /** Return a filename relative to our testing temporary directory */ const char * get_fname(const char *name) { static char buf[1024]; setup_directory(); if (!name) return temp_dir; tor_snprintf(buf,sizeof(buf),"%s/%s",temp_dir,name); return buf; } /* Remove a directory and all of its subdirectories */ static void rm_rf(const char *dir) { struct stat st; smartlist_t *elements; elements = tor_listdir(dir); if (elements) { SMARTLIST_FOREACH_BEGIN(elements, const char *, cp) { char *tmp = NULL; tor_asprintf(&tmp, "%s"PATH_SEPARATOR"%s", dir, cp); if (0 == stat(tmp,&st) && (st.st_mode & S_IFDIR)) { rm_rf(tmp); } else { if (unlink(tmp)) { fprintf(stderr, "Error removing %s: %s\n", tmp, strerror(errno)); } } tor_free(tmp); } SMARTLIST_FOREACH_END(cp); SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); smartlist_free(elements); } if (rmdir(dir)) fprintf(stderr, "Error removing directory %s: %s\n", dir, strerror(errno)); } /** Remove all files stored under the temporary directory, and the directory * itself. Called by atexit(). */ static void remove_directory(void) { if (getpid() != temp_dir_setup_in_pid) { /* Only clean out the tempdir when the main process is exiting. */ return; } rm_rf(temp_dir); } /** Define this if unit tests spend too much time generating public keys*/ #undef CACHE_GENERATED_KEYS static crypto_pk_t *pregen_keys[5] = {NULL, NULL, NULL, NULL, NULL}; #define N_PREGEN_KEYS ((int)(sizeof(pregen_keys)/sizeof(pregen_keys[0]))) /** Generate and return a new keypair for use in unit tests. If we're using * the key cache optimization, we might reuse keys: we only guarantee that * keys made with distinct values for idx are different. The value of * idx must be at least 0, and less than N_PREGEN_KEYS. */ crypto_pk_t * pk_generate(int idx) { #ifdef CACHE_GENERATED_KEYS tor_assert(idx < N_PREGEN_KEYS); if (! pregen_keys[idx]) { pregen_keys[idx] = crypto_pk_new(); tor_assert(!crypto_pk_generate_key(pregen_keys[idx])); } return crypto_pk_dup_key(pregen_keys[idx]); #else crypto_pk_t *result; (void) idx; result = crypto_pk_new(); tor_assert(!crypto_pk_generate_key(result)); return result; #endif } /** Free all storage used for the cached key optimization. */ static void free_pregenerated_keys(void) { unsigned idx; for (idx = 0; idx < N_PREGEN_KEYS; ++idx) { if (pregen_keys[idx]) { crypto_pk_free(pregen_keys[idx]); pregen_keys[idx] = NULL; } } } typedef struct socks_test_data_t { socks_request_t *req; buf_t *buf; } socks_test_data_t; static void * socks_test_setup(const struct testcase_t *testcase) { socks_test_data_t *data = tor_malloc(sizeof(socks_test_data_t)); (void)testcase; data->buf = buf_new_with_capacity(256); data->req = socks_request_new(); config_register_addressmaps(get_options()); return data; } static int socks_test_cleanup(const struct testcase_t *testcase, void *ptr) { socks_test_data_t *data = ptr; (void)testcase; buf_free(data->buf); socks_request_free(data->req); tor_free(data); return 1; } const struct testcase_setup_t socks_setup = { socks_test_setup, socks_test_cleanup }; #define SOCKS_TEST_INIT() \ socks_test_data_t *testdata = ptr; \ buf_t *buf = testdata->buf; \ socks_request_t *socks = testdata->req; #define ADD_DATA(buf, s) \ write_to_buf(s, sizeof(s)-1, buf) static void socks_request_clear(socks_request_t *socks) { tor_free(socks->username); tor_free(socks->password); memset(socks, 0, sizeof(socks_request_t)); } /** Perform unsupported SOCKS 4 commands */ static void test_socks_4_unsupported_commands(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 4 Send BIND [02] to IP address 2.2.2.2:4369 */ ADD_DATA(buf, "\x04\x02\x11\x11\x02\x02\x02\x02\x00"); test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == -1); test_eq(4, socks->socks_version); test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */ done: ; } /** Perform supported SOCKS 4 commands */ static void test_socks_4_supported_commands(void *ptr) { SOCKS_TEST_INIT(); test_eq(0, buf_datalen(buf)); /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4370 */ ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x03\x00"); test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); test_eq(4, socks->socks_version); test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */ test_eq(SOCKS_COMMAND_CONNECT, socks->command); test_streq("2.2.2.3", socks->address); test_eq(4370, socks->port); test_assert(socks->got_auth == 0); test_assert(! socks->username); test_eq(0, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4369 with userid*/ ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x04me\x00"); test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); test_eq(4, socks->socks_version); test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */ test_eq(SOCKS_COMMAND_CONNECT, socks->command); test_streq("2.2.2.4", socks->address); test_eq(4370, socks->port); test_assert(socks->got_auth == 1); test_assert(socks->username); test_eq(2, socks->usernamelen); test_memeq("me", socks->username, 2); test_eq(0, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 4a Send RESOLVE [F0] request for torproject.org */ ADD_DATA(buf, "\x04\xF0\x01\x01\x00\x00\x00\x02me\x00torproject.org\x00"); test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); test_eq(4, socks->socks_version); test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */ test_streq("torproject.org", socks->address); test_eq(0, buf_datalen(buf)); done: ; } /** Perform unsupported SOCKS 5 commands */ static void test_socks_5_unsupported_commands(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Send unsupported BIND [02] command */ ADD_DATA(buf, "\x05\x02\x00\x01"); test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks), 0); test_eq(0, buf_datalen(buf)); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(0, socks->reply[1]); ADD_DATA(buf, "\x05\x02\x00\x01\x02\x02\x02\x01\x01\x01"); test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks), -1); /* XXX: shouldn't tor reply 'command not supported' [07]? */ buf_clear(buf); socks_request_clear(socks); /* SOCKS 5 Send unsupported UDP_ASSOCIATE [03] command */ ADD_DATA(buf, "\x05\x03\x00\x01\x02"); test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks), 0); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(2, socks->reply[1]); ADD_DATA(buf, "\x05\x03\x00\x01\x02\x02\x02\x01\x01\x01"); test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks), -1); /* XXX: shouldn't tor reply 'command not supported' [07]? */ done: ; } /** Perform supported SOCKS 5 commands */ static void test_socks_5_supported_commands(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */ ADD_DATA(buf, "\x05\x01\x00"); test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks), 0); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(0, socks->reply[1]); ADD_DATA(buf, "\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11"); test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks), 1); test_streq("2.2.2.2", socks->address); test_eq(4369, socks->port); test_eq(0, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 5 Send CONNECT [01] to FQDN torproject.org:4369 */ ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\x01\x00\x03\x0Etorproject.org\x11\x11"); test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks), 1); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(0, socks->reply[1]); test_streq("torproject.org", socks->address); test_eq(4369, socks->port); test_eq(0, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 5 Send RESOLVE [F0] request for torproject.org:4369 */ ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\xF0\x00\x03\x0Etorproject.org\x01\x02"); test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(0, socks->reply[1]); test_streq("torproject.org", socks->address); test_eq(0, buf_datalen(buf)); socks_request_clear(socks); /* SOCKS 5 Send RESOLVE_PTR [F1] for IP address 2.2.2.5 */ ADD_DATA(buf, "\x05\x01\x00"); ADD_DATA(buf, "\x05\xF1\x00\x01\x02\x02\x02\x05\x01\x03"); test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(0, socks->reply[1]); test_streq("2.2.2.5", socks->address); test_eq(0, buf_datalen(buf)); done: ; } /** Perform SOCKS 5 authentication */ static void test_socks_5_no_authenticate(void *ptr) { SOCKS_TEST_INIT(); /*SOCKS 5 No Authentication */ ADD_DATA(buf,"\x05\x01\x00"); test_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(SOCKS_NO_AUTH, socks->reply[1]); test_eq(0, buf_datalen(buf)); /*SOCKS 5 Send username/password anyway - pretend to be broken */ ADD_DATA(buf,"\x01\x02\x01\x01\x02\x01\x01"); test_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(1, socks->reply[0]); test_eq(0, socks->reply[1]); test_eq(2, socks->usernamelen); test_eq(2, socks->passwordlen); test_memeq("\x01\x01", socks->username, 2); test_memeq("\x01\x01", socks->password, 2); done: ; } /** Perform SOCKS 5 authentication */ static void test_socks_5_authenticate(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Negotiate username/password authentication */ ADD_DATA(buf, "\x05\x01\x02"); test_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(SOCKS_USER_PASS, socks->reply[1]); test_eq(5, socks->socks_version); test_eq(0, buf_datalen(buf)); /* SOCKS 5 Send username/password */ ADD_DATA(buf, "\x01\x02me\x08mypasswd"); test_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(1, socks->reply[0]); test_eq(0, socks->reply[1]); test_eq(2, socks->usernamelen); test_eq(8, socks->passwordlen); test_memeq("me", socks->username, 2); test_memeq("mypasswd", socks->password, 8); done: ; } /** Perform SOCKS 5 authentication and send data all in one go */ static void test_socks_5_authenticate_with_data(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Negotiate username/password authentication */ ADD_DATA(buf, "\x05\x01\x02"); test_assert(!fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks)); test_eq(2, socks->replylen); test_eq(5, socks->reply[0]); test_eq(SOCKS_USER_PASS, socks->reply[1]); test_eq(5, socks->socks_version); test_eq(0, buf_datalen(buf)); /* SOCKS 5 Send username/password */ /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */ ADD_DATA(buf, "\x01\x02me\x03you\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11"); test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == 1); test_eq(5, socks->socks_version); test_eq(2, socks->replylen); test_eq(1, socks->reply[0]); test_eq(0, socks->reply[1]); test_streq("2.2.2.2", socks->address); test_eq(4369, socks->port); test_eq(2, socks->usernamelen); test_eq(3, socks->passwordlen); test_memeq("me", socks->username, 2); test_memeq("you", socks->password, 3); done: ; } /** Perform SOCKS 5 authentication before method negotiated */ static void test_socks_5_auth_before_negotiation(void *ptr) { SOCKS_TEST_INIT(); /* SOCKS 5 Send username/password */ ADD_DATA(buf, "\x01\x02me\x02me"); test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, get_options()->SafeSocks) == -1); test_eq(0, socks->socks_version); test_eq(0, socks->replylen); test_eq(0, socks->reply[0]); test_eq(0, socks->reply[1]); done: ; } static void test_buffer_copy(void *arg) { generic_buffer_t *buf=NULL, *buf2=NULL; const char *s; size_t len; char b[256]; int i; (void)arg; buf = generic_buffer_new(); tt_assert(buf); /* Copy an empty buffer. */ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf)); tt_assert(buf2); tt_int_op(0, ==, generic_buffer_len(buf2)); /* Now try with a short buffer. */ s = "And now comes an act of enormous enormance!"; len = strlen(s); generic_buffer_add(buf, s, len); tt_int_op(len, ==, generic_buffer_len(buf)); /* Add junk to buf2 so we can test replacing.*/ generic_buffer_add(buf2, "BLARG", 5); tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf)); tt_int_op(len, ==, generic_buffer_len(buf2)); generic_buffer_get(buf2, b, len); test_mem_op(b, ==, s, len); /* Now free buf2 and retry so we can test allocating */ generic_buffer_free(buf2); buf2 = NULL; tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf)); tt_int_op(len, ==, generic_buffer_len(buf2)); generic_buffer_get(buf2, b, len); test_mem_op(b, ==, s, len); /* Clear buf for next test */ generic_buffer_get(buf, b, len); tt_int_op(generic_buffer_len(buf),==,0); /* Okay, now let's try a bigger buffer. */ s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit " "esse quam nihil molestiae consequatur, vel illum qui dolorem eum " "fugiat quo voluptas nulla pariatur?"; len = strlen(s); for (i = 0; i < 256; ++i) { b[0]=i; generic_buffer_add(buf, b, 1); generic_buffer_add(buf, s, len); } tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf)); tt_int_op(generic_buffer_len(buf2), ==, generic_buffer_len(buf)); for (i = 0; i < 256; ++i) { generic_buffer_get(buf2, b, len+1); tt_int_op((unsigned char)b[0],==,i); test_mem_op(b+1, ==, s, len); } done: if (buf) generic_buffer_free(buf); if (buf2) generic_buffer_free(buf2); } /** Run unit tests for buffers.c */ static void test_buffers(void) { char str[256]; char str2[256]; buf_t *buf = NULL, *buf2 = NULL; const char *cp; int j; size_t r; /**** * buf_new ****/ if (!(buf = buf_new())) test_fail(); //test_eq(buf_capacity(buf), 4096); test_eq(buf_datalen(buf), 0); /**** * General pointer frobbing */ for (j=0;j<256;++j) { str[j] = (char)j; } write_to_buf(str, 256, buf); write_to_buf(str, 256, buf); test_eq(buf_datalen(buf), 512); fetch_from_buf(str2, 200, buf); test_memeq(str, str2, 200); test_eq(buf_datalen(buf), 312); memset(str2, 0, sizeof(str2)); fetch_from_buf(str2, 256, buf); test_memeq(str+200, str2, 56); test_memeq(str, str2+56, 200); test_eq(buf_datalen(buf), 56); memset(str2, 0, sizeof(str2)); /* Okay, now we should be 512 bytes into the 4096-byte buffer. If we add * another 3584 bytes, we hit the end. */ for (j=0;j<15;++j) { write_to_buf(str, 256, buf); } assert_buf_ok(buf); test_eq(buf_datalen(buf), 3896); fetch_from_buf(str2, 56, buf); test_eq(buf_datalen(buf), 3840); test_memeq(str+200, str2, 56); for (j=0;j<15;++j) { memset(str2, 0, sizeof(str2)); fetch_from_buf(str2, 256, buf); test_memeq(str, str2, 256); } test_eq(buf_datalen(buf), 0); buf_free(buf); buf = NULL; /* Okay, now make sure growing can work. */ buf = buf_new_with_capacity(16); //test_eq(buf_capacity(buf), 16); write_to_buf(str+1, 255, buf); //test_eq(buf_capacity(buf), 256); fetch_from_buf(str2, 254, buf); test_memeq(str+1, str2, 254); //test_eq(buf_capacity(buf), 256); assert_buf_ok(buf); write_to_buf(str, 32, buf); //test_eq(buf_capacity(buf), 256); assert_buf_ok(buf); write_to_buf(str, 256, buf); assert_buf_ok(buf); //test_eq(buf_capacity(buf), 512); test_eq(buf_datalen(buf), 33+256); fetch_from_buf(str2, 33, buf); test_eq(*str2, str[255]); test_memeq(str2+1, str, 32); //test_eq(buf_capacity(buf), 512); test_eq(buf_datalen(buf), 256); fetch_from_buf(str2, 256, buf); test_memeq(str, str2, 256); /* now try shrinking: case 1. */ buf_free(buf); buf = buf_new_with_capacity(33668); for (j=0;j<67;++j) { write_to_buf(str,255, buf); } //test_eq(buf_capacity(buf), 33668); test_eq(buf_datalen(buf), 17085); for (j=0; j < 40; ++j) { fetch_from_buf(str2, 255,buf); test_memeq(str2, str, 255); } /* now try shrinking: case 2. */ buf_free(buf); buf = buf_new_with_capacity(33668); for (j=0;j<67;++j) { write_to_buf(str,255, buf); } for (j=0; j < 20; ++j) { fetch_from_buf(str2, 255,buf); test_memeq(str2, str, 255); } for (j=0;j<80;++j) { write_to_buf(str,255, buf); } //test_eq(buf_capacity(buf),33668); for (j=0; j < 120; ++j) { fetch_from_buf(str2, 255,buf); test_memeq(str2, str, 255); } /* Move from buf to buf. */ buf_free(buf); buf = buf_new_with_capacity(4096); buf2 = buf_new_with_capacity(4096); for (j=0;j<100;++j) write_to_buf(str, 255, buf); test_eq(buf_datalen(buf), 25500); for (j=0;j<100;++j) { r = 10; move_buf_to_buf(buf2, buf, &r); test_eq(r, 0); } test_eq(buf_datalen(buf), 24500); test_eq(buf_datalen(buf2), 1000); for (j=0;j<3;++j) { fetch_from_buf(str2, 255, buf2); test_memeq(str2, str, 255); } r = 8192; /*big move*/ move_buf_to_buf(buf2, buf, &r); test_eq(r, 0); r = 30000; /* incomplete move */ move_buf_to_buf(buf2, buf, &r); test_eq(r, 13692); for (j=0;j<97;++j) { fetch_from_buf(str2, 255, buf2); test_memeq(str2, str, 255); } buf_free(buf); buf_free(buf2); buf = buf2 = NULL; buf = buf_new_with_capacity(5); cp = "Testing. This is a moderately long Testing string."; for (j = 0; cp[j]; j++) write_to_buf(cp+j, 1, buf); test_eq(0, buf_find_string_offset(buf, "Testing", 7)); test_eq(1, buf_find_string_offset(buf, "esting", 6)); test_eq(1, buf_find_string_offset(buf, "est", 3)); test_eq(39, buf_find_string_offset(buf, "ing str", 7)); test_eq(35, buf_find_string_offset(buf, "Testing str", 11)); test_eq(32, buf_find_string_offset(buf, "ng ", 3)); test_eq(43, buf_find_string_offset(buf, "string.", 7)); test_eq(-1, buf_find_string_offset(buf, "shrdlu", 6)); test_eq(-1, buf_find_string_offset(buf, "Testing thing", 13)); test_eq(-1, buf_find_string_offset(buf, "ngx", 3)); buf_free(buf); buf = NULL; /* Try adding a string too long for any freelist. */ { char *cp = tor_malloc_zero(65536); buf = buf_new(); write_to_buf(cp, 65536, buf); tor_free(cp); tt_int_op(buf_datalen(buf), ==, 65536); buf_free(buf); buf = NULL; } done: if (buf) buf_free(buf); if (buf2) buf_free(buf2); } /** Run unit tests for the onion handshake code. */ static void test_onion_handshake(void) { /* client-side */ crypto_dh_t *c_dh = NULL; char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; char c_keys[40]; /* server-side */ char s_buf[TAP_ONIONSKIN_REPLY_LEN]; char s_keys[40]; /* shared */ crypto_pk_t *pk = NULL; pk = pk_generate(0); /* client handshake 1. */ memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN); test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf)); /* server handshake */ memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN); memset(s_keys, 0, 40); test_assert(! onion_skin_TAP_server_handshake(c_buf, pk, NULL, s_buf, s_keys, 40)); /* client handshake 2 */ memset(c_keys, 0, 40); test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40)); if (memcmp(c_keys, s_keys, 40)) { puts("Aiiiie"); exit(1); } test_memeq(c_keys, s_keys, 40); memset(s_buf, 0, 40); test_memneq(c_keys, s_buf, 40); done: if (c_dh) crypto_dh_free(c_dh); if (pk) crypto_pk_free(pk); } #ifdef CURVE25519_ENABLED static void test_ntor_handshake(void *arg) { /* client-side */ ntor_handshake_state_t *c_state = NULL; uint8_t c_buf[NTOR_ONIONSKIN_LEN]; uint8_t c_keys[400]; /* server-side */ di_digest256_map_t *s_keymap=NULL; curve25519_keypair_t s_keypair; uint8_t s_buf[NTOR_REPLY_LEN]; uint8_t s_keys[400]; /* shared */ const curve25519_public_key_t *server_pubkey; uint8_t node_id[20] = "abcdefghijklmnopqrst"; (void) arg; /* Make the server some keys */ curve25519_secret_key_generate(&s_keypair.seckey, 0); curve25519_public_key_generate(&s_keypair.pubkey, &s_keypair.seckey); dimap_add_entry(&s_keymap, s_keypair.pubkey.public_key, &s_keypair); server_pubkey = &s_keypair.pubkey; /* client handshake 1. */ memset(c_buf, 0, NTOR_ONIONSKIN_LEN); tt_int_op(0, ==, onion_skin_ntor_create(node_id, server_pubkey, &c_state, c_buf)); /* server handshake */ memset(s_buf, 0, NTOR_REPLY_LEN); memset(s_keys, 0, 40); tt_int_op(0, ==, onion_skin_ntor_server_handshake(c_buf, s_keymap, NULL, node_id, s_buf, s_keys, 400)); /* client handshake 2 */ memset(c_keys, 0, 40); tt_int_op(0, ==, onion_skin_ntor_client_handshake(c_state, s_buf, c_keys, 400)); test_memeq(c_keys, s_keys, 400); memset(s_buf, 0, 40); test_memneq(c_keys, s_buf, 40); done: ntor_handshake_state_free(c_state); dimap_free(s_keymap, NULL); } #endif /** Run unit tests for the onion queues. */ static void test_onion_queues(void) { uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0}; uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0}; or_circuit_t *circ1 = or_circuit_new(0, NULL); or_circuit_t *circ2 = or_circuit_new(0, NULL); create_cell_t *onionskin = NULL; create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t)); create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t)); create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP, TAP_ONIONSKIN_CHALLENGE_LEN, buf1); create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, NTOR_ONIONSKIN_LEN, buf2); test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); test_eq(0, onion_pending_add(circ1, create1)); test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); test_eq(0, onion_pending_add(circ2, create2)); test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); test_eq_ptr(circ2, onion_next_task(&onionskin)); test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); clear_pending_onions(); test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP)); test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR)); done: ; // circuit_free(circ1); // circuit_free(circ2); /* and free create1 and create2 */ /* XXX leaks everything here */ } static void test_circuit_timeout(void) { /* Plan: * 1. Generate 1000 samples * 2. Estimate parameters * 3. If difference, repeat * 4. Save state * 5. load state * 6. Estimate parameters * 7. compare differences */ circuit_build_times_t initial; circuit_build_times_t estimate; circuit_build_times_t final; double timeout1, timeout2; or_state_t state; int i, runs; double close_ms; circuit_build_times_init(&initial); circuit_build_times_init(&estimate); circuit_build_times_init(&final); memset(&state, 0, sizeof(or_state_t)); circuitbuild_running_unit_tests(); #define timeout0 (build_time_t)(30*1000.0) initial.Xm = 3000; circuit_build_times_initial_alpha(&initial, CBT_DEFAULT_QUANTILE_CUTOFF/100.0, timeout0); close_ms = MAX(circuit_build_times_calculate_timeout(&initial, CBT_DEFAULT_CLOSE_QUANTILE/100.0), CBT_DEFAULT_TIMEOUT_INITIAL_VALUE); do { for (i=0; i < CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE; i++) { build_time_t sample = circuit_build_times_generate_sample(&initial,0,1); if (sample > close_ms) { circuit_build_times_add_time(&estimate, CBT_BUILD_ABANDONED); } else { circuit_build_times_add_time(&estimate, sample); } } circuit_build_times_update_alpha(&estimate); timeout1 = circuit_build_times_calculate_timeout(&estimate, CBT_DEFAULT_QUANTILE_CUTOFF/100.0); circuit_build_times_set_timeout(&estimate); log_notice(LD_CIRC, "Timeout1 is %f, Xm is %d", timeout1, estimate.Xm); /* 2% error */ } while (fabs(circuit_build_times_cdf(&initial, timeout0) - circuit_build_times_cdf(&initial, timeout1)) > 0.02); test_assert(estimate.total_build_times <= CBT_NCIRCUITS_TO_OBSERVE); circuit_build_times_update_state(&estimate, &state); test_assert(circuit_build_times_parse_state(&final, &state) == 0); circuit_build_times_update_alpha(&final); timeout2 = circuit_build_times_calculate_timeout(&final, CBT_DEFAULT_QUANTILE_CUTOFF/100.0); circuit_build_times_set_timeout(&final); log_notice(LD_CIRC, "Timeout2 is %f, Xm is %d", timeout2, final.Xm); /* 5% here because some accuracy is lost due to histogram conversion */ test_assert(fabs(circuit_build_times_cdf(&initial, timeout0) - circuit_build_times_cdf(&initial, timeout2)) < 0.05); for (runs = 0; runs < 50; runs++) { int build_times_idx = 0; int total_build_times = 0; final.close_ms = final.timeout_ms = CBT_DEFAULT_TIMEOUT_INITIAL_VALUE; estimate.close_ms = estimate.timeout_ms = CBT_DEFAULT_TIMEOUT_INITIAL_VALUE; for (i = 0; i < CBT_DEFAULT_RECENT_CIRCUITS*2; i++) { circuit_build_times_network_circ_success(&estimate); circuit_build_times_add_time(&estimate, circuit_build_times_generate_sample(&estimate, 0, CBT_DEFAULT_QUANTILE_CUTOFF/100.0)); circuit_build_times_network_circ_success(&estimate); circuit_build_times_add_time(&final, circuit_build_times_generate_sample(&final, 0, CBT_DEFAULT_QUANTILE_CUTOFF/100.0)); } test_assert(!circuit_build_times_network_check_changed(&estimate)); test_assert(!circuit_build_times_network_check_changed(&final)); /* Reset liveness to be non-live */ final.liveness.network_last_live = 0; estimate.liveness.network_last_live = 0; build_times_idx = estimate.build_times_idx; total_build_times = estimate.total_build_times; test_assert(circuit_build_times_network_check_live(&estimate)); test_assert(circuit_build_times_network_check_live(&final)); circuit_build_times_count_close(&estimate, 0, (time_t)(approx_time()-estimate.close_ms/1000.0-1)); circuit_build_times_count_close(&final, 0, (time_t)(approx_time()-final.close_ms/1000.0-1)); test_assert(!circuit_build_times_network_check_live(&estimate)); test_assert(!circuit_build_times_network_check_live(&final)); log_info(LD_CIRC, "idx: %d %d, tot: %d %d", build_times_idx, estimate.build_times_idx, total_build_times, estimate.total_build_times); /* Check rollback index. Should match top of loop. */ test_assert(build_times_idx == estimate.build_times_idx); // This can fail if estimate.total_build_times == 1000, because // in that case, rewind actually causes us to lose timeouts if (total_build_times != CBT_NCIRCUITS_TO_OBSERVE) test_assert(total_build_times == estimate.total_build_times); /* Now simulate that the network has become live and we need * a change */ circuit_build_times_network_is_live(&estimate); circuit_build_times_network_is_live(&final); for (i = 0; i < CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT; i++) { circuit_build_times_count_timeout(&estimate, 1); if (i < CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT-1) { circuit_build_times_count_timeout(&final, 1); } } test_assert(estimate.liveness.after_firsthop_idx == 0); test_assert(final.liveness.after_firsthop_idx == CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT-1); test_assert(circuit_build_times_network_check_live(&estimate)); test_assert(circuit_build_times_network_check_live(&final)); circuit_build_times_count_timeout(&final, 1); } done: return; } /* Helper: assert that short_policy parses and writes back out as itself, or as expected if that's provided. */ static void test_short_policy_parse(const char *input, const char *expected) { short_policy_t *short_policy = NULL; char *out = NULL; if (expected == NULL) expected = input; short_policy = parse_short_policy(input); tt_assert(short_policy); out = write_short_policy(short_policy); tt_str_op(out, ==, expected); done: tor_free(out); short_policy_free(short_policy); } /** Helper: Parse the exit policy string in policy_str, and make sure * that policies_summarize() produces the string expected_summary from * it. */ static void test_policy_summary_helper(const char *policy_str, const char *expected_summary) { config_line_t line; smartlist_t *policy = smartlist_new(); char *summary = NULL; char *summary_after = NULL; int r; short_policy_t *short_policy = NULL; line.key = (char*)"foo"; line.value = (char *)policy_str; line.next = NULL; r = policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1); test_eq(r, 0); summary = policy_summarize(policy, AF_INET); test_assert(summary != NULL); test_streq(summary, expected_summary); short_policy = parse_short_policy(summary); tt_assert(short_policy); summary_after = write_short_policy(short_policy); test_streq(summary, summary_after); done: tor_free(summary_after); tor_free(summary); if (policy) addr_policy_list_free(policy); short_policy_free(short_policy); } /** Run unit tests for generating summary lines of exit policies */ static void test_policies(void) { int i; smartlist_t *policy = NULL, *policy2 = NULL, *policy3 = NULL, *policy4 = NULL, *policy5 = NULL, *policy6 = NULL, *policy7 = NULL; addr_policy_t *p; tor_addr_t tar; config_line_t line; smartlist_t *sm = NULL; char *policy_str = NULL; policy = smartlist_new(); p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); test_assert(p != NULL); test_eq(ADDR_POLICY_REJECT, p->policy_type); tor_addr_from_ipv4h(&tar, 0xc0a80000u); test_eq(0, tor_addr_compare(&p->addr, &tar, CMP_EXACT)); test_eq(16, p->maskbits); test_eq(1, p->prt_min); test_eq(65535, p->prt_max); smartlist_add(policy, p); tor_addr_from_ipv4h(&tar, 0x01020304u); test_assert(ADDR_POLICY_ACCEPTED == compare_tor_addr_to_addr_policy(&tar, 2, policy)); tor_addr_make_unspec(&tar); test_assert(ADDR_POLICY_PROBABLY_ACCEPTED == compare_tor_addr_to_addr_policy(&tar, 2, policy)); tor_addr_from_ipv4h(&tar, 0xc0a80102); test_assert(ADDR_POLICY_REJECTED == compare_tor_addr_to_addr_policy(&tar, 2, policy)); test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, NULL, 1)); test_assert(policy2); policy3 = smartlist_new(); p = router_parse_addr_policy_item_from_string("reject *:*",-1); test_assert(p != NULL); smartlist_add(policy3, p); p = router_parse_addr_policy_item_from_string("accept *:*",-1); test_assert(p != NULL); smartlist_add(policy3, p); policy4 = smartlist_new(); p = router_parse_addr_policy_item_from_string("accept *:443",-1); test_assert(p != NULL); smartlist_add(policy4, p); p = router_parse_addr_policy_item_from_string("accept *:443",-1); test_assert(p != NULL); smartlist_add(policy4, p); policy5 = smartlist_new(); p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("reject *:65535",-1); test_assert(p != NULL); smartlist_add(policy5, p); p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1); test_assert(p != NULL); smartlist_add(policy5, p); policy6 = smartlist_new(); p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1); test_assert(p != NULL); smartlist_add(policy6, p); policy7 = smartlist_new(); p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1); test_assert(p != NULL); smartlist_add(policy7, p); test_assert(!exit_policy_is_general_exit(policy)); test_assert(exit_policy_is_general_exit(policy2)); test_assert(!exit_policy_is_general_exit(NULL)); test_assert(!exit_policy_is_general_exit(policy3)); test_assert(!exit_policy_is_general_exit(policy4)); test_assert(!exit_policy_is_general_exit(policy5)); test_assert(!exit_policy_is_general_exit(policy6)); test_assert(!exit_policy_is_general_exit(policy7)); test_assert(cmp_addr_policies(policy, policy2)); test_assert(cmp_addr_policies(policy, NULL)); test_assert(!cmp_addr_policies(policy2, policy2)); test_assert(!cmp_addr_policies(NULL, NULL)); test_assert(!policy_is_reject_star(policy2, AF_INET)); test_assert(policy_is_reject_star(policy, AF_INET)); test_assert(policy_is_reject_star(NULL, AF_INET)); addr_policy_list_free(policy); policy = NULL; /* make sure compacting logic works. */ policy = NULL; line.key = (char*)"foo"; line.value = (char*)"accept *:80,reject private:*,reject *:*"; line.next = NULL; test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1)); test_assert(policy); //test_streq(policy->string, "accept *:80"); //test_streq(policy->next->string, "reject *:*"); test_eq(smartlist_len(policy), 4); /* test policy summaries */ /* check if we properly ignore private IP addresses */ test_policy_summary_helper("reject 192.168.0.0/16:*," "reject 0.0.0.0/8:*," "reject 10.0.0.0/8:*," "accept *:10-30," "accept *:90," "reject *:*", "accept 10-30,90"); /* check all accept policies, and proper counting of rejects */ test_policy_summary_helper("reject 11.0.0.0/9:80," "reject 12.0.0.0/9:80," "reject 13.0.0.0/9:80," "reject 14.0.0.0/9:80," "accept *:*", "accept 1-65535"); test_policy_summary_helper("reject 11.0.0.0/9:80," "reject 12.0.0.0/9:80," "reject 13.0.0.0/9:80," "reject 14.0.0.0/9:80," "reject 15.0.0.0:81," "accept *:*", "accept 1-65535"); test_policy_summary_helper("reject 11.0.0.0/9:80," "reject 12.0.0.0/9:80," "reject 13.0.0.0/9:80," "reject 14.0.0.0/9:80," "reject 15.0.0.0:80," "accept *:*", "reject 80"); /* no exits */ test_policy_summary_helper("accept 11.0.0.0/9:80," "reject *:*", "reject 1-65535"); /* port merging */ test_policy_summary_helper("accept *:80," "accept *:81," "accept *:100-110," "accept *:111," "reject *:*", "accept 80-81,100-111"); /* border ports */ test_policy_summary_helper("accept *:1," "accept *:3," "accept *:65535," "reject *:*", "accept 1,3,65535"); /* holes */ test_policy_summary_helper("accept *:1," "accept *:3," "accept *:5," "accept *:7," "reject *:*", "accept 1,3,5,7"); test_policy_summary_helper("reject *:1," "reject *:3," "reject *:5," "reject *:7," "accept *:*", "reject 1,3,5,7"); /* Short policies with unrecognized formats should get accepted. */ test_short_policy_parse("accept fred,2,3-5", "accept 2,3-5"); test_short_policy_parse("accept 2,fred,3", "accept 2,3"); test_short_policy_parse("accept 2,fred,3,bob", "accept 2,3"); test_short_policy_parse("accept 2,-3,500-600", "accept 2,500-600"); /* Short policies with nil entries are accepted too. */ test_short_policy_parse("accept 1,,3", "accept 1,3"); test_short_policy_parse("accept 100-200,,", "accept 100-200"); test_short_policy_parse("reject ,1-10,,,,30-40", "reject 1-10,30-40"); /* Try parsing various broken short policies */ tt_ptr_op(NULL, ==, parse_short_policy("accept 200-199")); tt_ptr_op(NULL, ==, parse_short_policy("")); tt_ptr_op(NULL, ==, parse_short_policy("rejekt 1,2,3")); tt_ptr_op(NULL, ==, parse_short_policy("reject ")); tt_ptr_op(NULL, ==, parse_short_policy("reject")); tt_ptr_op(NULL, ==, parse_short_policy("rej")); tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3,100000")); tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3x,4")); tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3x,4")); tt_ptr_op(NULL, ==, parse_short_policy("accept 2-")); tt_ptr_op(NULL, ==, parse_short_policy("accept 2-x")); tt_ptr_op(NULL, ==, parse_short_policy("accept 1-,3")); tt_ptr_op(NULL, ==, parse_short_policy("accept 1-,3")); /* Test a too-long policy. */ { int i; char *policy = NULL; smartlist_t *chunks = smartlist_new(); smartlist_add(chunks, tor_strdup("accept ")); for (i=1; i<10000; ++i) smartlist_add_asprintf(chunks, "%d,", i); smartlist_add(chunks, tor_strdup("20000")); policy = smartlist_join_strings(chunks, "", 0, NULL); SMARTLIST_FOREACH(chunks, char *, ch, tor_free(ch)); smartlist_free(chunks); tt_ptr_op(NULL, ==, parse_short_policy(policy));/* shouldn't be accepted */ tor_free(policy); /* could leak. */ } /* truncation ports */ sm = smartlist_new(); for (i=1; i<2000; i+=2) { char buf[POLICY_BUF_LEN]; tor_snprintf(buf, sizeof(buf), "reject *:%d", i); smartlist_add(sm, tor_strdup(buf)); } smartlist_add(sm, tor_strdup("accept *:*")); policy_str = smartlist_join_strings(sm, ",", 0, NULL); test_policy_summary_helper( policy_str, "accept 2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44," "46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90," "92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128," "130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164," "166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200," "202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236," "238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272," "274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308," "310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344," "346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380," "382,384,386,388,390,392,394,396,398,400,402,404,406,408,410,412,414,416," "418,420,422,424,426,428,430,432,434,436,438,440,442,444,446,448,450,452," "454,456,458,460,462,464,466,468,470,472,474,476,478,480,482,484,486,488," "490,492,494,496,498,500,502,504,506,508,510,512,514,516,518,520,522"); done: addr_policy_list_free(policy); addr_policy_list_free(policy2); addr_policy_list_free(policy3); addr_policy_list_free(policy4); addr_policy_list_free(policy5); addr_policy_list_free(policy6); addr_policy_list_free(policy7); tor_free(policy_str); if (sm) { SMARTLIST_FOREACH(sm, char *, s, tor_free(s)); smartlist_free(sm); } } /** Test encoding and parsing of rendezvous service descriptors. */ static void test_rend_fns(void) { rend_service_descriptor_t *generated = NULL, *parsed = NULL; char service_id[DIGEST_LEN]; char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1]; const char *next_desc; smartlist_t *descs = smartlist_new(); char computed_desc_id[DIGEST_LEN]; char parsed_desc_id[DIGEST_LEN]; crypto_pk_t *pk1 = NULL, *pk2 = NULL; time_t now; char *intro_points_encrypted = NULL; size_t intro_points_size; size_t encoded_size; int i; char address1[] = "fooaddress.onion"; char address2[] = "aaaaaaaaaaaaaaaa.onion"; char address3[] = "fooaddress.exit"; char address4[] = "www.torproject.org"; char address5[] = "foo.abcdefghijklmnop.onion"; char address6[] = "foo.bar.abcdefghijklmnop.onion"; char address7[] = ".abcdefghijklmnop.onion"; test_assert(BAD_HOSTNAME == parse_extended_hostname(address1)); test_assert(ONION_HOSTNAME == parse_extended_hostname(address2)); test_streq(address2, "aaaaaaaaaaaaaaaa"); test_assert(EXIT_HOSTNAME == parse_extended_hostname(address3)); test_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4)); test_assert(ONION_HOSTNAME == parse_extended_hostname(address5)); test_streq(address5, "abcdefghijklmnop"); test_assert(ONION_HOSTNAME == parse_extended_hostname(address6)); test_streq(address6, "abcdefghijklmnop"); test_assert(BAD_HOSTNAME == parse_extended_hostname(address7)); pk1 = pk_generate(0); pk2 = pk_generate(1); generated = tor_malloc_zero(sizeof(rend_service_descriptor_t)); generated->pk = crypto_pk_dup_key(pk1); crypto_pk_get_digest(generated->pk, service_id); base32_encode(service_id_base32, REND_SERVICE_ID_LEN_BASE32+1, service_id, REND_SERVICE_ID_LEN); now = time(NULL); generated->timestamp = now; generated->version = 2; generated->protocols = 42; generated->intro_nodes = smartlist_new(); for (i = 0; i < 3; i++) { rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t)); crypto_pk_t *okey = pk_generate(2 + i); intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); intro->extend_info->onion_key = okey; crypto_pk_get_digest(intro->extend_info->onion_key, intro->extend_info->identity_digest); //crypto_rand(info->identity_digest, DIGEST_LEN); /* Would this work? */ intro->extend_info->nickname[0] = '$'; base16_encode(intro->extend_info->nickname + 1, sizeof(intro->extend_info->nickname) - 1, intro->extend_info->identity_digest, DIGEST_LEN); /* Does not cover all IP addresses. */ tor_addr_from_ipv4h(&intro->extend_info->addr, crypto_rand_int(65536)); intro->extend_info->port = 1 + crypto_rand_int(65535); intro->intro_key = crypto_pk_dup_key(pk2); smartlist_add(generated->intro_nodes, intro); } test_assert(rend_encode_v2_descriptors(descs, generated, now, 0, REND_NO_AUTH, NULL, NULL) > 0); test_assert(rend_compute_v2_desc_id(computed_desc_id, service_id_base32, NULL, now, 0) == 0); test_memeq(((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0))->desc_id, computed_desc_id, DIGEST_LEN); test_assert(rend_parse_v2_service_descriptor(&parsed, parsed_desc_id, &intro_points_encrypted, &intro_points_size, &encoded_size, &next_desc, ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0))->desc_str) == 0); test_assert(parsed); test_memeq(((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0))->desc_id, parsed_desc_id, DIGEST_LEN); test_eq(rend_parse_introduction_points(parsed, intro_points_encrypted, intro_points_size), 3); test_assert(!crypto_pk_cmp_keys(generated->pk, parsed->pk)); test_eq(parsed->timestamp, now); test_eq(parsed->version, 2); test_eq(parsed->protocols, 42); test_eq(smartlist_len(parsed->intro_nodes), 3); for (i = 0; i < smartlist_len(parsed->intro_nodes); i++) { rend_intro_point_t *par_intro = smartlist_get(parsed->intro_nodes, i), *gen_intro = smartlist_get(generated->intro_nodes, i); extend_info_t *par_info = par_intro->extend_info; extend_info_t *gen_info = gen_intro->extend_info; test_assert(!crypto_pk_cmp_keys(gen_info->onion_key, par_info->onion_key)); test_memeq(gen_info->identity_digest, par_info->identity_digest, DIGEST_LEN); test_streq(gen_info->nickname, par_info->nickname); test_assert(tor_addr_eq(&gen_info->addr, &par_info->addr)); test_eq(gen_info->port, par_info->port); } rend_service_descriptor_free(parsed); rend_service_descriptor_free(generated); parsed = generated = NULL; done: if (descs) { for (i = 0; i < smartlist_len(descs); i++) rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i)); smartlist_free(descs); } if (parsed) rend_service_descriptor_free(parsed); if (generated) rend_service_descriptor_free(generated); if (pk1) crypto_pk_free(pk1); if (pk2) crypto_pk_free(pk2); tor_free(intro_points_encrypted); } /** Run unit tests for GeoIP code. */ static void test_geoip(void) { int i, j; time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ char *s = NULL, *v = NULL; const char *bridge_stats_1 = "bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n" "bridge-ips zz=24,xy=8\n" "bridge-ip-versions v4=16,v6=16\n", *dirreq_stats_1 = "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips ab=8\n" "dirreq-v3-reqs ab=8\n" "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", *dirreq_stats_2 = "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", *dirreq_stats_3 = "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n", *dirreq_stats_4 = "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n" "dirreq-v3-ips \n" "dirreq-v3-reqs \n" "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0," "not-modified=0,busy=0\n" "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n" "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n", *entry_stats_1 = "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n" "entry-ips ab=8\n", *entry_stats_2 = "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n" "entry-ips \n"; tor_addr_t addr; struct in6_addr in6; /* Populate the DB a bit. Add these in order, since we can't do the final * 'sort' step. These aren't very good IP addresses, but they're perfectly * fine uint32_t values. */ test_eq(0, geoip_parse_entry("10,50,AB", AF_INET)); test_eq(0, geoip_parse_entry("52,90,XY", AF_INET)); test_eq(0, geoip_parse_entry("95,100,AB", AF_INET)); test_eq(0, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET)); test_eq(0, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET)); test_eq(0, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET)); /* Populate the IPv6 DB equivalently with fake IPs in the same range */ test_eq(0, geoip_parse_entry("::a,::32,AB", AF_INET6)); test_eq(0, geoip_parse_entry("::34,::5a,XY", AF_INET6)); test_eq(0, geoip_parse_entry("::5f,::64,AB", AF_INET6)); test_eq(0, geoip_parse_entry("::69,::8c,ZZ", AF_INET6)); test_eq(0, geoip_parse_entry("::96,::be,XY", AF_INET6)); test_eq(0, geoip_parse_entry("::c8,::fa,AB", AF_INET6)); /* We should have 4 countries: ??, ab, xy, zz. */ test_eq(4, geoip_get_n_countries()); memset(&in6, 0, sizeof(in6)); /* Make sure that country ID actually works. */ #define SET_TEST_IPV6(i) \ do { \ set_uint32(in6.s6_addr + 12, htonl((uint32_t) (i))); \ } while (0) #define CHECK_COUNTRY(country, val) do { \ /* test ipv4 country lookup */ \ test_streq(country, \ geoip_get_country_name(geoip_get_country_by_ipv4(val))); \ /* test ipv6 country lookup */ \ SET_TEST_IPV6(val); \ test_streq(country, \ geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \ } while (0) CHECK_COUNTRY("??", 3); CHECK_COUNTRY("ab", 32); CHECK_COUNTRY("??", 5); CHECK_COUNTRY("??", 51); CHECK_COUNTRY("xy", 150); CHECK_COUNTRY("xy", 190); CHECK_COUNTRY("??", 2000); test_eq(0, geoip_get_country_by_ipv4(3)); SET_TEST_IPV6(3); test_eq(0, geoip_get_country_by_ipv6(&in6)); #undef CHECK_COUNTRY /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs * using ipv4. Since our fake geoip database is the same between * ipv4 and ipv6, we should get the same result no matter which * address family we pick for each IP. */ #define SET_TEST_ADDRESS(i) do { \ if ((i) & 1) { \ SET_TEST_IPV6(i); \ tor_addr_from_in6(&addr, &in6); \ } else { \ tor_addr_from_ipv4h(&addr, (uint32_t) i); \ } \ } while (0) get_options_mutable()->BridgeRelay = 1; get_options_mutable()->BridgeRecordUsageByCountry = 1; /* Put 9 observations in AB... */ for (i=32; i < 40; ++i) { SET_TEST_ADDRESS(i); geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200); } SET_TEST_ADDRESS(225); geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200); /* and 3 observations in XY, several times. */ for (j=0; j < 10; ++j) for (i=52; i < 55; ++i) { SET_TEST_ADDRESS(i); geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-3600); } /* and 17 observations in ZZ... */ for (i=110; i < 127; ++i) { SET_TEST_ADDRESS(i); geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now); } geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v); test_assert(s); test_assert(v); test_streq("zz=24,ab=16,xy=8", s); test_streq("v4=16,v6=16", v); tor_free(s); tor_free(v); /* Now clear out all the AB observations. */ geoip_remove_old_clients(now-6000); geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v); test_assert(s); test_assert(v); test_streq("zz=24,xy=8", s); test_streq("v4=16,v6=16", v); tor_free(s); tor_free(v); /* Start testing bridge statistics by making sure that we don't output * bridge stats without initializing them. */ s = geoip_format_bridge_stats(now + 86400); test_assert(!s); /* Initialize stats and generate the bridge-stats history string out of * the connecting clients added above. */ geoip_bridge_stats_init(now); s = geoip_format_bridge_stats(now + 86400); test_assert(s); test_streq(bridge_stats_1, s); tor_free(s); /* Stop collecting bridge stats and make sure we don't write a history * string anymore. */ geoip_bridge_stats_term(); s = geoip_format_bridge_stats(now + 86400); test_assert(!s); /* Stop being a bridge and start being a directory mirror that gathers * directory request statistics. */ geoip_bridge_stats_term(); get_options_mutable()->BridgeRelay = 0; get_options_mutable()->BridgeRecordUsageByCountry = 0; get_options_mutable()->DirReqStatistics = 1; /* Start testing dirreq statistics by making sure that we don't collect * dirreq stats without initializing them. */ SET_TEST_ADDRESS(100); geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now); s = geoip_format_dirreq_stats(now + 86400); test_assert(!s); /* Initialize stats, note one connecting client, and generate the * dirreq-stats history string. */ geoip_dirreq_stats_init(now); SET_TEST_ADDRESS(100); geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now); s = geoip_format_dirreq_stats(now + 86400); test_streq(dirreq_stats_1, s); tor_free(s); /* Stop collecting stats, add another connecting client, and ensure we * don't generate a history string. */ geoip_dirreq_stats_term(); SET_TEST_ADDRESS(101); geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now); s = geoip_format_dirreq_stats(now + 86400); test_assert(!s); /* Re-start stats, add a connecting client, reset stats, and make sure * that we get an all empty history string. */ geoip_dirreq_stats_init(now); SET_TEST_ADDRESS(100); geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now); geoip_reset_dirreq_stats(now); s = geoip_format_dirreq_stats(now + 86400); test_streq(dirreq_stats_2, s); tor_free(s); /* Note a successful network status response and make sure that it * appears in the history string. */ geoip_note_ns_response(GEOIP_SUCCESS); s = geoip_format_dirreq_stats(now + 86400); test_streq(dirreq_stats_3, s); tor_free(s); /* Start a tunneled directory request. */ geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED); s = geoip_format_dirreq_stats(now + 86400); test_streq(dirreq_stats_4, s); /* Stop collecting directory request statistics and start gathering * entry stats. */ geoip_dirreq_stats_term(); get_options_mutable()->DirReqStatistics = 0; get_options_mutable()->EntryStatistics = 1; /* Start testing entry statistics by making sure that we don't collect * anything without initializing entry stats. */ SET_TEST_ADDRESS(100); geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now); s = geoip_format_entry_stats(now + 86400); test_assert(!s); /* Initialize stats, note one connecting client, and generate the * entry-stats history string. */ geoip_entry_stats_init(now); SET_TEST_ADDRESS(100); geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now); s = geoip_format_entry_stats(now + 86400); test_streq(entry_stats_1, s); tor_free(s); /* Stop collecting stats, add another connecting client, and ensure we * don't generate a history string. */ geoip_entry_stats_term(); SET_TEST_ADDRESS(101); geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now); s = geoip_format_entry_stats(now + 86400); test_assert(!s); /* Re-start stats, add a connecting client, reset stats, and make sure * that we get an all empty history string. */ geoip_entry_stats_init(now); SET_TEST_ADDRESS(100); geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now); geoip_reset_entry_stats(now); s = geoip_format_entry_stats(now + 86400); test_streq(entry_stats_2, s); tor_free(s); #undef SET_TEST_ADDRESS #undef SET_TEST_IPV6 /* Stop collecting entry statistics. */ geoip_entry_stats_term(); get_options_mutable()->EntryStatistics = 0; done: tor_free(s); tor_free(v); } /** Run unit tests for stats code. */ static void test_stats(void) { time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ char *s = NULL; int i; /* Start with testing exit port statistics; we shouldn't collect exit * stats without initializing them. */ rep_hist_note_exit_stream_opened(80); rep_hist_note_exit_bytes(80, 100, 10000); s = rep_hist_format_exit_stats(now + 86400); test_assert(!s); /* Initialize stats, note some streams and bytes, and generate history * string. */ rep_hist_exit_stats_init(now); rep_hist_note_exit_stream_opened(80); rep_hist_note_exit_bytes(80, 100, 10000); rep_hist_note_exit_stream_opened(443); rep_hist_note_exit_bytes(443, 100, 10000); rep_hist_note_exit_bytes(443, 100, 10000); s = rep_hist_format_exit_stats(now + 86400); test_streq("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n" "exit-kibibytes-written 80=1,443=1,other=0\n" "exit-kibibytes-read 80=10,443=20,other=0\n" "exit-streams-opened 80=4,443=4,other=0\n", s); tor_free(s); /* Add a few bytes on 10 more ports and ensure that only the top 10 * ports are contained in the history string. */ for (i = 50; i < 60; i++) { rep_hist_note_exit_bytes(i, i, i); rep_hist_note_exit_stream_opened(i); } s = rep_hist_format_exit_stats(now + 86400); test_streq("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n" "exit-kibibytes-written 52=1,53=1,54=1,55=1,56=1,57=1,58=1," "59=1,80=1,443=1,other=1\n" "exit-kibibytes-read 52=1,53=1,54=1,55=1,56=1,57=1,58=1," "59=1,80=10,443=20,other=1\n" "exit-streams-opened 52=4,53=4,54=4,55=4,56=4,57=4,58=4," "59=4,80=4,443=4,other=4\n", s); tor_free(s); /* Stop collecting stats, add some bytes, and ensure we don't generate * a history string. */ rep_hist_exit_stats_term(); rep_hist_note_exit_bytes(80, 100, 10000); s = rep_hist_format_exit_stats(now + 86400); test_assert(!s); /* Re-start stats, add some bytes, reset stats, and see what history we * get when observing no streams or bytes at all. */ rep_hist_exit_stats_init(now); rep_hist_note_exit_stream_opened(80); rep_hist_note_exit_bytes(80, 100, 10000); rep_hist_reset_exit_stats(now); s = rep_hist_format_exit_stats(now + 86400); test_streq("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n" "exit-kibibytes-written other=0\n" "exit-kibibytes-read other=0\n" "exit-streams-opened other=0\n", s); tor_free(s); /* Continue with testing connection statistics; we shouldn't collect * conn stats without initializing them. */ rep_hist_note_or_conn_bytes(1, 20, 400, now); s = rep_hist_format_conn_stats(now + 86400); test_assert(!s); /* Initialize stats, note bytes, and generate history string. */ rep_hist_conn_stats_init(now); rep_hist_note_or_conn_bytes(1, 30000, 400000, now); rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5); rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10); rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15); s = rep_hist_format_conn_stats(now + 86400); test_streq("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n", s); tor_free(s); /* Stop collecting stats, add some bytes, and ensure we don't generate * a history string. */ rep_hist_conn_stats_term(); rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15); s = rep_hist_format_conn_stats(now + 86400); test_assert(!s); /* Re-start stats, add some bytes, reset stats, and see what history we * get when observing no bytes at all. */ rep_hist_conn_stats_init(now); rep_hist_note_or_conn_bytes(1, 30000, 400000, now); rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5); rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10); rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15); rep_hist_reset_conn_stats(now); s = rep_hist_format_conn_stats(now + 86400); test_streq("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n", s); tor_free(s); /* Continue with testing buffer statistics; we shouldn't collect buffer * stats without initializing them. */ rep_hist_add_buffer_stats(2.0, 2.0, 20); s = rep_hist_format_buffer_stats(now + 86400); test_assert(!s); /* Initialize stats, add statistics for a single circuit, and generate * the history string. */ rep_hist_buffer_stats_init(now); rep_hist_add_buffer_stats(2.0, 2.0, 20); s = rep_hist_format_buffer_stats(now + 86400); test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n" "cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n" "cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00," "0.00,0.00\n" "cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n" "cell-circuits-per-decile 1\n", s); tor_free(s); /* Add nineteen more circuit statistics to the one that's already in the * history to see that the math works correctly. */ for (i = 21; i < 30; i++) rep_hist_add_buffer_stats(2.0, 2.0, i); for (i = 20; i < 30; i++) rep_hist_add_buffer_stats(3.5, 3.5, i); s = rep_hist_format_buffer_stats(now + 86400); test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n" "cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n" "cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75," "2.75,2.75\n" "cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n" "cell-circuits-per-decile 2\n", s); tor_free(s); /* Stop collecting stats, add statistics for one circuit, and ensure we * don't generate a history string. */ rep_hist_buffer_stats_term(); rep_hist_add_buffer_stats(2.0, 2.0, 20); s = rep_hist_format_buffer_stats(now + 86400); test_assert(!s); /* Re-start stats, add statistics for one circuit, reset stats, and make * sure that the history has all zeros. */ rep_hist_buffer_stats_init(now); rep_hist_add_buffer_stats(2.0, 2.0, 20); rep_hist_reset_buffer_stats(now); s = rep_hist_format_buffer_stats(now + 86400); test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n" "cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n" "cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00," "0.00,0.00\n" "cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n" "cell-circuits-per-decile 0\n", s); done: tor_free(s); } static void * legacy_test_setup(const struct testcase_t *testcase) { return testcase->setup_data; } void legacy_test_helper(void *data) { void (*fn)(void) = data; fn(); } static int legacy_test_cleanup(const struct testcase_t *testcase, void *ptr) { (void)ptr; (void)testcase; return 1; } const struct testcase_setup_t legacy_setup = { legacy_test_setup, legacy_test_cleanup }; #define ENT(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_ ## name } #define FORK(name) \ { #name, legacy_test_helper, TT_FORK, &legacy_setup, test_ ## name } static struct testcase_t test_array[] = { ENT(buffers), { "buffer_copy", test_buffer_copy, 0, NULL, NULL }, ENT(onion_handshake), ENT(onion_queues), #ifdef CURVE25519_ENABLED { "ntor_handshake", test_ntor_handshake, 0, NULL, NULL }, #endif ENT(circuit_timeout), ENT(policies), ENT(rend_fns), ENT(geoip), FORK(stats), END_OF_TESTCASES }; #define SOCKSENT(name) \ { #name, test_socks_##name, TT_FORK, &socks_setup, NULL } static struct testcase_t socks_tests[] = { SOCKSENT(4_unsupported_commands), SOCKSENT(4_supported_commands), SOCKSENT(5_unsupported_commands), SOCKSENT(5_supported_commands), SOCKSENT(5_no_authenticate), SOCKSENT(5_auth_before_negotiation), SOCKSENT(5_authenticate), SOCKSENT(5_authenticate_with_data), END_OF_TESTCASES }; extern struct testcase_t addr_tests[]; extern struct testcase_t crypto_tests[]; extern struct testcase_t container_tests[]; extern struct testcase_t util_tests[]; extern struct testcase_t dir_tests[]; extern struct testcase_t microdesc_tests[]; extern struct testcase_t pt_tests[]; extern struct testcase_t config_tests[]; extern struct testcase_t introduce_tests[]; extern struct testcase_t replaycache_tests[]; extern struct testcase_t cell_format_tests[]; static struct testgroup_t testgroups[] = { { "", test_array }, { "socks/", socks_tests }, { "addr/", addr_tests }, { "crypto/", crypto_tests }, { "container/", container_tests }, { "util/", util_tests }, { "cellfmt/", cell_format_tests }, { "dir/", dir_tests }, { "dir/md/", microdesc_tests }, { "pt/", pt_tests }, { "config/", config_tests }, { "replaycache/", replaycache_tests }, { "introduce/", introduce_tests }, END_OF_GROUPS }; /** Main entry point for unit test code: parse the command line, and run * some unit tests. */ int main(int c, const char **v) { or_options_t *options; char *errmsg = NULL; int i, i_out; int loglevel = LOG_ERR; #ifdef USE_DMALLOC { int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_); tor_assert(r); } #endif update_approx_time(time(NULL)); options = options_new(); tor_threads_init(); init_logging(); for (i_out = i = 1; i < c; ++i) { if (!strcmp(v[i], "--warn")) { loglevel = LOG_WARN; } else if (!strcmp(v[i], "--notice")) { loglevel = LOG_NOTICE; } else if (!strcmp(v[i], "--info")) { loglevel = LOG_INFO; } else if (!strcmp(v[i], "--debug")) { loglevel = LOG_DEBUG; } else { v[i_out++] = v[i]; } } c = i_out; { log_severity_list_t s; memset(&s, 0, sizeof(s)); set_log_severity_config(loglevel, LOG_ERR, &s); add_stream_log(&s, "", fileno(stdout)); } options->command = CMD_RUN_UNITTESTS; if (crypto_global_init(0, NULL, NULL)) { printf("Can't initialize crypto subsystem; exiting.\n"); return 1; } crypto_set_tls_dh_prime(NULL); crypto_seed_rng(1); rep_hist_init(); network_init(); setup_directory(); options_init(options); options->DataDirectory = tor_strdup(temp_dir); options->EntryStatistics = 1; if (set_options(options, &errmsg) < 0) { printf("Failed to set initial options: %s\n", errmsg); tor_free(errmsg); return 1; } atexit(remove_directory); have_failed = (tinytest_main(c, v, testgroups) != 0); free_pregenerated_keys(); #ifdef USE_DMALLOC tor_free_all(0); dmalloc_log_unfreed(); #endif if (have_failed) return 1; else return 0; } tor-0.2.4.20/src/test/test_data.c0000644000175000017500000002175012255745673013371 00000000000000/* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** First of 3 example authority certificates for unit testing. */ const char AUTHORITY_CERT_1[] = "dir-key-certificate-version 3\n" "fingerprint D867ACF56A9D229B35C25F0090BC9867E906BE69\n" "dir-key-published 2008-12-12 18:07:24\n" "dir-key-expires 2009-12-12 18:07:24\n" "dir-identity-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIIBigKCAYEAveMpKlw8oD1YqFqpJchuwSR82BDhutbqgHiez3QO9FmzOctJpV+Y\n" "mpTYIJLS/qC+4GBKFF1VK0C4SoBrS3zri0qdXdE+vBGcyrxrjMklpxoqSKRY2011\n" "4eqYPghKlo5RzuqteBclGCHyNxWjUJeRKDWgvh+U/gr2uYM6fRm5q0fCzg4aECE7\n" "VP6fDGZrMbQI8jHpiMSoC9gkUASNEa6chLInlnP8/H5qUEW4TB9CN/q095pefuwL\n" "P+F+1Nz5hnM7fa5XmeMB8iM4RriUmOQlLBZgpQBMpEfWMIPcR9F1Gh3MxERqqUcH\n" "tmij+IZdeXg9OkCXykcabaYIhZD3meErn9Tax4oA/THduLfgli9zM0ExwzH1OooN\n" "L8rIcJ+2eBo3bQiQUbdYW71sl9w7nSPtircbJUa1mUvWYLPWQxFliPiQSetgJLMj\n" "VQqtPmV2hvN2Xk3lLfJO50qMTK7w7Gsaw8UtV4YDM1Hcjp/hQaIB1xfwhXgl+eUU\n" "btUa4c+cUTjHAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "dir-signing-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBALPSUInyuEu6NV3NjozplaniIEBzQXEjv1x9/+mqnwZABpYVmuy9A8nx\n" "eoyY3sZFsnYwNW/IZjAgG23pEmevu3F+L4myMjjaa6ORl3MgRYQ4gmuFqpefrGdm\n" "ywRCleh2JerkQ4VxOuq10dn/abITzLyaZzMw30KXWp5pxKXOLtxFAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "dir-key-crosscert\n" "-----BEGIN ID SIGNATURE-----\n" "FTBJNR/Hlt4T53yUMp1r/QCSMCpkHJCbYBT0R0pvYqhqFfYN5qHRSICRXaFFImIF\n" "0DGWmwRza6DxPKNzkm5/b7I0de9zJW1jNNdQAQK5xppAtQcAafRdu8cBonnmh9KX\n" "k1NrAK/X00FYywju3yl/SxCn1GddVNkHYexEudmJMPM=\n" "-----END ID SIGNATURE-----\n" "dir-key-certification\n" "-----BEGIN SIGNATURE-----\n" "pjWguLFBfELZDc6DywL6Do21SCl7LcutfpM92MEn4WYeSNcTXNR6lRX7reOEJk4e\n" "NwEaMt+Hl7slgeR5wjnW3OmMmRPZK9bquNWbfD+sAOV9bRFZTpXIdleAQFPlwvMF\n" "z/Gzwspzn4i2Yh6hySShrctMmW8YL3OM8LsBXzBhp/rG2uHlsxmIsc13DA6HWt61\n" "ffY72uNE6KckDGsQ4wPGP9q69y6g+X+TNio1KPbsILbePv6EjbO+rS8FiS4njPlg\n" "SPYry1RaUvxzxTkswIzdE1tjJrUiqpbWlTGxrH9N4OszoLm45Pc784KLULrjKIoi\n" "Q+vRsGrcMBAa+kDowWU6H1ryKR7KOhzRTcf2uqLE/W3ezaRwmOG+ETmoVFwbhk2X\n" "OlbXEM9fWP+INvFkr6Z93VYL2jGkCjV7e3xXmre/Lb92fUcYi6t5dwzfV8gJnIoG\n" "eCHd0K8NrQK0ipVk/7zcPDKOPeo9Y5aj/f6X/pDHtb+Dd5sT+l82G/Tqy4DIYUYR\n" "-----END SIGNATURE-----\n"; /** The private signing key for AUTHORITY_CERT_1 */ const char AUTHORITY_SIGNKEY_1[] = "-----BEGIN RSA PRIVATE KEY-----\n" "MIICWwIBAAKBgQCz0lCJ8rhLujVdzY6M6ZWp4iBAc0FxI79cff/pqp8GQAaWFZrs\n" "vQPJ8XqMmN7GRbJ2MDVvyGYwIBtt6RJnr7txfi+JsjI42mujkZdzIEWEOIJrhaqX\n" "n6xnZssEQpXodiXq5EOFcTrqtdHZ/2myE8y8mmczMN9Cl1qeacSlzi7cRQIDAQAB\n" "AoGASpzUkDinIbzU0eQt5ugxEnliOnvYRpK3nzAk1JbYPyan1PSIAPz4qn1JBTeV\n" "EB3xS7r7ITO8uvFHkFZqLZ2sH1uE6e4sAytJGO+kyqnlkiDTPEXpcGe99j8PH1yj\n" "xUOrHRlAYWjG8NEkQi+APA+HZkswE3L/viFwR2AARoE2ac0CQQDsOLdNJa+mqn6N\n" "1L76nEl/YgXHtKUks+beOR3IgknKEjcsJJEUHyiu0wjbXZV6gTtyQvcAePglUUD1\n" "R2OkOOADAkEAwuCxvHEAPeQbVt8fSvxw74vqew6LITP2Utb1dQK0E26IRPF36BsJ\n" "buO/gqMZv6ALq+/KxpA/pUsApbgog9uUFwJAYvHCvbrKX1pM1iXFtP1fv86UMzlU\n" "bxI34t8zvXftZonIuGG8rxv6E3hr3k7NvNmCx/KKuZTyA9eMCPFVKEV2dwJACn8j\n" "06yagLrqphE6lEVop953cM1lvRIZcHjXm8fbfzhy6pO/C6d5KJnn1NeIKYQrXMV7\n" "vJpEc1jI3iQ/Omr3XQJAEBIt5MlP2wlrX9om7B+32XBygUssY3cw/bXybZrtSU0/\n" "Yx4lqK0ca5IkTp3HevwnlWaJgbaOTUspCVshzJBhDA==\n" "-----END RSA PRIVATE KEY-----\n"; /** Second of 3 example authority certificates for unit testing. */ const char AUTHORITY_CERT_2[] = "dir-key-certificate-version 3\n" "fingerprint 4D44AE0470B9E88FD4558EFEC82698FB33715400\n" "dir-key-published 2007-06-13 16:52:32\n" "dir-key-expires 2008-06-13 16:52:32\n" "dir-identity-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIIBigKCAYEAqukDwQRm1Oy1pPY+7GNRnRNFJzEVPUBfJwC4tBH19tkvdRQPuIGI\n" "2jiTy/rmZ6CLcl1G0oulSgxfKEX75QdptOasZu+rKUrRRSxx0QrXhs9a7up0rpXh\n" "13fw3mh1Vl/As3rJYF30Hjk01BTOJMxi/HY2y0ALQytFWjiMGY74A9Y6+uDcHkB2\n" "KflBjxIl8zpCsXsTTnUhN5kXqaOOnK46XaUShSpXsyOxTMJXuJEtgLz9XCyA8XjW\n" "d75QLHucEnlTqxUAdI5YSN2KIlIJiySCVnAorDpJey2mE9VncpHQWMCv/FPFdnSU\n" "EMMPUc4bBShcoNFf0mMJeV2sv+dBkgKAL0GLM19PuJIThJhfN/B6+YQTxw4HEpPV\n" "plfUqYRN0fYC+5hCTS6rroO/uCfDR7NBtoeDNm9dQrvjfk3b/Mywah1rdWNjnVqs\n" "tPJaz3fc/CVBOUUexhmyktgLuwSNEYIQilQ+BydkWN/4RObhV+YSV5BgekEDVaoS\n" "RHw4IbYBDHVxAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "dir-signing-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAOu3dgrQth3iqvi/UzfywaANw0bBUuMOBhnMBeiLEcRLneJHUJkVvrpR\n" "/EDQkdMov1e7CX6aqBKygVnbDNYjJ+bcQej8MKpuuW+zIknnz5lfnAVZO5uAmo3Y\n" "DpG574oQ2FFMdkWHSBloIRxSj/E4Jn1M2qJjElBXP0E33Ka/Noo7AgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "dir-key-certification\n" "-----BEGIN SIGNATURE-----\n" "Fv0Li68QUdAiChY3OklZOakHzwXAUfCzDNxkqe+HLC0n6ZECE9ZCvLVo69XmgVhH\n" "L5qYr2rxT6QpF+9yuOHbN9gWn8EsDcli06MlhX9TUt/IYVxHa/9tJwNoTfEw2w2D\n" "tyHhWm94IfOK7/Sea6jHnjckl80X+kk0ZNtAGs3/6fP4iltKNGXnvBwfgLpEgW7X\n" "NpDl0OLeDuA79zem2GogwQZQdoDbePByU0TJVx9jYi2Bzx2Nb2H0hRTPP6+dY0HQ\n" "MHb7yyyTQRad5iAUnExKhhyt22p7X3a6lgkAhq4YrNn/zVPkpnT2dzjsOydTHOW8\n" "2BQs33QlGNe095i47pJBDYsUgmJaXfqB/RG6dFg7jwIsc3/7dZcvcqfxY7wKcD/T\n" "wtogCIKxDvWbZn7f0hqYkT6uQC8Zom8bcnedmyzufOZCyA2SqQ2wvio6lznR4RIB\n" "a8qDHR0tPS9/VkqTPcvUWCZeY3UiDeWPjoK1nea1pz6DHDWglKPx86a0amjjayZQ\n" "-----END SIGNATURE-----\n"; /** The private signing key for AUTHORITY_CERT_2 */ const char AUTHORITY_SIGNKEY_2[] = "-----BEGIN RSA PRIVATE KEY-----\n" "MIICXgIBAAKBgQDrt3YK0LYd4qr4v1M38sGgDcNGwVLjDgYZzAXoixHES53iR1CZ\n" "Fb66UfxA0JHTKL9Xuwl+mqgSsoFZ2wzWIyfm3EHo/DCqbrlvsyJJ58+ZX5wFWTub\n" "gJqN2A6Rue+KENhRTHZFh0gZaCEcUo/xOCZ9TNqiYxJQVz9BN9ymvzaKOwIDAQAB\n" "AoGAJ+I9/ex8tCfTSA2PdisEKiHKBeHWNYb870Z/RW6qje1BhLUOZSixwfL3XLwt\n" "wG3nml+SZrKid69uhZaz4FPIf0tqCgURf6dDrF5vuzzr7VLVqkZHYSBp0vE6bu0R\n" "Sgc5QNxI2talgc4bsp0O0C+Zd4n3Yto0pXl/I6NHVAxlFBECQQD2mahkY+QEHWPV\n" "yRY3w3HhRmWBcrkY2zVyvPpqfn/sdHRPYW/yj4Xr/d1CO9VyFmEs4k324lIvu6LT\n" "WDdpPlcJAkEA9LOZv5aNeAm8ckvvXH7iv8KiONiSz0n9wlisxMhNYTEkOCo1g7jG\n" "AX5ZknRC9s4sWCPOBpMhloUvemdQ5FCEIwJBAMqCFwoSCf7jD8hRcUBr7QodoF/0\n" "kVJ7OeI2lMJ9jZnlbFp/3snn2Qeam2e38SnWfQi582KKKwnt4eIDMMXpntkCQQDI\n" "v1Lh11wl3y7nQZ6T7lCNatp08k+2mQgCWYcbRQweMRd6sD4I2xwt+372ZETPfyLo\n" "CC+sOyYx+v+RVpMJS3irAkEA6l98nMteZKmhOgyKSjdolP+ahpZunb+WnCdAtP97\n" "rjZyXmEZS3oe7TRCDD28GAGMmxSDvNfOOpyn14ishEs5AQ==\n" "-----END RSA PRIVATE KEY-----\n"; /** Third of 3 example authority certificates for unit testing. */ const char AUTHORITY_CERT_3[] = "dir-key-certificate-version 3\n" "fingerprint ED3719BF554DE9D7D59F5CA5A4F5AD121D020ED9\n" "dir-key-published 2007-06-13 16:52:40\n" "dir-key-expires 2008-06-13 16:52:40\n" "dir-identity-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIIBigKCAYEAtB+yw4BNxtZAG4cPaedkhWNmeij7IuNWmXjh58ZYEGurvGyHs1w4\n" "QlwNYI2UftSIeIGdWZ5fJ17h9P3xvO6eeJuOt4KPrNOxUbSGrELEx1Lje1fDAJ1X\n" "SvN+dvptusxtyFUr8afgTPrFIvYuazQ6q/Rw+NDagjmDx3h/A/enihpBnjwzeH8j\n" "Xzu7b+HKnzFnNfveTDdvSy0NSC6tCOnrfXo31XbXRXtlesnMIpbJClUcAv55eyai\n" "/PrVPCCUz8mk0sQnn2Xhv1YJmwOlQTGMfg0a0kWLmh+UWcHsGQ4VWxBZJcuzgFHG\n" "hu2/Fz6DXSpX5Q6B9HKoGmnH1oBh24l0kUW1jL8BxPY4YDU1Lt5t3qgcDn9dXYcI\n" "o8VvyI0ecSc26Q2PYFWX1hpN4VIBZ8uGaW3IpyTdNiRq0g3iMGRFEXcDlWuyMB9E\n" "EbSM7m/79V/z7SjDd75EP8Z0qDPESEVB8a8LbuSJtzFVE0KHd7RzkIEN5sorXspZ\n" "/THukftSmkIvAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "dir-signing-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBANrSZlUq38Boz3iuUOydYTJV57rTbq1bz805FP2QG2Z+2bwpgKIOZag/\n" "gN2A1ySJaIYLgZIg9irxrLkqlY/UAjC23y6V9fJXP1S3TXoqLmHleW8PsaDLuwTo\n" "hCWaR61Mx9WG7IXcodn2Z7RiCfZpSW4Rztbk5WtjQa5jPXSFOuBJAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "dir-key-certification\n" "-----BEGIN SIGNATURE-----\n" "UNXZy+4OQ8iat+gw+vg2ynvKj2BYbqZt+EAZAV3rmw6gux44U9TLRECRd6LsA08N\n" "4+Vz01TU81xqMgfrUy94ei2YvcfpO8art9/muWHTP9SmOX8S1uqDqLWA+n723C9A\n" "HyVXn4aINncO2081gJcIW5+Ul8WTCeZe/n3LVPTCKbTdqxvmrPUdCWlJTQUmb19M\n" "T+kcCjaEfgQGLC+Y2MHqYe/nxz+aBKqpjiWUDdjc35va6r/2e3c0jGi1B1xRZxN1\n" "xThPZ+CifjDoWBxJdDGlIfZRK1lMnOCJY9w9ibTXQ1UnvE4whFvmB55/t9/XLq4q\n" "3pnZz0H7funey3+ilmTxDohoAYT1GX+4a+3xYH07UmAFqlTzqKClj84XEHn+Cer7\n" "Nun9kJlJFuBgUpQjwCkzedFZKKLOHgB2h7trJfnqcBpAM8Rup1Bb5u/RcBx9gy1q\n" "pMc65FviIrc/Q5TUku6NNbCbnGll1599PvWuUzkG42lJ17V6psKHIsqGtVdHlCUc\n" "-----END SIGNATURE-----\n"; /** The private signing key for AUTHORITY_CERT_3 */ const char AUTHORITY_SIGNKEY_3[] = "-----BEGIN RSA PRIVATE KEY-----\n" "MIICXgIBAAKBgQDa0mZVKt/AaM94rlDsnWEyVee6026tW8/NORT9kBtmftm8KYCi\n" "DmWoP4DdgNckiWiGC4GSIPYq8ay5KpWP1AIwtt8ulfXyVz9Ut016Ki5h5XlvD7Gg\n" "y7sE6IQlmketTMfVhuyF3KHZ9me0Ygn2aUluEc7W5OVrY0GuYz10hTrgSQIDAQAB\n" "AoGBAIyoeG1AnQmildKeQpiGZackf0uhg2BeRwpFKg//5Q0Sd0Wza+M/2+q1v1Ei\n" "86ihxxV7KfPTykk6hmuUSwVkI28Z+5J9NYTr35EzPiUlqpo0iclTkFqrlbqSPULx\n" "9fQhvcOGv1c0m5CnYrHsM8eu3tagLg+6OE4abLOYX4Az5pkxAkEA/NwHhVaVJrXH\n" "lGDrRAfGtaD5Tzeeg1H9DNZi5lmFiSNR0O11sgDLkiZNP5oM8knyqo8Gq08hwxEb\n" "yqMXM3XtJQJBAN2KJbFhOjDIkvJyYvbmcP6P7vV2c9j+oUTKkFMF7vvfWunxMi9j\n" "ghbdUKgl7tU0VFpw7ufDDD0pkN6sua3gp1UCQQCvNzTK861U7p/GtMYyFQVf9JTt\n" "jMf9jYHBNInBvwTme6AFG5bz6tMlif77dJ9GAXHzODrR2Hq3thJA/3RjR3M1AkBg\n" "+6M4ncmtpYC+5lhwob0Bk90WU/6vFflfdhXsYoKWfNb95vsDR9qhS82Nbt25NClh\n" "VmMfzoFDHTkwYgj/F4PpAkEA+RaaSRP7BmbvFNqvlm8J/m0RVdAH4+p/Q5Z5u6Yo\n" "N7xC/gFi0qFPGKsDvD2CncAYmt+KNsd8S0JGDN4eieKn+Q==\n" "-----END RSA PRIVATE KEY-----\n"; tor-0.2.4.20/src/test/test_cell_formats.c0000644000175000017500000010012412166113000015071 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CONNECTION_EDGE_PRIVATE #define RELAY_PRIVATE #include "or.h" #include "connection_edge.h" #include "onion.h" #include "onion_tap.h" #include "onion_fast.h" #include "onion_ntor.h" #include "relay.h" #include "test.h" #include #include static void test_cfmt_relay_header(void *arg) { relay_header_t rh; const uint8_t hdr_1[RELAY_HEADER_SIZE] = "\x03" "\x00\x00" "\x21\x22" "ABCD" "\x01\x03"; uint8_t hdr_out[RELAY_HEADER_SIZE]; (void)arg; tt_int_op(sizeof(hdr_1), ==, RELAY_HEADER_SIZE); relay_header_unpack(&rh, hdr_1); tt_int_op(rh.command, ==, 3); tt_int_op(rh.recognized, ==, 0); tt_int_op(rh.stream_id, ==, 0x2122); test_mem_op(rh.integrity, ==, "ABCD", 4); tt_int_op(rh.length, ==, 0x103); relay_header_pack(hdr_out, &rh); test_mem_op(hdr_out, ==, hdr_1, RELAY_HEADER_SIZE); done: ; } static void make_relay_cell(cell_t *out, uint8_t command, const void *body, size_t bodylen) { relay_header_t rh; memset(&rh, 0, sizeof(rh)); rh.stream_id = 5; rh.command = command; rh.length = bodylen; out->command = CELL_RELAY; out->circ_id = 10; relay_header_pack(out->payload, &rh); memcpy(out->payload + RELAY_HEADER_SIZE, body, bodylen); } static void test_cfmt_begin_cells(void *arg) { cell_t cell; begin_cell_t bcell; uint8_t end_reason; (void)arg; /* Try begindir. */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "", 0); tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_ptr_op(NULL, ==, bcell.address); tt_int_op(0, ==, bcell.flags); tt_int_op(0, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(1, ==, bcell.is_begindir); /* A Begindir with extra stuff. */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "12345", 5); tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_ptr_op(NULL, ==, bcell.address); tt_int_op(0, ==, bcell.flags); tt_int_op(0, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(1, ==, bcell.is_begindir); /* A short but valid begin cell */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:9", 6); tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_str_op("a.b", ==, bcell.address); tt_int_op(0, ==, bcell.flags); tt_int_op(9, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(0, ==, bcell.is_begindir); tor_free(bcell.address); /* A significantly loner begin cell */ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "here-is-a-nice-long.hostname.com:65535"; make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, strlen(c)+1); } tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_str_op("here-is-a-nice-long.hostname.com", ==, bcell.address); tt_int_op(0, ==, bcell.flags); tt_int_op(65535, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(0, ==, bcell.is_begindir); tor_free(bcell.address); /* An IPv4 begin cell. */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15); tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_str_op("18.9.22.169", ==, bcell.address); tt_int_op(0, ==, bcell.flags); tt_int_op(80, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(0, ==, bcell.is_begindir); tor_free(bcell.address); /* An IPv6 begin cell. Let's make sure we handle colons*/ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "[2620::6b0:b:1a1a:0:26e5:480e]:80", 34); tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", ==, bcell.address); tt_int_op(0, ==, bcell.flags); tt_int_op(80, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(0, ==, bcell.is_begindir); tor_free(bcell.address); /* a begin cell with extra junk but not enough for flags. */ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "another.example.com:80\x00\x01\x02"; make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); } tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_str_op("another.example.com", ==, bcell.address); tt_int_op(0, ==, bcell.flags); tt_int_op(80, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(0, ==, bcell.is_begindir); tor_free(bcell.address); /* a begin cell with flags. */ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "another.example.com:443\x00\x01\x02\x03\x04"; make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); } tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_str_op("another.example.com", ==, bcell.address); tt_int_op(0x1020304, ==, bcell.flags); tt_int_op(443, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(0, ==, bcell.is_begindir); tor_free(bcell.address); /* a begin cell with flags and even more cruft after that. */ memset(&bcell, 0x7f, sizeof(bcell)); { const char c[] = "a-further.example.com:22\x00\xee\xaa\x00\xffHi mom"; make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1); } tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason)); tt_str_op("a-further.example.com", ==, bcell.address); tt_int_op(0xeeaa00ff, ==, bcell.flags); tt_int_op(22, ==, bcell.port); tt_int_op(5, ==, bcell.stream_id); tt_int_op(0, ==, bcell.is_begindir); tor_free(bcell.address); /* bad begin cell: impossible length. */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 7); cell.payload[9] = 0x01; /* Set length to 510 */ cell.payload[10] = 0xfe; { relay_header_t rh; relay_header_unpack(&rh, cell.payload); tt_int_op(rh.length, ==, 510); } tt_int_op(-2, ==, begin_cell_parse(&cell, &bcell, &end_reason)); /* Bad begin cell: no body. */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0); tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); /* bad begin cell: no body. */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0); tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); /* bad begin cell: no colon */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b", 4); tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); /* bad begin cell: no ports */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:", 5); tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); /* bad begin cell: bad port */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:xyz", 8); tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:100000", 11); tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); /* bad begin cell: no nul */ memset(&bcell, 0x7f, sizeof(bcell)); make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 6); tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason)); done: tor_free(bcell.address); } static void test_cfmt_connected_cells(void *arg) { relay_header_t rh; cell_t cell; tor_addr_t addr; int ttl, r; char *mem_op_hex_tmp = NULL; (void)arg; /* Let's try an oldschool one with nothing in it. */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "", 0); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_UNSPEC); tt_int_op(ttl, ==, -1); /* A slightly less oldschool one: only an IPv4 address */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_INET); tt_str_op(fmt_addr(&addr), ==, "32.48.64.80"); tt_int_op(ttl, ==, -1); /* Bogus but understandable: truncated TTL */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_INET); tt_str_op(fmt_addr(&addr), ==, "17.18.19.20"); tt_int_op(ttl, ==, -1); /* Regular IPv4 one: address and TTL */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x02\x03\x04\x05\x00\x00\x0e\x10", 8); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_INET); tt_str_op(fmt_addr(&addr), ==, "2.3.4.5"); tt_int_op(ttl, ==, 3600); /* IPv4 with too-big TTL */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x02\x03\x04\x05\xf0\x00\x00\x00", 8); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_INET); tt_str_op(fmt_addr(&addr), ==, "2.3.4.5"); tt_int_op(ttl, ==, -1); /* IPv6 (ttl is mandatory) */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x00\x00\x02\x58", 25); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_INET6); tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68"); tt_int_op(ttl, ==, 600); /* IPv6 (ttl too big) */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x90\x00\x02\x58", 25); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_INET6); tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68"); tt_int_op(ttl, ==, -1); /* Bogus size: 3. */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x00\x01\x02", 3); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, -1); /* Bogus family: 7. */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x07" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x90\x00\x02\x58", 25); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, -1); /* Truncated IPv6. */ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x00\x00\x00\x00\x06" "\x26\x07\xf8\xb0\x40\x0c\x0c\x02" "\x00\x00\x00\x00\x00\x00\x00\x68" "\x00\x00\x02", 24); relay_header_unpack(&rh, cell.payload); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, -1); /* Now make sure we can generate connected cells correctly. */ /* Try an IPv4 address */ memset(&rh, 0, sizeof(rh)); memset(&cell, 0, sizeof(cell)); tor_addr_parse(&addr, "30.40.50.60"); rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, &addr, 128); tt_int_op(rh.length, ==, 8); test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000080"); /* Try parsing it. */ tor_addr_make_unspec(&addr); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_INET); tt_str_op(fmt_addr(&addr), ==, "30.40.50.60"); tt_int_op(ttl, ==, 128); /* Try an IPv6 address */ memset(&rh, 0, sizeof(rh)); memset(&cell, 0, sizeof(cell)); tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e"); rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE, &addr, 3600); tt_int_op(rh.length, ==, 25); test_memeq_hex(cell.payload + RELAY_HEADER_SIZE, "00000000" "06" "2620000006b0000b1a1a000026e5480e" "00000e10"); /* Try parsing it. */ tor_addr_make_unspec(&addr); r = connected_cell_parse(&rh, &cell, &addr, &ttl); tt_int_op(r, ==, 0); tt_int_op(tor_addr_family(&addr), ==, AF_INET6); tt_str_op(fmt_addr(&addr), ==, "2620:0:6b0:b:1a1a:0:26e5:480e"); tt_int_op(ttl, ==, 3600); done: tor_free(mem_op_hex_tmp); } static void test_cfmt_create_cells(void *arg) { uint8_t b[MAX_ONIONSKIN_CHALLENGE_LEN]; create_cell_t cc; cell_t cell; cell_t cell2; (void)arg; /* === Let's try parsing some good cells! */ /* A valid create cell. */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); cell.command = CELL_CREATE; memcpy(cell.payload, b, TAP_ONIONSKIN_CHALLENGE_LEN); tt_int_op(0, ==, create_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATE, ==, cc.cell_type); tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type); tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len); test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10); tt_int_op(0, ==, create_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); /* A valid create_fast cell. */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, CREATE_FAST_LEN); cell.command = CELL_CREATE_FAST; memcpy(cell.payload, b, CREATE_FAST_LEN); tt_int_op(0, ==, create_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATE_FAST, ==, cc.cell_type); tt_int_op(ONION_HANDSHAKE_TYPE_FAST, ==, cc.handshake_type); tt_int_op(CREATE_FAST_LEN, ==, cc.handshake_len); test_memeq(cc.onionskin, b, CREATE_FAST_LEN + 10); tt_int_op(0, ==, create_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); /* A valid create2 cell with a TAP payload */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); cell.command = CELL_CREATE2; memcpy(cell.payload, "\x00\x00\x00\xBA", 4); /* TAP, 186 bytes long */ memcpy(cell.payload+4, b, TAP_ONIONSKIN_CHALLENGE_LEN); tt_int_op(0, ==, create_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATE2, ==, cc.cell_type); tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type); tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len); test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10); tt_int_op(0, ==, create_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); /* A valid create2 cell with an ntor payload */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, NTOR_ONIONSKIN_LEN); cell.command = CELL_CREATE2; memcpy(cell.payload, "\x00\x02\x00\x54", 4); /* ntor, 84 bytes long */ memcpy(cell.payload+4, b, NTOR_ONIONSKIN_LEN); #ifdef CURVE25519_ENABLED tt_int_op(0, ==, create_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATE2, ==, cc.cell_type); tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type); tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len); test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10); tt_int_op(0, ==, create_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); #else tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); #endif /* A valid create cell with an ntor payload, in legacy format. */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, NTOR_ONIONSKIN_LEN); cell.command = CELL_CREATE; memcpy(cell.payload, "ntorNTORntorNTOR", 16); memcpy(cell.payload+16, b, NTOR_ONIONSKIN_LEN); #ifdef CURVE25519_ENABLED tt_int_op(0, ==, create_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATE, ==, cc.cell_type); tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type); tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len); test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10); tt_int_op(0, ==, create_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); #else tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); #endif /* == Okay, now let's try to parse some impossible stuff. */ /* It has to be some kind of a create cell! */ cell.command = CELL_CREATED; tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); /* You can't acutally make an unparseable CREATE or CREATE_FAST cell. */ /* Try some CREATE2 cells. First with a bad type. */ cell.command = CELL_CREATE2; memcpy(cell.payload, "\x00\x50\x00\x99", 4); /* Type 0x50???? */ tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); /* Now a good type with an incorrect length. */ memcpy(cell.payload, "\x00\x00\x00\xBC", 4); /* TAP, 187 bytes.*/ tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); /* Now a good type with a ridiculous length. */ memcpy(cell.payload, "\x00\x00\x02\x00", 4); /* TAP, 512 bytes.*/ tt_int_op(-1, ==, create_cell_parse(&cc, &cell)); /* == Time to try formatting bad cells. The important thing is that we reject big lengths, so just check that for now. */ cc.handshake_len = 512; tt_int_op(-1, ==, create_cell_format(&cell2, &cc)); /* == Try formatting a create2 cell we don't understand. XXXX */ done: ; } static void test_cfmt_created_cells(void *arg) { uint8_t b[512]; created_cell_t cc; cell_t cell; cell_t cell2; (void)arg; /* A good CREATED cell */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN); cell.command = CELL_CREATED; memcpy(cell.payload, b, TAP_ONIONSKIN_REPLY_LEN); tt_int_op(0, ==, created_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATED, ==, cc.cell_type); tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, cc.handshake_len); test_memeq(cc.reply, b, TAP_ONIONSKIN_REPLY_LEN + 10); tt_int_op(0, ==, created_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); /* A good CREATED_FAST cell */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, CREATED_FAST_LEN); cell.command = CELL_CREATED_FAST; memcpy(cell.payload, b, CREATED_FAST_LEN); tt_int_op(0, ==, created_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATED_FAST, ==, cc.cell_type); tt_int_op(CREATED_FAST_LEN, ==, cc.handshake_len); test_memeq(cc.reply, b, CREATED_FAST_LEN + 10); tt_int_op(0, ==, created_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); /* A good CREATED2 cell with short reply */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, 64); cell.command = CELL_CREATED2; memcpy(cell.payload, "\x00\x40", 2); memcpy(cell.payload+2, b, 64); tt_int_op(0, ==, created_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATED2, ==, cc.cell_type); tt_int_op(64, ==, cc.handshake_len); test_memeq(cc.reply, b, 80); tt_int_op(0, ==, created_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); /* A good CREATED2 cell with maximal reply */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, 496); cell.command = CELL_CREATED2; memcpy(cell.payload, "\x01\xF0", 2); memcpy(cell.payload+2, b, 496); tt_int_op(0, ==, created_cell_parse(&cc, &cell)); tt_int_op(CELL_CREATED2, ==, cc.cell_type); tt_int_op(496, ==, cc.handshake_len); test_memeq(cc.reply, b, 496); tt_int_op(0, ==, created_cell_format(&cell2, &cc)); tt_int_op(cell.command, ==, cell2.command); test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE); /* Bogus CREATED2 cell: too long! */ memset(&cell, 0, sizeof(cell)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, 496); cell.command = CELL_CREATED2; memcpy(cell.payload, "\x01\xF1", 2); tt_int_op(-1, ==, created_cell_parse(&cc, &cell)); /* Unformattable CREATED2 cell: too long! */ cc.handshake_len = 497; tt_int_op(-1, ==, created_cell_format(&cell2, &cc)); done: ; } static void test_cfmt_extend_cells(void *arg) { cell_t cell; uint8_t b[512]; extend_cell_t ec; create_cell_t *cc = &ec.create_cell; uint8_t p[RELAY_PAYLOAD_SIZE]; uint8_t p2[RELAY_PAYLOAD_SIZE]; uint8_t p2_cmd; uint16_t p2_len; char *mem_op_hex_tmp = NULL; (void) arg; /* Let's start with a simple EXTEND cell. */ memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN); memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */ memcpy(p+6,b,TAP_ONIONSKIN_CHALLENGE_LEN); memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20); tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND, p, 26+TAP_ONIONSKIN_CHALLENGE_LEN)); tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type); tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr)); tt_int_op(258, ==, ec.orport_ipv4.port); tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr)); test_memeq(ec.node_id, "electroencephalogram", 20); tt_int_op(cc->cell_type, ==, CELL_CREATE); tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_TAP); tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_CHALLENGE_LEN); test_memeq(cc->onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN+20); tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND); tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN); test_memeq(p2, p, RELAY_PAYLOAD_SIZE); /* Let's do an ntor stuffed in a legacy EXTEND cell */ memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, NTOR_ONIONSKIN_LEN); memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */ memcpy(p+6,"ntorNTORntorNTOR", 16); memcpy(p+22, b, NTOR_ONIONSKIN_LEN); memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20); tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND, p, 26+TAP_ONIONSKIN_CHALLENGE_LEN)); tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type); tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr)); tt_int_op(258, ==, ec.orport_ipv4.port); tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr)); test_memeq(ec.node_id, "electroencephalogram", 20); tt_int_op(cc->cell_type, ==, CELL_CREATE2); tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR); tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN); test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20); tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND); tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN); test_memeq(p2, p, RELAY_PAYLOAD_SIZE); tt_int_op(0, ==, create_cell_format_relayed(&cell, cc)); /* Now let's do a minimal ntor EXTEND2 cell. */ memset(&ec, 0xff, sizeof(ec)); memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, NTOR_ONIONSKIN_LEN); /* 2 items; one 18.244.0.1:61681 */ memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); /* The other is a digest. */ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); /* Prep for the handshake: type and length */ memcpy(p+31, "\x00\x02\x00\x54", 4); memcpy(p+35, b, NTOR_ONIONSKIN_LEN); tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, 35+NTOR_ONIONSKIN_LEN)); tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type); tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr)); tt_int_op(61681, ==, ec.orport_ipv4.port); tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr)); test_memeq(ec.node_id, "anarchoindividualist", 20); tt_int_op(cc->cell_type, ==, CELL_CREATE2); tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR); tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN); test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20); tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2); tt_int_op(p2_len, ==, 35+NTOR_ONIONSKIN_LEN); test_memeq(p2, p, RELAY_PAYLOAD_SIZE); /* Now let's do a fanciful EXTEND2 cell. */ memset(&ec, 0xff, sizeof(ec)); memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, 99); /* 4 items; one 18 244 0 1 61681 */ memcpy(p, "\x04\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); /* One is a digest. */ memcpy(p+9, "\x02\x14" "anthropomorphization", 22); /* One is an ipv6 address */ memcpy(p+31, "\x01\x12\x20\x02\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\xf0\xc5\x1e\x11\x12", 20); /* One is the Konami code. */ memcpy(p+51, "\xf0\x20upupdowndownleftrightleftrightba", 34); /* Prep for the handshake: weird type and length */ memcpy(p+85, "\x01\x05\x00\x63", 4); memcpy(p+89, b, 99); tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, 89+99)); tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type); tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr)); tt_int_op(61681, ==, ec.orport_ipv4.port); tt_str_op("2002::f0:c51e", ==, fmt_addr(&ec.orport_ipv6.addr)); tt_int_op(4370, ==, ec.orport_ipv6.port); test_memeq(ec.node_id, "anthropomorphization", 20); tt_int_op(cc->cell_type, ==, CELL_CREATE2); tt_int_op(cc->handshake_type, ==, 0x105); tt_int_op(cc->handshake_len, ==, 99); test_memeq(cc->onionskin, b, 99+20); tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2); /* We'll generate it minus the IPv6 address and minus the konami code */ tt_int_op(p2_len, ==, 89+99-34-20); test_memeq_hex(p2, /* Two items: one that same darn IP address. */ "02000612F40001F0F1" /* The next is a digest : anthropomorphization */ "0214616e7468726f706f6d6f727068697a6174696f6e" /* Now the handshake prologue */ "01050063"); test_memeq(p2+1+8+22+4, b, 99+20); tt_int_op(0, ==, create_cell_format_relayed(&cell, cc)); /* == Now try parsing some junk */ /* Try a too-long handshake */ memset(p, 0, sizeof(p)); memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); memcpy(p+31, "\xff\xff\x01\xd0", 4); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); /* Try two identities. */ memset(p, 0, sizeof(p)); memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); memcpy(p+31, "\x02\x14" "autodepolymerization", 22); memcpy(p+53, "\xff\xff\x00\x10", 4); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); /* No identities. */ memset(p, 0, sizeof(p)); memcpy(p, "\x01\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); memcpy(p+53, "\xff\xff\x00\x10", 4); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); /* Try a bad IPv4 address (too long, too short)*/ memset(p, 0, sizeof(p)); memcpy(p, "\x02\x00\x07\x12\xf4\x00\x01\xf0\xf1\xff", 10); memcpy(p+10, "\x02\x14" "anarchoindividualist", 22); memcpy(p+32, "\xff\xff\x00\x10", 4); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); memset(p, 0, sizeof(p)); memcpy(p, "\x02\x00\x05\x12\xf4\x00\x01\xf0", 8); memcpy(p+8, "\x02\x14" "anarchoindividualist", 22); memcpy(p+30, "\xff\xff\x00\x10", 4); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); /* IPv6 address (too long, too short, no IPv4)*/ memset(p, 0, sizeof(p)); memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); memcpy(p+31, "\x01\x13" "xxxxxxxxxxxxxxxxYYZ", 19); memcpy(p+50, "\xff\xff\x00\x20", 4); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); memset(p, 0, sizeof(p)); memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9); memcpy(p+9, "\x02\x14" "anarchoindividualist", 22); memcpy(p+31, "\x01\x11" "xxxxxxxxxxxxxxxxY", 17); memcpy(p+48, "\xff\xff\x00\x20", 4); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); memset(p, 0, sizeof(p)); memcpy(p, "\x02", 1); memcpy(p+1, "\x02\x14" "anarchoindividualist", 22); memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18); memcpy(p+41, "\xff\xff\x00\x20", 4); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); /* Running out of space in specifiers */ memset(p,0,sizeof(p)); memcpy(p, "\x05\x0a\xff", 3); memcpy(p+3+255, "\x0a\xff", 2); tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, sizeof(p))); /* Fuzz, because why not. */ memset(&ec, 0xff, sizeof(ec)); { int i; memset(p, 0, sizeof(p)); for (i = 0; i < 10000; ++i) { int n = crypto_rand_int(sizeof(p)); crypto_rand((char *)p, n); extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, n); } } done: tor_free(mem_op_hex_tmp); } static void test_cfmt_extended_cells(void *arg) { uint8_t b[512]; extended_cell_t ec; created_cell_t *cc = &ec.created_cell; uint8_t p[RELAY_PAYLOAD_SIZE]; uint8_t p2[RELAY_PAYLOAD_SIZE]; uint8_t p2_cmd; uint16_t p2_len; char *mem_op_hex_tmp = NULL; (void) arg; /* Try a regular EXTENDED cell. */ memset(&ec, 0xff, sizeof(ec)); memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN); memcpy(p,b,TAP_ONIONSKIN_REPLY_LEN); tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p, TAP_ONIONSKIN_REPLY_LEN)); tt_int_op(RELAY_COMMAND_EXTENDED, ==, ec.cell_type); tt_int_op(cc->cell_type, ==, CELL_CREATED); tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_REPLY_LEN); test_memeq(cc->reply, b, TAP_ONIONSKIN_REPLY_LEN); tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec)); tt_int_op(RELAY_COMMAND_EXTENDED, ==, p2_cmd); tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, p2_len); test_memeq(p2, p, sizeof(p2)); /* Try an EXTENDED2 cell */ memset(&ec, 0xff, sizeof(ec)); memset(p, 0, sizeof(p)); memset(b, 0, sizeof(b)); crypto_rand((char*)b, 42); memcpy(p,"\x00\x2a",2); memcpy(p+2,b,42); tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, 2+42)); tt_int_op(RELAY_COMMAND_EXTENDED2, ==, ec.cell_type); tt_int_op(cc->cell_type, ==, CELL_CREATED2); tt_int_op(cc->handshake_len, ==, 42); test_memeq(cc->reply, b, 42+10); tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec)); tt_int_op(RELAY_COMMAND_EXTENDED2, ==, p2_cmd); tt_int_op(2+42, ==, p2_len); test_memeq(p2, p, sizeof(p2)); /* Try an almost-too-long EXTENDED2 cell */ memcpy(p, "\x01\xf0", 2); tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p))); /* Now try a too-long extended2 cell. That's the only misparse I can think * of. */ memcpy(p, "\x01\xf1", 2); tt_int_op(-1, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p))); done: tor_free(mem_op_hex_tmp); } #define TEST(name, flags) \ { #name, test_cfmt_ ## name, flags, 0, NULL } struct testcase_t cell_format_tests[] = { TEST(relay_header, 0), TEST(begin_cells, 0), TEST(connected_cells, 0), TEST(create_cells, 0), TEST(created_cells, 0), TEST(extend_cells, 0), TEST(extended_cells, 0), END_OF_TESTCASES }; tor-0.2.4.20/src/test/test_crypto.c0000644000175000017500000011544212255745673014002 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CRYPTO_PRIVATE #define CRYPTO_CURVE25519_PRIVATE #include "or.h" #include "test.h" #include "aes.h" #include "util.h" #ifdef CURVE25519_ENABLED #include "crypto_curve25519.h" #endif /** Run unit tests for Diffie-Hellman functionality. */ static void test_crypto_dh(void) { crypto_dh_t *dh1 = crypto_dh_new(DH_TYPE_CIRCUIT); crypto_dh_t *dh2 = crypto_dh_new(DH_TYPE_CIRCUIT); char p1[DH_BYTES]; char p2[DH_BYTES]; char s1[DH_BYTES]; char s2[DH_BYTES]; ssize_t s1len, s2len; test_eq(crypto_dh_get_bytes(dh1), DH_BYTES); test_eq(crypto_dh_get_bytes(dh2), DH_BYTES); memset(p1, 0, DH_BYTES); memset(p2, 0, DH_BYTES); test_memeq(p1, p2, DH_BYTES); test_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES)); test_memneq(p1, p2, DH_BYTES); test_assert(! crypto_dh_get_public(dh2, p2, DH_BYTES)); test_memneq(p1, p2, DH_BYTES); memset(s1, 0, DH_BYTES); memset(s2, 0xFF, DH_BYTES); s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p2, DH_BYTES, s1, 50); s2len = crypto_dh_compute_secret(LOG_WARN, dh2, p1, DH_BYTES, s2, 50); test_assert(s1len > 0); test_eq(s1len, s2len); test_memeq(s1, s2, s1len); { /* XXXX Now fabricate some bad values and make sure they get caught, * Check 0, 1, N-1, >= N, etc. */ } done: crypto_dh_free(dh1); crypto_dh_free(dh2); } /** Run unit tests for our random number generation function and its wrappers. */ static void test_crypto_rng(void) { int i, j, allok; char data1[100], data2[100]; double d; /* Try out RNG. */ test_assert(! crypto_seed_rng(0)); crypto_rand(data1, 100); crypto_rand(data2, 100); test_memneq(data1,data2,100); allok = 1; for (i = 0; i < 100; ++i) { uint64_t big; char *host; j = crypto_rand_int(100); if (j < 0 || j >= 100) allok = 0; big = crypto_rand_uint64(U64_LITERAL(1)<<40); if (big >= (U64_LITERAL(1)<<40)) allok = 0; big = crypto_rand_uint64(U64_LITERAL(5)); if (big >= 5) allok = 0; d = crypto_rand_double(); test_assert(d >= 0); test_assert(d < 1.0); host = crypto_random_hostname(3,8,"www.",".onion"); if (strcmpstart(host,"www.") || strcmpend(host,".onion") || strlen(host) < 13 || strlen(host) > 18) allok = 0; tor_free(host); } test_assert(allok); done: ; } /** Run unit tests for our AES functionality */ static void test_crypto_aes(void *arg) { char *data1 = NULL, *data2 = NULL, *data3 = NULL; crypto_cipher_t *env1 = NULL, *env2 = NULL; int i, j; char *mem_op_hex_tmp=NULL; int use_evp = !strcmp(arg,"evp"); evaluate_evp_for_aes(use_evp); evaluate_ctr_for_aes(); data1 = tor_malloc(1024); data2 = tor_malloc(1024); data3 = tor_malloc(1024); /* Now, test encryption and decryption with stream cipher. */ data1[0]='\0'; for (i = 1023; i>0; i -= 35) strncat(data1, "Now is the time for all good onions", i); memset(data2, 0, 1024); memset(data3, 0, 1024); env1 = crypto_cipher_new(NULL); test_neq_ptr(env1, 0); env2 = crypto_cipher_new(crypto_cipher_get_key(env1)); test_neq_ptr(env2, 0); /* Try encrypting 512 chars. */ crypto_cipher_encrypt(env1, data2, data1, 512); crypto_cipher_decrypt(env2, data3, data2, 512); test_memeq(data1, data3, 512); test_memneq(data1, data2, 512); /* Now encrypt 1 at a time, and get 1 at a time. */ for (j = 512; j < 560; ++j) { crypto_cipher_encrypt(env1, data2+j, data1+j, 1); } for (j = 512; j < 560; ++j) { crypto_cipher_decrypt(env2, data3+j, data2+j, 1); } test_memeq(data1, data3, 560); /* Now encrypt 3 at a time, and get 5 at a time. */ for (j = 560; j < 1024-5; j += 3) { crypto_cipher_encrypt(env1, data2+j, data1+j, 3); } for (j = 560; j < 1024-5; j += 5) { crypto_cipher_decrypt(env2, data3+j, data2+j, 5); } test_memeq(data1, data3, 1024-5); /* Now make sure that when we encrypt with different chunk sizes, we get the same results. */ crypto_cipher_free(env2); env2 = NULL; memset(data3, 0, 1024); env2 = crypto_cipher_new(crypto_cipher_get_key(env1)); test_neq_ptr(env2, NULL); for (j = 0; j < 1024-16; j += 17) { crypto_cipher_encrypt(env2, data3+j, data1+j, 17); } for (j= 0; j < 1024-16; ++j) { if (data2[j] != data3[j]) { printf("%d: %d\t%d\n", j, (int) data2[j], (int) data3[j]); } } test_memeq(data2, data3, 1024-16); crypto_cipher_free(env1); env1 = NULL; crypto_cipher_free(env2); env2 = NULL; /* NIST test vector for aes. */ /* IV starts at 0 */ env1 = crypto_cipher_new("\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00"); crypto_cipher_encrypt(env1, data1, "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", 16); test_memeq_hex(data1, "0EDD33D3C621E546455BD8BA1418BEC8"); /* Now test rollover. All these values are originally from a python * script. */ crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00" "\xff\xff\xff\xff\xff\xff\xff\xff"); memset(data2, 0, 1024); crypto_cipher_encrypt(env1, data1, data2, 32); test_memeq_hex(data1, "335fe6da56f843199066c14a00a40231" "cdd0b917dbc7186908a6bfb5ffd574d3"); crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); memset(data2, 0, 1024); crypto_cipher_encrypt(env1, data1, data2, 32); test_memeq_hex(data1, "e627c6423fa2d77832a02b2794094b73" "3e63c721df790d2c6469cc1953a3ffac"); crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); memset(data2, 0, 1024); crypto_cipher_encrypt(env1, data1, data2, 32); test_memeq_hex(data1, "2aed2bff0de54f9328efd070bf48f70a" "0EDD33D3C621E546455BD8BA1418BEC8"); /* Now check rollover on inplace cipher. */ crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); crypto_cipher_crypt_inplace(env1, data2, 64); test_memeq_hex(data2, "2aed2bff0de54f9328efd070bf48f70a" "0EDD33D3C621E546455BD8BA1418BEC8" "93e2c5243d6839eac58503919192f7ae" "1908e67cafa08d508816659c2e693191"); crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); crypto_cipher_crypt_inplace(env1, data2, 64); test_assert(tor_mem_is_zero(data2, 64)); done: tor_free(mem_op_hex_tmp); if (env1) crypto_cipher_free(env1); if (env2) crypto_cipher_free(env2); tor_free(data1); tor_free(data2); tor_free(data3); } /** Run unit tests for our SHA-1 functionality */ static void test_crypto_sha(void) { crypto_digest_t *d1 = NULL, *d2 = NULL; int i; char key[160]; char digest[32]; char data[50]; char d_out1[DIGEST_LEN], d_out2[DIGEST256_LEN]; char *mem_op_hex_tmp=NULL; /* Test SHA-1 with a test vector from the specification. */ i = crypto_digest(data, "abc", 3); test_memeq_hex(data, "A9993E364706816ABA3E25717850C26C9CD0D89D"); tt_int_op(i, ==, 0); /* Test SHA-256 with a test vector from the specification. */ i = crypto_digest256(data, "abc", 3, DIGEST_SHA256); test_memeq_hex(data, "BA7816BF8F01CFEA414140DE5DAE2223B00361A3" "96177A9CB410FF61F20015AD"); tt_int_op(i, ==, 0); /* Test HMAC-SHA-1 with test cases from RFC2202. */ /* Case 1. */ memset(key, 0x0b, 20); crypto_hmac_sha1(digest, key, 20, "Hi There", 8); test_streq(hex_str(digest, 20), "B617318655057264E28BC0B6FB378C8EF146BE00"); /* Case 2. */ crypto_hmac_sha1(digest, "Jefe", 4, "what do ya want for nothing?", 28); test_streq(hex_str(digest, 20), "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79"); /* Case 4. */ base16_decode(key, 25, "0102030405060708090a0b0c0d0e0f10111213141516171819", 50); memset(data, 0xcd, 50); crypto_hmac_sha1(digest, key, 25, data, 50); test_streq(hex_str(digest, 20), "4C9007F4026250C6BC8414F9BF50C86C2D7235DA"); /* Case 5. */ memset(key, 0xaa, 80); crypto_hmac_sha1(digest, key, 80, "Test Using Larger Than Block-Size Key - Hash Key First", 54); test_streq(hex_str(digest, 20), "AA4AE5E15272D00E95705637CE8A3B55ED402112"); /* Test HMAC-SHA256 with test cases from wikipedia and RFC 4231 */ /* Case empty (wikipedia) */ crypto_hmac_sha256(digest, "", 0, "", 0); test_streq(hex_str(digest, 32), "B613679A0814D9EC772F95D778C35FC5FF1697C493715653C6C712144292C5AD"); /* Case quick-brown (wikipedia) */ crypto_hmac_sha256(digest, "key", 3, "The quick brown fox jumps over the lazy dog", 43); test_streq(hex_str(digest, 32), "F7BC83F430538424B13298E6AA6FB143EF4D59A14946175997479DBC2D1A3CD8"); /* "Test Case 1" from RFC 4231 */ memset(key, 0x0b, 20); crypto_hmac_sha256(digest, key, 20, "Hi There", 8); test_memeq_hex(digest, "b0344c61d8db38535ca8afceaf0bf12b" "881dc200c9833da726e9376c2e32cff7"); /* "Test Case 2" from RFC 4231 */ memset(key, 0x0b, 20); crypto_hmac_sha256(digest, "Jefe", 4, "what do ya want for nothing?", 28); test_memeq_hex(digest, "5bdcc146bf60754e6a042426089575c7" "5a003f089d2739839dec58b964ec3843"); /* "Test case 3" from RFC 4231 */ memset(key, 0xaa, 20); memset(data, 0xdd, 50); crypto_hmac_sha256(digest, key, 20, data, 50); test_memeq_hex(digest, "773ea91e36800e46854db8ebd09181a7" "2959098b3ef8c122d9635514ced565fe"); /* "Test case 4" from RFC 4231 */ base16_decode(key, 25, "0102030405060708090a0b0c0d0e0f10111213141516171819", 50); memset(data, 0xcd, 50); crypto_hmac_sha256(digest, key, 25, data, 50); test_memeq_hex(digest, "82558a389a443c0ea4cc819899f2083a" "85f0faa3e578f8077a2e3ff46729665b"); /* "Test case 5" from RFC 4231 */ memset(key, 0x0c, 20); crypto_hmac_sha256(digest, key, 20, "Test With Truncation", 20); test_memeq_hex(digest, "a3b6167473100ee06e0c796c2955552b"); /* "Test case 6" from RFC 4231 */ memset(key, 0xaa, 131); crypto_hmac_sha256(digest, key, 131, "Test Using Larger Than Block-Size Key - Hash Key First", 54); test_memeq_hex(digest, "60e431591ee0b67f0d8a26aacbf5b77f" "8e0bc6213728c5140546040f0ee37f54"); /* "Test case 7" from RFC 4231 */ memset(key, 0xaa, 131); crypto_hmac_sha256(digest, key, 131, "This is a test using a larger than block-size key and a " "larger than block-size data. The key needs to be hashed " "before being used by the HMAC algorithm.", 152); test_memeq_hex(digest, "9b09ffa71b942fcb27635fbcd5b0e944" "bfdc63644f0713938a7f51535c3a35e2"); /* Incremental digest code. */ d1 = crypto_digest_new(); test_assert(d1); crypto_digest_add_bytes(d1, "abcdef", 6); d2 = crypto_digest_dup(d1); test_assert(d2); crypto_digest_add_bytes(d2, "ghijkl", 6); crypto_digest_get_digest(d2, d_out1, sizeof(d_out1)); crypto_digest(d_out2, "abcdefghijkl", 12); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_assign(d2, d1); crypto_digest_add_bytes(d2, "mno", 3); crypto_digest_get_digest(d2, d_out1, sizeof(d_out1)); crypto_digest(d_out2, "abcdefmno", 9); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_get_digest(d1, d_out1, sizeof(d_out1)); crypto_digest(d_out2, "abcdef", 6); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_free(d1); crypto_digest_free(d2); /* Incremental digest code with sha256 */ d1 = crypto_digest256_new(DIGEST_SHA256); test_assert(d1); crypto_digest_add_bytes(d1, "abcdef", 6); d2 = crypto_digest_dup(d1); test_assert(d2); crypto_digest_add_bytes(d2, "ghijkl", 6); crypto_digest_get_digest(d2, d_out1, sizeof(d_out1)); crypto_digest256(d_out2, "abcdefghijkl", 12, DIGEST_SHA256); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_assign(d2, d1); crypto_digest_add_bytes(d2, "mno", 3); crypto_digest_get_digest(d2, d_out1, sizeof(d_out1)); crypto_digest256(d_out2, "abcdefmno", 9, DIGEST_SHA256); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_get_digest(d1, d_out1, sizeof(d_out1)); crypto_digest256(d_out2, "abcdef", 6, DIGEST_SHA256); test_memeq(d_out1, d_out2, DIGEST_LEN); done: if (d1) crypto_digest_free(d1); if (d2) crypto_digest_free(d2); tor_free(mem_op_hex_tmp); } /** Run unit tests for our public key crypto functions */ static void test_crypto_pk(void) { crypto_pk_t *pk1 = NULL, *pk2 = NULL; char *encoded = NULL; char data1[1024], data2[1024], data3[1024]; size_t size; int i, j, p, len; /* Public-key ciphers */ pk1 = pk_generate(0); pk2 = crypto_pk_new(); test_assert(pk1 && pk2); test_assert(! crypto_pk_write_public_key_to_string(pk1, &encoded, &size)); test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size)); test_eq(0, crypto_pk_cmp_keys(pk1, pk2)); /* comparison between keys and NULL */ tt_int_op(crypto_pk_cmp_keys(NULL, pk1), <, 0); tt_int_op(crypto_pk_cmp_keys(NULL, NULL), ==, 0); tt_int_op(crypto_pk_cmp_keys(pk1, NULL), >, 0); test_eq(128, crypto_pk_keysize(pk1)); test_eq(1024, crypto_pk_num_bits(pk1)); test_eq(128, crypto_pk_keysize(pk2)); test_eq(1024, crypto_pk_num_bits(pk2)); test_eq(128, crypto_pk_public_encrypt(pk2, data1, sizeof(data1), "Hello whirled.", 15, PK_PKCS1_OAEP_PADDING)); test_eq(128, crypto_pk_public_encrypt(pk1, data2, sizeof(data1), "Hello whirled.", 15, PK_PKCS1_OAEP_PADDING)); /* oaep padding should make encryption not match */ test_memneq(data1, data2, 128); test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data1, 128, PK_PKCS1_OAEP_PADDING,1)); test_streq(data3, "Hello whirled."); memset(data3, 0, 1024); test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128, PK_PKCS1_OAEP_PADDING,1)); test_streq(data3, "Hello whirled."); /* Can't decrypt with public key. */ test_eq(-1, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data2, 128, PK_PKCS1_OAEP_PADDING,1)); /* Try again with bad padding */ memcpy(data2+1, "XYZZY", 5); /* This has fails ~ once-in-2^40 */ test_eq(-1, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128, PK_PKCS1_OAEP_PADDING,1)); /* File operations: save and load private key */ test_assert(! crypto_pk_write_private_key_to_filename(pk1, get_fname("pkey1"))); /* failing case for read: can't read. */ test_assert(crypto_pk_read_private_key_from_filename(pk2, get_fname("xyzzy")) < 0); write_str_to_file(get_fname("xyzzy"), "foobar", 6); /* Failing case for read: no key. */ test_assert(crypto_pk_read_private_key_from_filename(pk2, get_fname("xyzzy")) < 0); test_assert(! crypto_pk_read_private_key_from_filename(pk2, get_fname("pkey1"))); test_eq(15, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data1, 128, PK_PKCS1_OAEP_PADDING,1)); /* Now try signing. */ strlcpy(data1, "Ossifrage", 1024); test_eq(128, crypto_pk_private_sign(pk1, data2, sizeof(data2), data1, 10)); test_eq(10, crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128)); test_streq(data3, "Ossifrage"); /* Try signing digests. */ test_eq(128, crypto_pk_private_sign_digest(pk1, data2, sizeof(data2), data1, 10)); test_eq(20, crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128)); test_eq(0, crypto_pk_public_checksig_digest(pk1, data1, 10, data2, 128)); test_eq(-1, crypto_pk_public_checksig_digest(pk1, data1, 11, data2, 128)); /*XXXX test failed signing*/ /* Try encoding */ crypto_pk_free(pk2); pk2 = NULL; i = crypto_pk_asn1_encode(pk1, data1, 1024); test_assert(i>0); pk2 = crypto_pk_asn1_decode(data1, i); test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0); /* Try with hybrid encryption wrappers. */ crypto_rand(data1, 1024); for (i = 0; i < 2; ++i) { for (j = 85; j < 140; ++j) { memset(data2,0,1024); memset(data3,0,1024); p = (i==0)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING; len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2), data1,j,p,0); test_assert(len>=0); len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3), data2,len,p,1); test_eq(len,j); test_memeq(data1,data3,j); } } /* Try copy_full */ crypto_pk_free(pk2); pk2 = crypto_pk_copy_full(pk1); test_assert(pk2 != NULL); test_neq_ptr(pk1, pk2); test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0); done: if (pk1) crypto_pk_free(pk1); if (pk2) crypto_pk_free(pk2); tor_free(encoded); } /** Run unit tests for misc crypto formatting functionality (base64, base32, * fingerprints, etc) */ static void test_crypto_formats(void) { char *data1 = NULL, *data2 = NULL, *data3 = NULL; int i, j, idx; data1 = tor_malloc(1024); data2 = tor_malloc(1024); data3 = tor_malloc(1024); test_assert(data1 && data2 && data3); /* Base64 tests */ memset(data1, 6, 1024); for (idx = 0; idx < 10; ++idx) { i = base64_encode(data2, 1024, data1, idx); test_assert(i >= 0); j = base64_decode(data3, 1024, data2, i); test_eq(j,idx); test_memeq(data3, data1, idx); } strlcpy(data1, "Test string that contains 35 chars.", 1024); strlcat(data1, " 2nd string that contains 35 chars.", 1024); i = base64_encode(data2, 1024, data1, 71); test_assert(i >= 0); j = base64_decode(data3, 1024, data2, i); test_eq(j, 71); test_streq(data3, data1); test_assert(data2[i] == '\0'); crypto_rand(data1, DIGEST_LEN); memset(data2, 100, 1024); digest_to_base64(data2, data1); test_eq(BASE64_DIGEST_LEN, strlen(data2)); test_eq(100, data2[BASE64_DIGEST_LEN+2]); memset(data3, 99, 1024); test_eq(digest_from_base64(data3, data2), 0); test_memeq(data1, data3, DIGEST_LEN); test_eq(99, data3[DIGEST_LEN+1]); test_assert(digest_from_base64(data3, "###") < 0); /* Encoding SHA256 */ crypto_rand(data2, DIGEST256_LEN); memset(data2, 100, 1024); digest256_to_base64(data2, data1); test_eq(BASE64_DIGEST256_LEN, strlen(data2)); test_eq(100, data2[BASE64_DIGEST256_LEN+2]); memset(data3, 99, 1024); test_eq(digest256_from_base64(data3, data2), 0); test_memeq(data1, data3, DIGEST256_LEN); test_eq(99, data3[DIGEST256_LEN+1]); /* Base32 tests */ strlcpy(data1, "5chrs", 1024); /* bit pattern is: [35 63 68 72 73] -> * [00110101 01100011 01101000 01110010 01110011] * By 5s: [00110 10101 10001 10110 10000 11100 10011 10011] */ base32_encode(data2, 9, data1, 5); test_streq(data2, "gvrwq4tt"); strlcpy(data1, "\xFF\xF5\x6D\x44\xAE\x0D\x5C\xC9\x62\xC4", 1024); base32_encode(data2, 30, data1, 10); test_streq(data2, "772w2rfobvomsywe"); /* Base16 tests */ strlcpy(data1, "6chrs\xff", 1024); base16_encode(data2, 13, data1, 6); test_streq(data2, "3663687273FF"); strlcpy(data1, "f0d678affc000100", 1024); i = base16_decode(data2, 8, data1, 16); test_eq(i,0); test_memeq(data2, "\xf0\xd6\x78\xaf\xfc\x00\x01\x00",8); /* now try some failing base16 decodes */ test_eq(-1, base16_decode(data2, 8, data1, 15)); /* odd input len */ test_eq(-1, base16_decode(data2, 7, data1, 16)); /* dest too short */ strlcpy(data1, "f0dz!8affc000100", 1024); test_eq(-1, base16_decode(data2, 8, data1, 16)); tor_free(data1); tor_free(data2); tor_free(data3); /* Add spaces to fingerprint */ { data1 = tor_strdup("ABCD1234ABCD56780000ABCD1234ABCD56780000"); test_eq(strlen(data1), 40); data2 = tor_malloc(FINGERPRINT_LEN+1); add_spaces_to_fp(data2, FINGERPRINT_LEN+1, data1); test_streq(data2, "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000"); tor_free(data1); tor_free(data2); } done: tor_free(data1); tor_free(data2); tor_free(data3); } /** Run unit tests for our secret-to-key passphrase hashing functionality. */ static void test_crypto_s2k(void) { char buf[29]; char buf2[29]; char *buf3 = NULL; int i; memset(buf, 0, sizeof(buf)); memset(buf2, 0, sizeof(buf2)); buf3 = tor_malloc(65536); memset(buf3, 0, 65536); secret_to_key(buf+9, 20, "", 0, buf); crypto_digest(buf2+9, buf3, 1024); test_memeq(buf, buf2, 29); memcpy(buf,"vrbacrda",8); memcpy(buf2,"vrbacrda",8); buf[8] = 96; buf2[8] = 96; secret_to_key(buf+9, 20, "12345678", 8, buf); for (i = 0; i < 65536; i += 16) { memcpy(buf3+i, "vrbacrda12345678", 16); } crypto_digest(buf2+9, buf3, 65536); test_memeq(buf, buf2, 29); done: tor_free(buf3); } /** Test AES-CTR encryption and decryption with IV. */ static void test_crypto_aes_iv(void *arg) { char *plain, *encrypted1, *encrypted2, *decrypted1, *decrypted2; char plain_1[1], plain_15[15], plain_16[16], plain_17[17]; char key1[16], key2[16]; ssize_t encrypted_size, decrypted_size; int use_evp = !strcmp(arg,"evp"); evaluate_evp_for_aes(use_evp); plain = tor_malloc(4095); encrypted1 = tor_malloc(4095 + 1 + 16); encrypted2 = tor_malloc(4095 + 1 + 16); decrypted1 = tor_malloc(4095 + 1); decrypted2 = tor_malloc(4095 + 1); crypto_rand(plain, 4095); crypto_rand(key1, 16); crypto_rand(key2, 16); crypto_rand(plain_1, 1); crypto_rand(plain_15, 15); crypto_rand(plain_16, 16); crypto_rand(plain_17, 17); key1[0] = key2[0] + 128; /* Make sure that contents are different. */ /* Encrypt and decrypt with the same key. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 4095, plain, 4095); test_eq(encrypted_size, 16 + 4095); tt_assert(encrypted_size > 0); /* This is obviously true, since 4111 is * greater than 0, but its truth is not * obvious to all analysis tools. */ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095, encrypted1, encrypted_size); test_eq(decrypted_size, 4095); tt_assert(decrypted_size > 0); test_memeq(plain, decrypted1, 4095); /* Encrypt a second time (with a new random initialization vector). */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted2, 16 + 4095, plain, 4095); test_eq(encrypted_size, 16 + 4095); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted2, 4095, encrypted2, encrypted_size); test_eq(decrypted_size, 4095); tt_assert(decrypted_size > 0); test_memeq(plain, decrypted2, 4095); test_memneq(encrypted1, encrypted2, encrypted_size); /* Decrypt with the wrong key. */ decrypted_size = crypto_cipher_decrypt_with_iv(key2, decrypted2, 4095, encrypted1, encrypted_size); test_memneq(plain, decrypted2, decrypted_size); /* Alter the initialization vector. */ encrypted1[0] += 42; decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095, encrypted1, encrypted_size); test_memneq(plain, decrypted2, 4095); /* Special length case: 1. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 1, plain_1, 1); test_eq(encrypted_size, 16 + 1); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 1, encrypted1, encrypted_size); test_eq(decrypted_size, 1); tt_assert(decrypted_size > 0); test_memeq(plain_1, decrypted1, 1); /* Special length case: 15. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 15, plain_15, 15); test_eq(encrypted_size, 16 + 15); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 15, encrypted1, encrypted_size); test_eq(decrypted_size, 15); tt_assert(decrypted_size > 0); test_memeq(plain_15, decrypted1, 15); /* Special length case: 16. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 16, plain_16, 16); test_eq(encrypted_size, 16 + 16); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 16, encrypted1, encrypted_size); test_eq(decrypted_size, 16); tt_assert(decrypted_size > 0); test_memeq(plain_16, decrypted1, 16); /* Special length case: 17. */ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 17, plain_17, 17); test_eq(encrypted_size, 16 + 17); tt_assert(encrypted_size > 0); decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 17, encrypted1, encrypted_size); test_eq(decrypted_size, 17); tt_assert(decrypted_size > 0); test_memeq(plain_17, decrypted1, 17); done: /* Free memory. */ tor_free(plain); tor_free(encrypted1); tor_free(encrypted2); tor_free(decrypted1); tor_free(decrypted2); } /** Test base32 decoding. */ static void test_crypto_base32_decode(void) { char plain[60], encoded[96 + 1], decoded[60]; int res; crypto_rand(plain, 60); /* Encode and decode a random string. */ base32_encode(encoded, 96 + 1, plain, 60); res = base32_decode(decoded, 60, encoded, 96); test_eq(res, 0); test_memeq(plain, decoded, 60); /* Encode, uppercase, and decode a random string. */ base32_encode(encoded, 96 + 1, plain, 60); tor_strupper(encoded); res = base32_decode(decoded, 60, encoded, 96); test_eq(res, 0); test_memeq(plain, decoded, 60); /* Change encoded string and decode. */ if (encoded[0] == 'A' || encoded[0] == 'a') encoded[0] = 'B'; else encoded[0] = 'A'; res = base32_decode(decoded, 60, encoded, 96); test_eq(res, 0); test_memneq(plain, decoded, 60); /* Bad encodings. */ encoded[0] = '!'; res = base32_decode(decoded, 60, encoded, 96); test_assert(res < 0); done: ; } static void test_crypto_kdf_TAP(void *arg) { uint8_t key_material[100]; int r; char *mem_op_hex_tmp = NULL; (void)arg; #define EXPAND(s) \ r = crypto_expand_key_material_TAP( \ (const uint8_t*)(s), strlen(s), \ key_material, 100) /* Test vectors generated with a little python script; feel free to write * your own. */ memset(key_material, 0, sizeof(key_material)); EXPAND(""); tt_int_op(r, ==, 0); test_memeq_hex(key_material, "5ba93c9db0cff93f52b521d7420e43f6eda2784fbf8b4530d8" "d246dd74ac53a13471bba17941dff7c4ea21bb365bbeeaf5f2" "c654883e56d11e43c44e9842926af7ca0a8cca12604f945414" "f07b01e13da42c6cf1de3abfdea9b95f34687cbbe92b9a7383"); EXPAND("Tor"); tt_int_op(r, ==, 0); test_memeq_hex(key_material, "776c6214fc647aaa5f683c737ee66ec44f03d0372e1cce6922" "7950f236ddf1e329a7ce7c227903303f525a8c6662426e8034" "870642a6dabbd41b5d97ec9bf2312ea729992f48f8ea2d0ba8" "3f45dfda1a80bdc8b80de01b23e3e0ffae099b3e4ccf28dc28"); EXPAND("AN ALARMING ITEM TO FIND ON A MONTHLY AUTO-DEBIT NOTICE"); tt_int_op(r, ==, 0); test_memeq_hex(key_material, "a340b5d126086c3ab29c2af4179196dbf95e1c72431419d331" "4844bf8f6afb6098db952b95581fb6c33625709d6f4400b8e7" "ace18a70579fad83c0982ef73f89395bcc39493ad53a685854" "daf2ba9b78733b805d9a6824c907ee1dba5ac27a1e466d4d10"); done: tor_free(mem_op_hex_tmp); #undef EXPAND } static void test_crypto_hkdf_sha256(void *arg) { uint8_t key_material[100]; const uint8_t salt[] = "ntor-curve25519-sha256-1:key_extract"; const size_t salt_len = strlen((char*)salt); const uint8_t m_expand[] = "ntor-curve25519-sha256-1:key_expand"; const size_t m_expand_len = strlen((char*)m_expand); int r; char *mem_op_hex_tmp = NULL; (void)arg; #define EXPAND(s) \ r = crypto_expand_key_material_rfc5869_sha256( \ (const uint8_t*)(s), strlen(s), \ salt, salt_len, \ m_expand, m_expand_len, \ key_material, 100) /* Test vectors generated with ntor_ref.py */ memset(key_material, 0, sizeof(key_material)); EXPAND(""); tt_int_op(r, ==, 0); test_memeq_hex(key_material, "d3490ed48b12a48f9547861583573fe3f19aafe3f81dc7fc75" "eeed96d741b3290f941576c1f9f0b2d463d1ec7ab2c6bf71cd" "d7f826c6298c00dbfe6711635d7005f0269493edf6046cc7e7" "dcf6abe0d20c77cf363e8ffe358927817a3d3e73712cee28d8"); EXPAND("Tor"); tt_int_op(r, ==, 0); test_memeq_hex(key_material, "5521492a85139a8d9107a2d5c0d9c91610d0f95989975ebee6" "c02a4f8d622a6cfdf9b7c7edd3832e2760ded1eac309b76f8d" "66c4a3c4d6225429b3a016e3c3d45911152fc87bc2de9630c3" "961be9fdb9f93197ea8e5977180801926d3321fa21513e59ac"); EXPAND("AN ALARMING ITEM TO FIND ON YOUR CREDIT-RATING STATEMENT"); tt_int_op(r, ==, 0); test_memeq_hex(key_material, "a2aa9b50da7e481d30463adb8f233ff06e9571a0ca6ab6df0f" "b206fa34e5bc78d063fc291501beec53b36e5a0e434561200c" "5f8bd13e0f88b3459600b4dc21d69363e2895321c06184879d" "94b18f078411be70b767c7fc40679a9440a0c95ea83a23efbf"); done: tor_free(mem_op_hex_tmp); #undef EXPAND } #ifdef CURVE25519_ENABLED static void test_crypto_curve25519_impl(void *arg) { /* adapted from curve25519_donna, which adapted it from test-curve25519 version 20050915, by D. J. Bernstein, Public domain. */ const int randomize_high_bit = (arg != NULL); #ifdef SLOW_CURVE25519_TEST const int loop_max=10000; const char e1_expected[] = "4faf81190869fd742a33691b0e0824d5" "7e0329f4dd2819f5f32d130f1296b500"; const char e2k_expected[] = "05aec13f92286f3a781ccae98995a3b9" "e0544770bc7de853b38f9100489e3e79"; const char e1e2k_expected[] = "cd6e8269104eb5aaee886bd2071fba88" "bd13861475516bc2cd2b6e005e805064"; #else const int loop_max=200; const char e1_expected[] = "bc7112cde03f97ef7008cad1bdc56be3" "c6a1037d74cceb3712e9206871dcf654"; const char e2k_expected[] = "dd8fa254fb60bdb5142fe05b1f5de44d" "8e3ee1a63c7d14274ea5d4c67f065467"; const char e1e2k_expected[] = "7ddb98bd89025d2347776b33901b3e7e" "c0ee98cb2257a4545c0cfb2ca3e1812b"; #endif unsigned char e1k[32]; unsigned char e2k[32]; unsigned char e1e2k[32]; unsigned char e2e1k[32]; unsigned char e1[32] = {3}; unsigned char e2[32] = {5}; unsigned char k[32] = {9}; int loop, i; char *mem_op_hex_tmp = NULL; for (loop = 0; loop < loop_max; ++loop) { curve25519_impl(e1k,e1,k); curve25519_impl(e2e1k,e2,e1k); curve25519_impl(e2k,e2,k); if (randomize_high_bit) { /* We require that the high bit of the public key be ignored. So if * we're doing this variant test, we randomize the high bit of e2k, and * make sure that the handshake still works out the same as it would * otherwise. */ uint8_t byte; crypto_rand((char*)&byte, 1); e2k[31] |= (byte & 0x80); } curve25519_impl(e1e2k,e1,e2k); test_memeq(e1e2k, e2e1k, 32); if (loop == loop_max-1) { break; } for (i = 0;i < 32;++i) e1[i] ^= e2k[i]; for (i = 0;i < 32;++i) e2[i] ^= e1k[i]; for (i = 0;i < 32;++i) k[i] ^= e1e2k[i]; } test_memeq_hex(e1, e1_expected); test_memeq_hex(e2k, e2k_expected); test_memeq_hex(e1e2k, e1e2k_expected); done: tor_free(mem_op_hex_tmp); } static void test_crypto_curve25519_wrappers(void *arg) { curve25519_public_key_t pubkey1, pubkey2; curve25519_secret_key_t seckey1, seckey2; uint8_t output1[CURVE25519_OUTPUT_LEN]; uint8_t output2[CURVE25519_OUTPUT_LEN]; (void)arg; /* Test a simple handshake, serializing and deserializing some stuff. */ curve25519_secret_key_generate(&seckey1, 0); curve25519_secret_key_generate(&seckey2, 1); curve25519_public_key_generate(&pubkey1, &seckey1); curve25519_public_key_generate(&pubkey2, &seckey2); test_assert(curve25519_public_key_is_ok(&pubkey1)); test_assert(curve25519_public_key_is_ok(&pubkey2)); curve25519_handshake(output1, &seckey1, &pubkey2); curve25519_handshake(output2, &seckey2, &pubkey1); test_memeq(output1, output2, sizeof(output1)); done: ; } static void test_crypto_curve25519_encode(void *arg) { curve25519_secret_key_t seckey; curve25519_public_key_t key1, key2, key3; char buf[64]; (void)arg; curve25519_secret_key_generate(&seckey, 0); curve25519_public_key_generate(&key1, &seckey); tt_int_op(0, ==, curve25519_public_to_base64(buf, &key1)); tt_int_op(CURVE25519_BASE64_PADDED_LEN, ==, strlen(buf)); tt_int_op(0, ==, curve25519_public_from_base64(&key2, buf)); test_memeq(key1.public_key, key2.public_key, CURVE25519_PUBKEY_LEN); buf[CURVE25519_BASE64_PADDED_LEN - 1] = '\0'; tt_int_op(CURVE25519_BASE64_PADDED_LEN-1, ==, strlen(buf)); tt_int_op(0, ==, curve25519_public_from_base64(&key3, buf)); test_memeq(key1.public_key, key3.public_key, CURVE25519_PUBKEY_LEN); /* Now try bogus parses. */ strlcpy(buf, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$=", sizeof(buf)); tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf)); strlcpy(buf, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", sizeof(buf)); tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf)); strlcpy(buf, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", sizeof(buf)); tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf)); done: ; } static void test_crypto_curve25519_persist(void *arg) { curve25519_keypair_t keypair, keypair2; char *fname = tor_strdup(get_fname("curve25519_keypair")); char *tag = NULL; char *content = NULL; const char *cp; struct stat st; size_t taglen; (void)arg; tt_int_op(0,==,curve25519_keypair_generate(&keypair, 0)); tt_int_op(0,==,curve25519_keypair_write_to_file(&keypair, fname, "testing")); tt_int_op(0,==,curve25519_keypair_read_from_file(&keypair2, &tag, fname)); tt_str_op(tag,==,"testing"); tor_free(tag); test_memeq(keypair.pubkey.public_key, keypair2.pubkey.public_key, CURVE25519_PUBKEY_LEN); test_memeq(keypair.seckey.secret_key, keypair2.seckey.secret_key, CURVE25519_SECKEY_LEN); content = read_file_to_str(fname, RFTS_BIN, &st); tt_assert(content); taglen = strlen("== c25519v1: testing =="); tt_int_op(st.st_size, ==, 32+CURVE25519_PUBKEY_LEN+CURVE25519_SECKEY_LEN); tt_assert(fast_memeq(content, "== c25519v1: testing ==", taglen)); tt_assert(tor_mem_is_zero(content+taglen, 32-taglen)); cp = content + 32; test_memeq(keypair.seckey.secret_key, cp, CURVE25519_SECKEY_LEN); cp += CURVE25519_SECKEY_LEN; test_memeq(keypair.pubkey.public_key, cp, CURVE25519_SECKEY_LEN); tor_free(fname); fname = tor_strdup(get_fname("bogus_keypair")); tt_int_op(-1, ==, curve25519_keypair_read_from_file(&keypair2, &tag, fname)); tor_free(tag); content[69] ^= 0xff; tt_int_op(0, ==, write_bytes_to_file(fname, content, (size_t)st.st_size, 1)); tt_int_op(-1, ==, curve25519_keypair_read_from_file(&keypair2, &tag, fname)); done: tor_free(fname); tor_free(content); tor_free(tag); } #endif static void * pass_data_setup_fn(const struct testcase_t *testcase) { return testcase->setup_data; } static int pass_data_cleanup_fn(const struct testcase_t *testcase, void *ptr) { (void)ptr; (void)testcase; return 1; } static const struct testcase_setup_t pass_data = { pass_data_setup_fn, pass_data_cleanup_fn }; #define CRYPTO_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_crypto_ ## name } struct testcase_t crypto_tests[] = { CRYPTO_LEGACY(formats), CRYPTO_LEGACY(rng), { "aes_AES", test_crypto_aes, TT_FORK, &pass_data, (void*)"aes" }, { "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" }, CRYPTO_LEGACY(sha), CRYPTO_LEGACY(pk), CRYPTO_LEGACY(dh), CRYPTO_LEGACY(s2k), { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" }, { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" }, CRYPTO_LEGACY(base32_decode), { "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL }, { "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL }, #ifdef CURVE25519_ENABLED { "curve25519_impl", test_crypto_curve25519_impl, 0, NULL, NULL }, { "curve25519_impl_hibit", test_crypto_curve25519_impl, 0, NULL, (void*)"y"}, { "curve25519_wrappers", test_crypto_curve25519_wrappers, 0, NULL, NULL }, { "curve25519_encode", test_crypto_curve25519_encode, 0, NULL, NULL }, { "curve25519_persist", test_crypto_curve25519_persist, 0, NULL, NULL }, #endif END_OF_TESTCASES }; tor-0.2.4.20/src/test/test-child.c0000644000175000017500000000164112166112777013450 00000000000000/* Copyright (c) 2011-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include #include "orconfig.h" #ifdef _WIN32 #define WINDOWS_LEAN_AND_MEAN #include #else #include #endif /** Trivial test program which prints out its command line arguments so we can * check if tor_spawn_background() works */ int main(int argc, char **argv) { int i; fprintf(stdout, "OUT\n"); fprintf(stderr, "ERR\n"); for (i = 1; i < argc; i++) fprintf(stdout, "%s\n", argv[i]); fprintf(stdout, "SLEEPING\n"); /* We need to flush stdout so that test_util_spawn_background_partial_read() succeed. Otherwise ReadFile() will get the entire output in one */ // XXX: Can we make stdio flush on newline? fflush(stdout); #ifdef _WIN32 Sleep(1000); #else sleep(1); #endif fprintf(stdout, "DONE\n"); #ifdef _WIN32 Sleep(1000); #else sleep(1); #endif return 0; } tor-0.2.4.20/src/test/test_util.c0000644000175000017500000030111412255745673013430 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CONTROL_PRIVATE #define MEMPOOL_PRIVATE #define UTIL_PRIVATE #include "or.h" #include "config.h" #include "control.h" #include "test.h" #include "mempool.h" #include "memarea.h" #ifdef _WIN32 #include #endif #include /* XXXX this is a minimal wrapper to make the unit tests compile with the * changed tor_timegm interface. */ static time_t tor_timegm_wrapper(const struct tm *tm) { time_t t; if (tor_timegm(tm, &t) < 0) return -1; return t; } #define tor_timegm tor_timegm_wrapper static void test_util_read_until_eof_impl(const char *fname, size_t file_len, size_t read_limit) { char *fifo_name = NULL; char *test_str = NULL; char *str = NULL; size_t sz = 9999999; int fd = -1; int r; fifo_name = tor_strdup(get_fname(fname)); test_str = tor_malloc(file_len); crypto_rand(test_str, file_len); r = write_bytes_to_file(fifo_name, test_str, file_len, 1); tt_int_op(r, ==, 0); fd = open(fifo_name, O_RDONLY|O_BINARY); tt_int_op(fd, >=, 0); str = read_file_to_str_until_eof(fd, read_limit, &sz); tt_assert(str != NULL); if (read_limit < file_len) tt_int_op(sz, ==, read_limit); else tt_int_op(sz, ==, file_len); test_mem_op(test_str, ==, str, sz); test_assert(str[sz] == '\0'); done: unlink(fifo_name); tor_free(fifo_name); tor_free(test_str); tor_free(str); if (fd >= 0) close(fd); } static void test_util_read_file_eof_tiny_limit(void *arg) { (void)arg; // purposely set limit shorter than what we wrote to the FIFO to // test the maximum, and that it puts the NUL in the right spot test_util_read_until_eof_impl("tor_test_fifo_tiny", 5, 4); } static void test_util_read_file_eof_two_loops(void *arg) { (void)arg; // write more than 1024 bytes to the FIFO to test two passes through // the loop in the method; if the re-alloc size is changed this // should be updated as well. test_util_read_until_eof_impl("tor_test_fifo_2k", 2048, 10000); } static void test_util_read_file_eof_zero_bytes(void *arg) { (void)arg; // zero-byte fifo test_util_read_until_eof_impl("tor_test_fifo_empty", 0, 10000); } static void test_util_time(void) { struct timeval start, end; struct tm a_time; char timestr[128]; time_t t_res; int i; struct timeval tv; /* Test tv_udiff */ start.tv_sec = 5; start.tv_usec = 5000; end.tv_sec = 5; end.tv_usec = 5000; test_eq(0L, tv_udiff(&start, &end)); end.tv_usec = 7000; test_eq(2000L, tv_udiff(&start, &end)); end.tv_sec = 6; test_eq(1002000L, tv_udiff(&start, &end)); end.tv_usec = 0; test_eq(995000L, tv_udiff(&start, &end)); end.tv_sec = 4; test_eq(-1005000L, tv_udiff(&start, &end)); /* Test tor_timegm */ /* The test values here are confirmed to be correct on a platform * with a working timegm. */ a_time.tm_year = 2003-1900; a_time.tm_mon = 7; a_time.tm_mday = 30; a_time.tm_hour = 6; a_time.tm_min = 14; a_time.tm_sec = 55; test_eq((time_t) 1062224095UL, tor_timegm(&a_time)); a_time.tm_year = 2004-1900; /* Try a leap year, after feb. */ test_eq((time_t) 1093846495UL, tor_timegm(&a_time)); a_time.tm_mon = 1; /* Try a leap year, in feb. */ a_time.tm_mday = 10; test_eq((time_t) 1076393695UL, tor_timegm(&a_time)); a_time.tm_mon = 0; a_time.tm_mday = 10; test_eq((time_t) 1073715295UL, tor_timegm(&a_time)); a_time.tm_mon = 12; /* Wrong month, it's 0-based */ a_time.tm_mday = 10; test_eq((time_t) -1, tor_timegm(&a_time)); a_time.tm_mon = -1; /* Wrong month */ a_time.tm_mday = 10; test_eq((time_t) -1, tor_timegm(&a_time)); /* Test {format,parse}_rfc1123_time */ format_rfc1123_time(timestr, 0); test_streq("Thu, 01 Jan 1970 00:00:00 GMT", timestr); format_rfc1123_time(timestr, (time_t)1091580502UL); test_streq("Wed, 04 Aug 2004 00:48:22 GMT", timestr); t_res = 0; i = parse_rfc1123_time(timestr, &t_res); test_eq(0,i); test_eq(t_res, (time_t)1091580502UL); /* The timezone doesn't matter */ t_res = 0; test_eq(0, parse_rfc1123_time("Wed, 04 Aug 2004 00:48:22 ZUL", &t_res)); test_eq(t_res, (time_t)1091580502UL); test_eq(-1, parse_rfc1123_time("Wed, zz Aug 2004 99-99x99 GMT", &t_res)); test_eq(-1, parse_rfc1123_time("Wed, 32 Mar 2011 00:00:00 GMT", &t_res)); test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 24:00:00 GMT", &t_res)); test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:60:00 GMT", &t_res)); test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:62 GMT", &t_res)); test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 1969 23:59:59 GMT", &t_res)); test_eq(-1, parse_rfc1123_time("Wed, 30 Ene 2011 23:59:59 GMT", &t_res)); test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:59 GM", &t_res)); #if 0 /* This fails, I imagine it's important and should be fixed? */ test_eq(-1, parse_rfc1123_time("Wed, 29 Feb 2011 16:00:00 GMT", &t_res)); /* Why is this string valid (ie. the test fails because it doesn't return -1)? */ test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:61 GMT", &t_res)); #endif /* Test parse_iso_time */ t_res = 0; i = parse_iso_time("", &t_res); test_eq(-1, i); t_res = 0; i = parse_iso_time("2004-08-32 00:48:22", &t_res); test_eq(-1, i); t_res = 0; i = parse_iso_time("1969-08-03 00:48:22", &t_res); test_eq(-1, i); t_res = 0; i = parse_iso_time("2004-08-04 00:48:22", &t_res); test_eq(0,i); test_eq(t_res, (time_t)1091580502UL); t_res = 0; i = parse_iso_time("2004-8-4 0:48:22", &t_res); test_eq(0, i); test_eq(t_res, (time_t)1091580502UL); test_eq(-1, parse_iso_time("2004-08-zz 99-99x99 GMT", &t_res)); test_eq(-1, parse_iso_time("2011-03-32 00:00:00 GMT", &t_res)); test_eq(-1, parse_iso_time("2011-03-30 24:00:00 GMT", &t_res)); test_eq(-1, parse_iso_time("2011-03-30 23:60:00 GMT", &t_res)); test_eq(-1, parse_iso_time("2011-03-30 23:59:62 GMT", &t_res)); test_eq(-1, parse_iso_time("1969-03-30 23:59:59 GMT", &t_res)); test_eq(-1, parse_iso_time("2011-00-30 23:59:59 GMT", &t_res)); test_eq(-1, parse_iso_time("2147483647-08-29 14:00:00", &t_res)); test_eq(-1, parse_iso_time("2011-03-30 23:59", &t_res)); /* Test tor_gettimeofday */ end.tv_sec = 4; end.tv_usec = 999990; start.tv_sec = 1; start.tv_usec = 500; tor_gettimeofday(&start); /* now make sure time works. */ tor_gettimeofday(&end); /* We might've timewarped a little. */ tt_int_op(tv_udiff(&start, &end), >=, -5000); /* Test format_iso_time */ tv.tv_sec = (time_t)1326296338; tv.tv_usec = 3060; format_iso_time(timestr, tv.tv_sec); test_streq("2012-01-11 15:38:58", timestr); /* The output of format_local_iso_time will vary by timezone, and setting our timezone for testing purposes would be a nontrivial flaky pain. Skip this test for now. format_local_iso_time(timestr, tv.tv_sec); test_streq("2012-01-11 10:38:58", timestr); */ format_iso_time_nospace(timestr, tv.tv_sec); test_streq("2012-01-11T15:38:58", timestr); test_eq(strlen(timestr), ISO_TIME_LEN); format_iso_time_nospace_usec(timestr, &tv); test_streq("2012-01-11T15:38:58.003060", timestr); test_eq(strlen(timestr), ISO_TIME_USEC_LEN); done: ; } static void test_util_parse_http_time(void *arg) { struct tm a_time; char b[ISO_TIME_LEN+1]; (void)arg; #define T(s) do { \ format_iso_time(b, tor_timegm(&a_time)); \ tt_str_op(b, ==, (s)); \ b[0]='\0'; \ } while (0) /* Test parse_http_time */ test_eq(-1, parse_http_time("", &a_time)); test_eq(-1, parse_http_time("Sunday, 32 Aug 2004 00:48:22 GMT", &a_time)); test_eq(-1, parse_http_time("Sunday, 3 Aug 1869 00:48:22 GMT", &a_time)); test_eq(-1, parse_http_time("Sunday, 32-Aug-94 00:48:22 GMT", &a_time)); test_eq(-1, parse_http_time("Sunday, 3-Ago-04 00:48:22", &a_time)); test_eq(-1, parse_http_time("Sunday, August the third", &a_time)); test_eq(-1, parse_http_time("Wednesday,,04 Aug 1994 00:48:22 GMT", &a_time)); test_eq(0, parse_http_time("Wednesday, 04 Aug 1994 00:48:22 GMT", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Wednesday, 4 Aug 1994 0:48:22 GMT", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Miercoles, 4 Aug 1994 0:48:22 GMT", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Wednesday, 04-Aug-94 00:48:22 GMT", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Wednesday, 4-Aug-94 0:48:22 GMT", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Miercoles, 4-Aug-94 0:48:22 GMT", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Wed Aug 04 00:48:22 1994", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Wed Aug 4 0:48:22 1994", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Mie Aug 4 0:48:22 1994", &a_time)); test_eq((time_t)775961302UL, tor_timegm(&a_time)); T("1994-08-04 00:48:22"); test_eq(0, parse_http_time("Sun, 1 Jan 2012 00:00:00 GMT", &a_time)); test_eq((time_t)1325376000UL, tor_timegm(&a_time)); T("2012-01-01 00:00:00"); test_eq(0, parse_http_time("Mon, 31 Dec 2012 00:00:00 GMT", &a_time)); test_eq((time_t)1356912000UL, tor_timegm(&a_time)); T("2012-12-31 00:00:00"); test_eq(-1, parse_http_time("2004-08-zz 99-99x99 GMT", &a_time)); test_eq(-1, parse_http_time("2011-03-32 00:00:00 GMT", &a_time)); test_eq(-1, parse_http_time("2011-03-30 24:00:00 GMT", &a_time)); test_eq(-1, parse_http_time("2011-03-30 23:60:00 GMT", &a_time)); test_eq(-1, parse_http_time("2011-03-30 23:59:62 GMT", &a_time)); test_eq(-1, parse_http_time("1969-03-30 23:59:59 GMT", &a_time)); test_eq(-1, parse_http_time("2011-00-30 23:59:59 GMT", &a_time)); test_eq(-1, parse_http_time("2011-03-30 23:59", &a_time)); #undef T done: ; } static void test_util_config_line(void) { char buf[1024]; char *k=NULL, *v=NULL; const char *str; /* Test parse_config_line_from_str */ strlcpy(buf, "k v\n" " key value with spaces \n" "keykey val\n" "k2\n" "k3 \n" "\n" " \n" "#comment\n" "k4#a\n" "k5#abc\n" "k6 val #with comment\n" "kseven \"a quoted 'string\"\n" "k8 \"a \\x71uoted\\n\\\"str\\\\ing\\t\\001\\01\\1\\\"\"\n" "k9 a line that\\\n spans two lines.\n\n" "k10 more than\\\n one contin\\\nuation\n" "k11 \\\ncontinuation at the start\n" "k12 line with a\\\n#comment\n embedded\n" "k13\\\ncontinuation at the very start\n" "k14 a line that has a comment and # ends with a slash \\\n" "k15 this should be the next new line\n" "k16 a line that has a comment and # ends without a slash \n" "k17 this should be the next new line\n" , sizeof(buf)); str = buf; str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k"); test_streq(v, "v"); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "key value with")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "key"); test_streq(v, "value with spaces"); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "keykey")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "keykey"); test_streq(v, "val"); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "k2\n")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k2"); test_streq(v, ""); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "k3 \n")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k3"); test_streq(v, ""); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "#comment")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k4"); test_streq(v, ""); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "k5#abc")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k5"); test_streq(v, ""); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "k6")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k6"); test_streq(v, "val"); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "kseven")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "kseven"); test_streq(v, "a quoted \'string"); tor_free(k); tor_free(v); test_assert(!strcmpstart(str, "k8 ")); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k8"); test_streq(v, "a quoted\n\"str\\ing\t\x01\x01\x01\""); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k9"); test_streq(v, "a line that spans two lines."); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k10"); test_streq(v, "more than one continuation"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k11"); test_streq(v, "continuation at the start"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k12"); test_streq(v, "line with a embedded"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k13"); test_streq(v, "continuation at the very start"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k14"); test_streq(v, "a line that has a comment and" ); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k15"); test_streq(v, "this should be the next new line"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k16"); test_streq(v, "a line that has a comment and" ); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k17"); test_streq(v, "this should be the next new line"); tor_free(k); tor_free(v); test_streq(str, ""); done: tor_free(k); tor_free(v); } static void test_util_config_line_quotes(void) { char buf1[1024]; char buf2[128]; char buf3[128]; char buf4[128]; char *k=NULL, *v=NULL; const char *str; /* Test parse_config_line_from_str */ strlcpy(buf1, "kTrailingSpace \"quoted value\" \n" "kTrailingGarbage \"quoted value\"trailing garbage\n" , sizeof(buf1)); strlcpy(buf2, "kTrailingSpaceAndGarbage \"quoted value\" trailing space+g\n" , sizeof(buf2)); strlcpy(buf3, "kMultilineTrailingSpace \"mline\\ \nvalue w/ trailing sp\"\n" , sizeof(buf3)); strlcpy(buf4, "kMultilineNoTrailingBackslash \"naked multiline\nvalue\"\n" , sizeof(buf4)); str = buf1; str = parse_config_line_from_str(str, &k, &v); test_streq(k, "kTrailingSpace"); test_streq(v, "quoted value"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); str = buf2; str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); str = buf3; str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); str = buf4; str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); done: tor_free(k); tor_free(v); } static void test_util_config_line_comment_character(void) { char buf[1024]; char *k=NULL, *v=NULL; const char *str; /* Test parse_config_line_from_str */ strlcpy(buf, "k1 \"# in quotes\"\n" "k2 some value # some comment\n" "k3 /home/user/myTorNetwork#2\n" /* Testcase for #1323 */ , sizeof(buf)); str = buf; str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k1"); test_streq(v, "# in quotes"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k2"); test_streq(v, "some value"); tor_free(k); tor_free(v); test_streq(str, "k3 /home/user/myTorNetwork#2\n"); #if 0 str = parse_config_line_from_str(str, &k, &v); test_streq(k, "k3"); test_streq(v, "/home/user/myTorNetwork#2"); tor_free(k); tor_free(v); test_streq(str, ""); #endif done: tor_free(k); tor_free(v); } static void test_util_config_line_escaped_content(void) { char buf1[1024]; char buf2[128]; char buf3[128]; char buf4[128]; char buf5[128]; char buf6[128]; char *k=NULL, *v=NULL; const char *str; /* Test parse_config_line_from_str */ strlcpy(buf1, "HexadecimalLower \"\\x2a\"\n" "HexadecimalUpper \"\\x2A\"\n" "HexadecimalUpperX \"\\X2A\"\n" "Octal \"\\52\"\n" "Newline \"\\n\"\n" "Tab \"\\t\"\n" "CarriageReturn \"\\r\"\n" "DoubleQuote \"\\\"\"\n" "SimpleQuote \"\\'\"\n" "Backslash \"\\\\\"\n" "Mix \"This is a \\\"star\\\":\\t\\'\\x2a\\'\\nAnd second line\"\n" , sizeof(buf1)); strlcpy(buf2, "BrokenEscapedContent \"\\a\"\n" , sizeof(buf2)); strlcpy(buf3, "BrokenEscapedContent \"\\x\"\n" , sizeof(buf3)); strlcpy(buf4, "BrokenOctal \"\\8\"\n" , sizeof(buf4)); strlcpy(buf5, "BrokenHex \"\\xg4\"\n" , sizeof(buf5)); strlcpy(buf6, "BrokenEscape \"\\" , sizeof(buf6)); str = buf1; str = parse_config_line_from_str(str, &k, &v); test_streq(k, "HexadecimalLower"); test_streq(v, "*"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "HexadecimalUpper"); test_streq(v, "*"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "HexadecimalUpperX"); test_streq(v, "*"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "Octal"); test_streq(v, "*"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "Newline"); test_streq(v, "\n"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "Tab"); test_streq(v, "\t"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "CarriageReturn"); test_streq(v, "\r"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "DoubleQuote"); test_streq(v, "\""); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "SimpleQuote"); test_streq(v, "'"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "Backslash"); test_streq(v, "\\"); tor_free(k); tor_free(v); str = parse_config_line_from_str(str, &k, &v); test_streq(k, "Mix"); test_streq(v, "This is a \"star\":\t'*'\nAnd second line"); tor_free(k); tor_free(v); test_streq(str, ""); str = buf2; str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); str = buf3; str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); str = buf4; str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); #if 0 str = buf5; str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); #endif str = buf6; str = parse_config_line_from_str(str, &k, &v); test_eq_ptr(str, NULL); tor_free(k); tor_free(v); done: tor_free(k); tor_free(v); } #ifndef _WIN32 static void test_util_expand_filename(void) { char *str; setenv("HOME", "/home/itv", 1); /* For "internal test value" */ str = expand_filename(""); test_streq("", str); tor_free(str); str = expand_filename("/normal/path"); test_streq("/normal/path", str); tor_free(str); str = expand_filename("/normal/trailing/path/"); test_streq("/normal/trailing/path/", str); tor_free(str); str = expand_filename("~"); test_streq("/home/itv/", str); tor_free(str); str = expand_filename("$HOME/nodice"); test_streq("$HOME/nodice", str); tor_free(str); str = expand_filename("~/"); test_streq("/home/itv/", str); tor_free(str); str = expand_filename("~/foobarqux"); test_streq("/home/itv/foobarqux", str); tor_free(str); str = expand_filename("~/../../etc/passwd"); test_streq("/home/itv/../../etc/passwd", str); tor_free(str); str = expand_filename("~/trailing/"); test_streq("/home/itv/trailing/", str); tor_free(str); /* Ideally we'd test ~anotheruser, but that's shady to test (we'd have to somehow inject/fake the get_user_homedir call) */ /* $HOME ending in a trailing slash */ setenv("HOME", "/home/itv/", 1); str = expand_filename("~"); test_streq("/home/itv/", str); tor_free(str); str = expand_filename("~/"); test_streq("/home/itv/", str); tor_free(str); str = expand_filename("~/foo"); test_streq("/home/itv/foo", str); tor_free(str); /* Try with empty $HOME */ setenv("HOME", "", 1); str = expand_filename("~"); test_streq("/", str); tor_free(str); str = expand_filename("~/"); test_streq("/", str); tor_free(str); str = expand_filename("~/foobar"); test_streq("/foobar", str); tor_free(str); /* Try with $HOME unset */ unsetenv("HOME"); str = expand_filename("~"); test_streq("/", str); tor_free(str); str = expand_filename("~/"); test_streq("/", str); tor_free(str); str = expand_filename("~/foobar"); test_streq("/foobar", str); tor_free(str); done: tor_free(str); } #endif /** Test basic string functionality. */ static void test_util_strmisc(void) { char buf[1024]; int i; char *cp, *cp_tmp = NULL; /* Test strl operations */ test_eq(5, strlcpy(buf, "Hello", 0)); test_eq(5, strlcpy(buf, "Hello", 10)); test_streq(buf, "Hello"); test_eq(5, strlcpy(buf, "Hello", 6)); test_streq(buf, "Hello"); test_eq(5, strlcpy(buf, "Hello", 5)); test_streq(buf, "Hell"); strlcpy(buf, "Hello", sizeof(buf)); test_eq(10, strlcat(buf, "Hello", 5)); /* Test strstrip() */ strlcpy(buf, "Testing 1 2 3", sizeof(buf)); tor_strstrip(buf, ",!"); test_streq(buf, "Testing 1 2 3"); strlcpy(buf, "!Testing 1 2 3?", sizeof(buf)); tor_strstrip(buf, "!? "); test_streq(buf, "Testing123"); strlcpy(buf, "!!!Testing 1 2 3??", sizeof(buf)); tor_strstrip(buf, "!? "); test_streq(buf, "Testing123"); /* Test parse_long */ /* Empty/zero input */ test_eq(0L, tor_parse_long("",10,0,100,&i,NULL)); test_eq(0, i); test_eq(0L, tor_parse_long("0",10,0,100,&i,NULL)); test_eq(1, i); /* Normal cases */ test_eq(10L, tor_parse_long("10",10,0,100,&i,NULL)); test_eq(1, i); test_eq(10L, tor_parse_long("10",10,0,10,&i,NULL)); test_eq(1, i); test_eq(10L, tor_parse_long("10",10,10,100,&i,NULL)); test_eq(1, i); test_eq(-50L, tor_parse_long("-50",10,-100,100,&i,NULL)); test_eq(1, i); test_eq(-50L, tor_parse_long("-50",10,-100,0,&i,NULL)); test_eq(1, i); test_eq(-50L, tor_parse_long("-50",10,-50,0,&i,NULL)); test_eq(1, i); /* Extra garbage */ test_eq(0L, tor_parse_long("10m",10,0,100,&i,NULL)); test_eq(0, i); test_eq(0L, tor_parse_long("-50 plus garbage",10,-100,100,&i,NULL)); test_eq(0, i); test_eq(10L, tor_parse_long("10m",10,0,100,&i,&cp)); test_eq(1, i); test_streq(cp, "m"); test_eq(-50L, tor_parse_long("-50 plus garbage",10,-100,100,&i,&cp)); test_eq(1, i); test_streq(cp, " plus garbage"); /* Out of bounds */ test_eq(0L, tor_parse_long("10",10,50,100,&i,NULL)); test_eq(0, i); test_eq(0L, tor_parse_long("-50",10,0,100,&i,NULL)); test_eq(0, i); /* Base different than 10 */ test_eq(2L, tor_parse_long("10",2,0,100,NULL,NULL)); test_eq(0L, tor_parse_long("2",2,0,100,NULL,NULL)); test_eq(0L, tor_parse_long("10",-2,0,100,NULL,NULL)); test_eq(68284L, tor_parse_long("10abc",16,0,70000,NULL,NULL)); test_eq(68284L, tor_parse_long("10ABC",16,0,70000,NULL,NULL)); /* Test parse_ulong */ test_eq(0UL, tor_parse_ulong("",10,0,100,NULL,NULL)); test_eq(0UL, tor_parse_ulong("0",10,0,100,NULL,NULL)); test_eq(10UL, tor_parse_ulong("10",10,0,100,NULL,NULL)); test_eq(0UL, tor_parse_ulong("10",10,50,100,NULL,NULL)); test_eq(10UL, tor_parse_ulong("10",10,0,10,NULL,NULL)); test_eq(10UL, tor_parse_ulong("10",10,10,100,NULL,NULL)); test_eq(0UL, tor_parse_ulong("8",8,0,100,NULL,NULL)); test_eq(50UL, tor_parse_ulong("50",10,50,100,NULL,NULL)); test_eq(0UL, tor_parse_ulong("-50",10,-100,100,NULL,NULL)); /* Test parse_uint64 */ test_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); test_eq(1, i); test_streq(cp, " x"); test_assert(U64_LITERAL(12345678901) == tor_parse_uint64("12345678901",10,0,UINT64_MAX, &i, &cp)); test_eq(1, i); test_streq(cp, ""); test_assert(U64_LITERAL(0) == tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp)); test_eq(0, i); { /* Test parse_double */ double d = tor_parse_double("10", 0, UINT64_MAX,&i,NULL); test_eq(1, i); test_assert(DBL_TO_U64(d) == 10); d = tor_parse_double("0", 0, UINT64_MAX,&i,NULL); test_eq(1, i); test_assert(DBL_TO_U64(d) == 0); d = tor_parse_double(" ", 0, UINT64_MAX,&i,NULL); test_eq(0, i); d = tor_parse_double(".0a", 0, UINT64_MAX,&i,NULL); test_eq(0, i); d = tor_parse_double(".0a", 0, UINT64_MAX,&i,&cp); test_eq(1, i); d = tor_parse_double("-.0", 0, UINT64_MAX,&i,NULL); test_eq(1, i); test_assert(DBL_TO_U64(d) == 0); d = tor_parse_double("-10", -100.0, 100.0,&i,NULL); test_eq(1, i); test_eq(-10.0, d); } { /* Test tor_parse_* where we overflow/underflow the underlying type. */ /* This string should overflow 64-bit ints. */ #define TOOBIG "100000000000000000000000000" test_eq(0L, tor_parse_long(TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); test_eq(i, 0); test_eq(0L, tor_parse_long("-"TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); test_eq(i, 0); test_eq(0UL, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL)); test_eq(i, 0); test_eq(U64_LITERAL(0), tor_parse_uint64(TOOBIG, 10, 0, UINT64_MAX, &i, NULL)); test_eq(i, 0); } /* Test snprintf */ /* Returning -1 when there's not enough room in the output buffer */ test_eq(-1, tor_snprintf(buf, 0, "Foo")); test_eq(-1, tor_snprintf(buf, 2, "Foo")); test_eq(-1, tor_snprintf(buf, 3, "Foo")); test_neq(-1, tor_snprintf(buf, 4, "Foo")); /* Always NUL-terminate the output */ tor_snprintf(buf, 5, "abcdef"); test_eq(0, buf[4]); tor_snprintf(buf, 10, "abcdef"); test_eq(0, buf[6]); /* uint64 */ tor_snprintf(buf, sizeof(buf), "x!"U64_FORMAT"!x", U64_PRINTF_ARG(U64_LITERAL(12345678901))); test_streq("x!12345678901!x", buf); /* Test str{,case}cmpstart */ test_assert(strcmpstart("abcdef", "abcdef")==0); test_assert(strcmpstart("abcdef", "abc")==0); test_assert(strcmpstart("abcdef", "abd")<0); test_assert(strcmpstart("abcdef", "abb")>0); test_assert(strcmpstart("ab", "abb")<0); test_assert(strcmpstart("ab", "")==0); test_assert(strcmpstart("ab", "ab ")<0); test_assert(strcasecmpstart("abcdef", "abCdEF")==0); test_assert(strcasecmpstart("abcDeF", "abc")==0); test_assert(strcasecmpstart("abcdef", "Abd")<0); test_assert(strcasecmpstart("Abcdef", "abb")>0); test_assert(strcasecmpstart("ab", "Abb")<0); test_assert(strcasecmpstart("ab", "")==0); test_assert(strcasecmpstart("ab", "ab ")<0); /* Test str{,case}cmpend */ test_assert(strcmpend("abcdef", "abcdef")==0); test_assert(strcmpend("abcdef", "def")==0); test_assert(strcmpend("abcdef", "deg")<0); test_assert(strcmpend("abcdef", "dee")>0); test_assert(strcmpend("ab", "aab")>0); test_assert(strcasecmpend("AbcDEF", "abcdef")==0); test_assert(strcasecmpend("abcdef", "dEF")==0); test_assert(strcasecmpend("abcdef", "Deg")<0); test_assert(strcasecmpend("abcDef", "dee")>0); test_assert(strcasecmpend("AB", "abb")<0); /* Test digest_is_zero */ memset(buf,0,20); buf[20] = 'x'; test_assert(tor_digest_is_zero(buf)); buf[19] = 'x'; test_assert(!tor_digest_is_zero(buf)); /* Test mem_is_zero */ memset(buf,0,128); buf[128] = 'x'; test_assert(tor_mem_is_zero(buf, 10)); test_assert(tor_mem_is_zero(buf, 20)); test_assert(tor_mem_is_zero(buf, 128)); test_assert(!tor_mem_is_zero(buf, 129)); buf[60] = (char)255; test_assert(!tor_mem_is_zero(buf, 128)); buf[0] = (char)1; test_assert(!tor_mem_is_zero(buf, 10)); /* Test 'escaped' */ test_assert(NULL == escaped(NULL)); test_streq("\"\"", escaped("")); test_streq("\"abcd\"", escaped("abcd")); test_streq("\"\\\\ \\n\\r\\t\\\"\\'\"", escaped("\\ \n\r\t\"'")); test_streq("\"unnecessary \\'backslashes\\'\"", escaped("unnecessary \'backslashes\'")); /* Non-printable characters appear as octal */ test_streq("\"z\\001abc\\277d\"", escaped("z\001abc\277d")); test_streq("\"z\\336\\255 ;foo\"", escaped("z\xde\xad\x20;foo")); /* Test strndup and memdup */ { const char *s = "abcdefghijklmnopqrstuvwxyz"; cp_tmp = tor_strndup(s, 30); test_streq(cp_tmp, s); /* same string, */ test_neq_ptr(cp_tmp, s); /* but different pointers. */ tor_free(cp_tmp); cp_tmp = tor_strndup(s, 5); test_streq(cp_tmp, "abcde"); tor_free(cp_tmp); s = "a\0b\0c\0d\0e\0"; cp_tmp = tor_memdup(s,10); test_memeq(cp_tmp, s, 10); /* same ram, */ test_neq_ptr(cp_tmp, s); /* but different pointers. */ tor_free(cp_tmp); } /* Test str-foo functions */ cp = tor_strdup("abcdef"); test_assert(tor_strisnonupper(cp)); cp[3] = 'D'; test_assert(!tor_strisnonupper(cp)); tor_strupper(cp); test_streq(cp, "ABCDEF"); tor_strlower(cp); test_streq(cp, "abcdef"); test_assert(tor_strisnonupper(cp)); test_assert(tor_strisprint(cp)); cp[3] = 3; test_assert(!tor_strisprint(cp)); tor_free(cp); /* Test memmem and memstr */ { const char *haystack = "abcde"; test_assert(!tor_memmem(haystack, 5, "ef", 2)); test_eq_ptr(tor_memmem(haystack, 5, "cd", 2), haystack + 2); test_eq_ptr(tor_memmem(haystack, 5, "cde", 3), haystack + 2); test_assert(!tor_memmem(haystack, 4, "cde", 3)); haystack = "ababcad"; test_eq_ptr(tor_memmem(haystack, 7, "abc", 3), haystack + 2); /* memstr */ test_eq_ptr(tor_memstr(haystack, 7, "abc"), haystack + 2); test_eq_ptr(tor_memstr(haystack, 7, "cad"), haystack + 4); test_assert(!tor_memstr(haystack, 6, "cad")); test_assert(!tor_memstr(haystack, 7, "cadd")); test_assert(!tor_memstr(haystack, 7, "fe")); test_assert(!tor_memstr(haystack, 7, "ababcade")); } /* Test hex_str */ { char binary_data[68]; size_t i; for (i = 0; i < sizeof(binary_data); ++i) binary_data[i] = i; test_streq(hex_str(binary_data, 0), ""); test_streq(hex_str(binary_data, 1), "00"); test_streq(hex_str(binary_data, 17), "000102030405060708090A0B0C0D0E0F10"); test_streq(hex_str(binary_data, 32), "000102030405060708090A0B0C0D0E0F" "101112131415161718191A1B1C1D1E1F"); test_streq(hex_str(binary_data, 34), "000102030405060708090A0B0C0D0E0F" "101112131415161718191A1B1C1D1E1F"); /* Repeat these tests for shorter strings after longer strings have been tried, to make sure we're correctly terminating strings */ test_streq(hex_str(binary_data, 1), "00"); test_streq(hex_str(binary_data, 0), ""); } /* Test strcmp_opt */ tt_int_op(strcmp_opt("", "foo"), <, 0); tt_int_op(strcmp_opt("", ""), ==, 0); tt_int_op(strcmp_opt("foo", ""), >, 0); tt_int_op(strcmp_opt(NULL, ""), <, 0); tt_int_op(strcmp_opt(NULL, NULL), ==, 0); tt_int_op(strcmp_opt("", NULL), >, 0); tt_int_op(strcmp_opt(NULL, "foo"), <, 0); tt_int_op(strcmp_opt("foo", NULL), >, 0); /* Test strcmp_len */ tt_int_op(strcmp_len("foo", "bar", 3), >, 0); tt_int_op(strcmp_len("foo", "bar", 2), <, 0); /* First len, then lexical */ tt_int_op(strcmp_len("foo2", "foo1", 4), >, 0); tt_int_op(strcmp_len("foo2", "foo1", 3), <, 0); /* Really stop at len */ tt_int_op(strcmp_len("foo2", "foo", 3), ==, 0); /* Really stop at len */ tt_int_op(strcmp_len("blah", "", 4), >, 0); tt_int_op(strcmp_len("blah", "", 0), ==, 0); done: tor_free(cp_tmp); } static void test_util_pow2(void) { /* Test tor_log2(). */ test_eq(tor_log2(64), 6); test_eq(tor_log2(65), 6); test_eq(tor_log2(63), 5); test_eq(tor_log2(0), 0); /* incorrect mathematically, but as specified */ test_eq(tor_log2(1), 0); test_eq(tor_log2(2), 1); test_eq(tor_log2(3), 1); test_eq(tor_log2(4), 2); test_eq(tor_log2(5), 2); test_eq(tor_log2(U64_LITERAL(40000000000000000)), 55); test_eq(tor_log2(UINT64_MAX), 63); /* Test round_to_power_of_2 */ test_eq(round_to_power_of_2(120), 128); test_eq(round_to_power_of_2(128), 128); test_eq(round_to_power_of_2(130), 128); test_eq(round_to_power_of_2(U64_LITERAL(40000000000000000)), U64_LITERAL(1)<<55); test_eq(round_to_power_of_2(U64_LITERAL(0xffffffffffffffff)), U64_LITERAL(1)<<63); test_eq(round_to_power_of_2(0), 1); test_eq(round_to_power_of_2(1), 1); test_eq(round_to_power_of_2(2), 2); test_eq(round_to_power_of_2(3), 2); test_eq(round_to_power_of_2(4), 4); test_eq(round_to_power_of_2(5), 4); test_eq(round_to_power_of_2(6), 4); test_eq(round_to_power_of_2(7), 8); done: ; } /** mutex for thread test to stop the threads hitting data at the same time. */ static tor_mutex_t *thread_test_mutex_ = NULL; /** mutexes for the thread test to make sure that the threads have to * interleave somewhat. */ static tor_mutex_t *thread_test_start1_ = NULL, *thread_test_start2_ = NULL; /** Shared strmap for the thread test. */ static strmap_t *thread_test_strmap_ = NULL; /** The name of thread1 for the thread test */ static char *thread1_name_ = NULL; /** The name of thread2 for the thread test */ static char *thread2_name_ = NULL; static void thread_test_func_(void* _s) ATTR_NORETURN; /** How many iterations have the threads in the unit test run? */ static int t1_count = 0, t2_count = 0; /** Helper function for threading unit tests: This function runs in a * subthread. It grabs its own mutex (start1 or start2) to make sure that it * should start, then it repeatedly alters _test_thread_strmap protected by * thread_test_mutex_. */ static void thread_test_func_(void* _s) { char *s = _s; int i, *count; tor_mutex_t *m; char buf[64]; char **cp; if (!strcmp(s, "thread 1")) { m = thread_test_start1_; cp = &thread1_name_; count = &t1_count; } else { m = thread_test_start2_; cp = &thread2_name_; count = &t2_count; } tor_snprintf(buf, sizeof(buf), "%lu", tor_get_thread_id()); *cp = tor_strdup(buf); tor_mutex_acquire(m); for (i=0; i<10000; ++i) { tor_mutex_acquire(thread_test_mutex_); strmap_set(thread_test_strmap_, "last to run", *cp); ++*count; tor_mutex_release(thread_test_mutex_); } tor_mutex_acquire(thread_test_mutex_); strmap_set(thread_test_strmap_, s, *cp); tor_mutex_release(thread_test_mutex_); tor_mutex_release(m); spawn_exit(); } /** Run unit tests for threading logic. */ static void test_util_threads(void) { char *s1 = NULL, *s2 = NULL; int done = 0, timedout = 0; time_t started; #ifndef _WIN32 struct timeval tv; tv.tv_sec=0; tv.tv_usec=100*1000; #endif #ifndef TOR_IS_MULTITHREADED /* Skip this test if we aren't threading. We should be threading most * everywhere by now. */ if (1) return; #endif thread_test_mutex_ = tor_mutex_new(); thread_test_start1_ = tor_mutex_new(); thread_test_start2_ = tor_mutex_new(); thread_test_strmap_ = strmap_new(); s1 = tor_strdup("thread 1"); s2 = tor_strdup("thread 2"); tor_mutex_acquire(thread_test_start1_); tor_mutex_acquire(thread_test_start2_); spawn_func(thread_test_func_, s1); spawn_func(thread_test_func_, s2); tor_mutex_release(thread_test_start2_); tor_mutex_release(thread_test_start1_); started = time(NULL); while (!done) { tor_mutex_acquire(thread_test_mutex_); strmap_assert_ok(thread_test_strmap_); if (strmap_get(thread_test_strmap_, "thread 1") && strmap_get(thread_test_strmap_, "thread 2")) { done = 1; } else if (time(NULL) > started + 150) { timedout = done = 1; } tor_mutex_release(thread_test_mutex_); #ifndef _WIN32 /* Prevent the main thread from starving the worker threads. */ select(0, NULL, NULL, NULL, &tv); #endif } tor_mutex_acquire(thread_test_start1_); tor_mutex_release(thread_test_start1_); tor_mutex_acquire(thread_test_start2_); tor_mutex_release(thread_test_start2_); tor_mutex_free(thread_test_mutex_); if (timedout) { printf("\nTimed out: %d %d", t1_count, t2_count); test_assert(strmap_get(thread_test_strmap_, "thread 1")); test_assert(strmap_get(thread_test_strmap_, "thread 2")); test_assert(!timedout); } /* different thread IDs. */ test_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"), strmap_get(thread_test_strmap_, "thread 2"))); test_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"), strmap_get(thread_test_strmap_, "last to run")) || !strcmp(strmap_get(thread_test_strmap_, "thread 2"), strmap_get(thread_test_strmap_, "last to run"))); done: tor_free(s1); tor_free(s2); tor_free(thread1_name_); tor_free(thread2_name_); if (thread_test_strmap_) strmap_free(thread_test_strmap_, NULL); if (thread_test_start1_) tor_mutex_free(thread_test_start1_); if (thread_test_start2_) tor_mutex_free(thread_test_start2_); } /** Run unit tests for compression functions */ static void test_util_gzip(void) { char *buf1=NULL, *buf2=NULL, *buf3=NULL, *cp1, *cp2; const char *ccp2; size_t len1, len2; tor_zlib_state_t *state = NULL; buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ"); test_assert(detect_compression_method(buf1, strlen(buf1)) == UNKNOWN_METHOD); if (is_gzip_supported()) { test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1, GZIP_METHOD)); test_assert(buf2); test_assert(len1 < strlen(buf1)); test_assert(detect_compression_method(buf2, len1) == GZIP_METHOD); test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1, GZIP_METHOD, 1, LOG_INFO)); test_assert(buf3); test_eq(strlen(buf1) + 1, len2); test_streq(buf1, buf3); tor_free(buf2); tor_free(buf3); } test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1, ZLIB_METHOD)); test_assert(buf2); test_assert(detect_compression_method(buf2, len1) == ZLIB_METHOD); test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1, ZLIB_METHOD, 1, LOG_INFO)); test_assert(buf3); test_eq(strlen(buf1) + 1, len2); test_streq(buf1, buf3); /* Check whether we can uncompress concatenated, compressed strings. */ tor_free(buf3); buf2 = tor_realloc(buf2, len1*2); memcpy(buf2+len1, buf2, len1); test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1*2, ZLIB_METHOD, 1, LOG_INFO)); test_eq((strlen(buf1)+1)*2, len2); test_memeq(buf3, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0", (strlen(buf1)+1)*2); tor_free(buf1); tor_free(buf2); tor_free(buf3); /* Check whether we can uncompress partial strings. */ buf1 = tor_strdup("String with low redundancy that won't be compressed much."); test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1, ZLIB_METHOD)); tt_assert(len1>16); /* when we allow an incomplete string, we should succeed.*/ tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1-16, ZLIB_METHOD, 0, LOG_INFO)); tt_assert(len2 > 5); buf3[len2]='\0'; tt_assert(!strcmpstart(buf1, buf3)); /* when we demand a complete string, this must fail. */ tor_free(buf3); tt_assert(tor_gzip_uncompress(&buf3, &len2, buf2, len1-16, ZLIB_METHOD, 1, LOG_INFO)); tt_assert(!buf3); /* Now, try streaming compression. */ tor_free(buf1); tor_free(buf2); tor_free(buf3); state = tor_zlib_new(1, ZLIB_METHOD); tt_assert(state); cp1 = buf1 = tor_malloc(1024); len1 = 1024; ccp2 = "ABCDEFGHIJABCDEFGHIJ"; len2 = 21; test_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 0) == TOR_ZLIB_OK); test_eq(0, len2); /* Make sure we compressed it all. */ test_assert(cp1 > buf1); len2 = 0; cp2 = cp1; test_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 1) == TOR_ZLIB_DONE); test_eq(0, len2); test_assert(cp1 > cp2); /* Make sure we really added something. */ tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf1, 1024-len1, ZLIB_METHOD, 1, LOG_WARN)); test_streq(buf3, "ABCDEFGHIJABCDEFGHIJ"); /*Make sure it compressed right.*/ test_eq(21, len2); done: if (state) tor_zlib_free(state); tor_free(buf2); tor_free(buf3); tor_free(buf1); } /** Run unit tests for mmap() wrapper functionality. */ static void test_util_mmap(void) { char *fname1 = tor_strdup(get_fname("mapped_1")); char *fname2 = tor_strdup(get_fname("mapped_2")); char *fname3 = tor_strdup(get_fname("mapped_3")); const size_t buflen = 17000; char *buf = tor_malloc(17000); tor_mmap_t *mapping = NULL; crypto_rand(buf, buflen); mapping = tor_mmap_file(fname1); test_assert(! mapping); write_str_to_file(fname1, "Short file.", 1); mapping = tor_mmap_file(fname1); test_assert(mapping); test_eq(mapping->size, strlen("Short file.")); test_streq(mapping->data, "Short file."); #ifdef _WIN32 tor_munmap_file(mapping); mapping = NULL; test_assert(unlink(fname1) == 0); #else /* make sure we can unlink. */ test_assert(unlink(fname1) == 0); test_streq(mapping->data, "Short file."); tor_munmap_file(mapping); mapping = NULL; #endif /* Now a zero-length file. */ write_str_to_file(fname1, "", 1); mapping = tor_mmap_file(fname1); test_eq_ptr(mapping, NULL); test_eq(ERANGE, errno); unlink(fname1); /* Make sure that we fail to map a no-longer-existent file. */ mapping = tor_mmap_file(fname1); test_assert(! mapping); /* Now try a big file that stretches across a few pages and isn't aligned */ write_bytes_to_file(fname2, buf, buflen, 1); mapping = tor_mmap_file(fname2); test_assert(mapping); test_eq(mapping->size, buflen); test_memeq(mapping->data, buf, buflen); tor_munmap_file(mapping); mapping = NULL; /* Now try a big aligned file. */ write_bytes_to_file(fname3, buf, 16384, 1); mapping = tor_mmap_file(fname3); test_assert(mapping); test_eq(mapping->size, 16384); test_memeq(mapping->data, buf, 16384); tor_munmap_file(mapping); mapping = NULL; done: unlink(fname1); unlink(fname2); unlink(fname3); tor_free(fname1); tor_free(fname2); tor_free(fname3); tor_free(buf); if (mapping) tor_munmap_file(mapping); } /** Run unit tests for escaping/unescaping data for use by controllers. */ static void test_util_control_formats(void) { char *out = NULL; const char *inp = "..This is a test\r\n.of the emergency \n..system.\r\n\rZ.\r\n"; size_t sz; sz = read_escaped_data(inp, strlen(inp), &out); test_streq(out, ".This is a test\nof the emergency \n.system.\n\rZ.\n"); test_eq(sz, strlen(out)); done: tor_free(out); } #define test_feq(value1,value2) do { \ double v1 = (value1), v2=(value2); \ double tf_diff = v1-v2; \ double tf_tolerance = ((v1+v2)/2.0)/1e8; \ if (tf_diff<0) tf_diff=-tf_diff; \ if (tf_tolerance<0) tf_tolerance=-tf_tolerance; \ if (tf_diffnew_chunk_capacity >= 100); test_assert(pool->item_alloc_size >= sizeof(void*)+1); mp_pool_destroy(pool); pool = NULL; pool = mp_pool_new(241, 2500); test_assert(pool); test_assert(pool->new_chunk_capacity >= 10); test_assert(pool->item_alloc_size >= sizeof(void*)+241); test_eq(pool->item_alloc_size & 0x03, 0); test_assert(pool->new_chunk_capacity < 60); allocated = smartlist_new(); for (i = 0; i < 20000; ++i) { if (smartlist_len(allocated) < 20 || crypto_rand_int(2)) { void *m = mp_pool_get(pool); memset(m, 0x09, 241); smartlist_add(allocated, m); //printf("%d: %p\n", i, m); //mp_pool_assert_ok(pool); } else { int idx = crypto_rand_int(smartlist_len(allocated)); void *m = smartlist_get(allocated, idx); //printf("%d: free %p\n", i, m); smartlist_del(allocated, idx); mp_pool_release(m); //mp_pool_assert_ok(pool); } if (crypto_rand_int(777)==0) mp_pool_clean(pool, 1, 1); if (i % 777) mp_pool_assert_ok(pool); } done: if (allocated) { SMARTLIST_FOREACH(allocated, void *, m, mp_pool_release(m)); mp_pool_assert_ok(pool); mp_pool_clean(pool, 0, 0); mp_pool_assert_ok(pool); smartlist_free(allocated); } if (pool) mp_pool_destroy(pool); } /** Run unittests for memory area allocator */ static void test_util_memarea(void) { memarea_t *area = memarea_new(); char *p1, *p2, *p3, *p1_orig; void *malloced_ptr = NULL; int i; test_assert(area); p1_orig = p1 = memarea_alloc(area,64); p2 = memarea_alloc_zero(area,52); p3 = memarea_alloc(area,11); test_assert(memarea_owns_ptr(area, p1)); test_assert(memarea_owns_ptr(area, p2)); test_assert(memarea_owns_ptr(area, p3)); /* Make sure we left enough space. */ test_assert(p1+64 <= p2); test_assert(p2+52 <= p3); /* Make sure we aligned. */ test_eq(((uintptr_t)p1) % sizeof(void*), 0); test_eq(((uintptr_t)p2) % sizeof(void*), 0); test_eq(((uintptr_t)p3) % sizeof(void*), 0); test_assert(!memarea_owns_ptr(area, p3+8192)); test_assert(!memarea_owns_ptr(area, p3+30)); test_assert(tor_mem_is_zero(p2, 52)); /* Make sure we don't overalign. */ p1 = memarea_alloc(area, 1); p2 = memarea_alloc(area, 1); test_eq_ptr(p1+sizeof(void*), p2); { malloced_ptr = tor_malloc(64); test_assert(!memarea_owns_ptr(area, malloced_ptr)); tor_free(malloced_ptr); } /* memarea_memdup */ { malloced_ptr = tor_malloc(64); crypto_rand((char*)malloced_ptr, 64); p1 = memarea_memdup(area, malloced_ptr, 64); test_assert(p1 != malloced_ptr); test_memeq(p1, malloced_ptr, 64); tor_free(malloced_ptr); } /* memarea_strdup. */ p1 = memarea_strdup(area,""); p2 = memarea_strdup(area, "abcd"); test_assert(p1); test_assert(p2); test_streq(p1, ""); test_streq(p2, "abcd"); /* memarea_strndup. */ { const char *s = "Ad ogni porta batte la morte e grida: il nome!"; /* (From Turandot, act 3.) */ size_t len = strlen(s); p1 = memarea_strndup(area, s, 1000); p2 = memarea_strndup(area, s, 10); test_streq(p1, s); test_assert(p2 >= p1 + len + 1); test_memeq(s, p2, 10); test_eq(p2[10], '\0'); p3 = memarea_strndup(area, s, len); test_streq(p3, s); p3 = memarea_strndup(area, s, len-1); test_memeq(s, p3, len-1); test_eq(p3[len-1], '\0'); } memarea_clear(area); p1 = memarea_alloc(area, 1); test_eq_ptr(p1, p1_orig); memarea_clear(area); /* Check for running over an area's size. */ for (i = 0; i < 512; ++i) { p1 = memarea_alloc(area, crypto_rand_int(5)+1); test_assert(memarea_owns_ptr(area, p1)); } memarea_assert_ok(area); /* Make sure we can allocate a too-big object. */ p1 = memarea_alloc_zero(area, 9000); p2 = memarea_alloc_zero(area, 16); test_assert(memarea_owns_ptr(area, p1)); test_assert(memarea_owns_ptr(area, p2)); done: memarea_drop_all(area); tor_free(malloced_ptr); } /** Run unit tests for utility functions to get file names relative to * the data directory. */ static void test_util_datadir(void) { char buf[1024]; char *f = NULL; char *temp_dir = NULL; temp_dir = get_datadir_fname(NULL); f = get_datadir_fname("state"); tor_snprintf(buf, sizeof(buf), "%s"PATH_SEPARATOR"state", temp_dir); test_streq(f, buf); tor_free(f); f = get_datadir_fname2("cache", "thingy"); tor_snprintf(buf, sizeof(buf), "%s"PATH_SEPARATOR"cache"PATH_SEPARATOR"thingy", temp_dir); test_streq(f, buf); tor_free(f); f = get_datadir_fname2_suffix("cache", "thingy", ".foo"); tor_snprintf(buf, sizeof(buf), "%s"PATH_SEPARATOR"cache"PATH_SEPARATOR"thingy.foo", temp_dir); test_streq(f, buf); tor_free(f); f = get_datadir_fname_suffix("cache", ".foo"); tor_snprintf(buf, sizeof(buf), "%s"PATH_SEPARATOR"cache.foo", temp_dir); test_streq(f, buf); done: tor_free(f); tor_free(temp_dir); } static void test_util_strtok(void) { char buf[128]; char buf2[128]; int i; char *cp1, *cp2; for (i = 0; i < 3; i++) { const char *pad1="", *pad2=""; switch (i) { case 0: break; case 1: pad1 = " "; pad2 = "!"; break; case 2: pad1 = " "; pad2 = ";!"; break; } tor_snprintf(buf, sizeof(buf), "%s", pad1); tor_snprintf(buf2, sizeof(buf2), "%s", pad2); test_assert(NULL == tor_strtok_r_impl(buf, " ", &cp1)); test_assert(NULL == tor_strtok_r_impl(buf2, ".!..;!", &cp2)); tor_snprintf(buf, sizeof(buf), "%sGraved on the dark in gestures of descent%s", pad1, pad1); tor_snprintf(buf2, sizeof(buf2), "%sthey.seemed;;their!.own;most.perfect;monument%s",pad2,pad2); /* -- "Year's End", Richard Wilbur */ test_streq("Graved", tor_strtok_r_impl(buf, " ", &cp1)); test_streq("they", tor_strtok_r_impl(buf2, ".!..;!", &cp2)); #define S1() tor_strtok_r_impl(NULL, " ", &cp1) #define S2() tor_strtok_r_impl(NULL, ".!..;!", &cp2) test_streq("on", S1()); test_streq("the", S1()); test_streq("dark", S1()); test_streq("seemed", S2()); test_streq("their", S2()); test_streq("own", S2()); test_streq("in", S1()); test_streq("gestures", S1()); test_streq("of", S1()); test_streq("most", S2()); test_streq("perfect", S2()); test_streq("descent", S1()); test_streq("monument", S2()); test_eq_ptr(NULL, S1()); test_eq_ptr(NULL, S2()); } buf[0] = 0; test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1)); test_eq_ptr(NULL, tor_strtok_r_impl(buf, "!", &cp1)); strlcpy(buf, "Howdy!", sizeof(buf)); test_streq("Howdy", tor_strtok_r_impl(buf, "!", &cp1)); test_eq_ptr(NULL, tor_strtok_r_impl(NULL, "!", &cp1)); strlcpy(buf, " ", sizeof(buf)); test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1)); strlcpy(buf, " ", sizeof(buf)); test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1)); strlcpy(buf, "something ", sizeof(buf)); test_streq("something", tor_strtok_r_impl(buf, " ", &cp1)); test_eq_ptr(NULL, tor_strtok_r_impl(NULL, ";", &cp1)); done: ; } static void test_util_find_str_at_start_of_line(void *ptr) { const char *long_string = "howdy world. how are you? i hope it's fine.\n" "hello kitty\n" "third line"; char *line2 = strchr(long_string,'\n')+1; char *line3 = strchr(line2,'\n')+1; const char *short_string = "hello kitty\n" "second line\n"; char *short_line2 = strchr(short_string,'\n')+1; (void)ptr; test_eq_ptr(long_string, find_str_at_start_of_line(long_string, "")); test_eq_ptr(NULL, find_str_at_start_of_line(short_string, "nonsense")); test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "nonsense")); test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "\n")); test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "how ")); test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "kitty")); test_eq_ptr(long_string, find_str_at_start_of_line(long_string, "h")); test_eq_ptr(long_string, find_str_at_start_of_line(long_string, "how")); test_eq_ptr(line2, find_str_at_start_of_line(long_string, "he")); test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hell")); test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello k")); test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello kitty\n")); test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello kitty\nt")); test_eq_ptr(line3, find_str_at_start_of_line(long_string, "third")); test_eq_ptr(line3, find_str_at_start_of_line(long_string, "third line")); test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "third line\n")); test_eq_ptr(short_line2, find_str_at_start_of_line(short_string, "second line\n")); done: ; } static void test_util_string_is_C_identifier(void *ptr) { (void)ptr; test_eq(1, string_is_C_identifier("string_is_C_identifier")); test_eq(1, string_is_C_identifier("_string_is_C_identifier")); test_eq(1, string_is_C_identifier("_")); test_eq(1, string_is_C_identifier("i")); test_eq(1, string_is_C_identifier("_____")); test_eq(1, string_is_C_identifier("__00__")); test_eq(1, string_is_C_identifier("__init__")); test_eq(1, string_is_C_identifier("_0")); test_eq(1, string_is_C_identifier("_0string_is_C_identifier")); test_eq(1, string_is_C_identifier("_0")); test_eq(0, string_is_C_identifier("0_string_is_C_identifier")); test_eq(0, string_is_C_identifier("0")); test_eq(0, string_is_C_identifier("")); test_eq(0, string_is_C_identifier(";")); test_eq(0, string_is_C_identifier("i;")); test_eq(0, string_is_C_identifier("_;")); test_eq(0, string_is_C_identifier("í")); test_eq(0, string_is_C_identifier("ñ")); done: ; } static void test_util_asprintf(void *ptr) { #define LOREMIPSUM \ "Lorem ipsum dolor sit amet, consectetur adipisicing elit" char *cp=NULL, *cp2=NULL; int r; (void)ptr; /* simple string */ r = tor_asprintf(&cp, "simple string 100%% safe"); test_assert(cp); test_streq("simple string 100% safe", cp); test_eq(strlen(cp), r); /* empty string */ r = tor_asprintf(&cp, "%s", ""); test_assert(cp); test_streq("", cp); test_eq(strlen(cp), r); /* numbers (%i) */ r = tor_asprintf(&cp, "I like numbers-%2i, %i, etc.", -1, 2); test_assert(cp); test_streq("I like numbers--1, 2, etc.", cp); test_eq(strlen(cp), r); /* numbers (%d) */ r = tor_asprintf(&cp2, "First=%d, Second=%d", 101, 202); test_assert(cp2); test_eq(strlen(cp2), r); test_streq("First=101, Second=202", cp2); test_assert(cp != cp2); tor_free(cp); tor_free(cp2); /* Glass-box test: a string exactly 128 characters long. */ r = tor_asprintf(&cp, "Lorem1: %sLorem2: %s", LOREMIPSUM, LOREMIPSUM); test_assert(cp); test_eq(128, r); test_assert(cp[128] == '\0'); test_streq("Lorem1: "LOREMIPSUM"Lorem2: "LOREMIPSUM, cp); tor_free(cp); /* String longer than 128 characters */ r = tor_asprintf(&cp, "1: %s 2: %s 3: %s", LOREMIPSUM, LOREMIPSUM, LOREMIPSUM); test_assert(cp); test_eq(strlen(cp), r); test_streq("1: "LOREMIPSUM" 2: "LOREMIPSUM" 3: "LOREMIPSUM, cp); done: tor_free(cp); tor_free(cp2); } static void test_util_listdir(void *ptr) { smartlist_t *dir_contents = NULL; char *fname1=NULL, *fname2=NULL, *fname3=NULL, *dir1=NULL, *dirname=NULL; int r; (void)ptr; fname1 = tor_strdup(get_fname("hopscotch")); fname2 = tor_strdup(get_fname("mumblety-peg")); fname3 = tor_strdup(get_fname(".hidden-file")); dir1 = tor_strdup(get_fname("some-directory")); dirname = tor_strdup(get_fname(NULL)); test_eq(0, write_str_to_file(fname1, "X\n", 0)); test_eq(0, write_str_to_file(fname2, "Y\n", 0)); test_eq(0, write_str_to_file(fname3, "Z\n", 0)); #ifdef _WIN32 r = mkdir(dir1); #else r = mkdir(dir1, 0700); #endif if (r) { fprintf(stderr, "Can't create directory %s:", dir1); perror(""); exit(1); } dir_contents = tor_listdir(dirname); test_assert(dir_contents); /* make sure that each filename is listed. */ test_assert(smartlist_contains_string_case(dir_contents, "hopscotch")); test_assert(smartlist_contains_string_case(dir_contents, "mumblety-peg")); test_assert(smartlist_contains_string_case(dir_contents, ".hidden-file")); test_assert(smartlist_contains_string_case(dir_contents, "some-directory")); test_assert(!smartlist_contains_string(dir_contents, ".")); test_assert(!smartlist_contains_string(dir_contents, "..")); done: tor_free(fname1); tor_free(fname2); tor_free(dirname); if (dir_contents) { SMARTLIST_FOREACH(dir_contents, char *, cp, tor_free(cp)); smartlist_free(dir_contents); } } static void test_util_parent_dir(void *ptr) { char *cp; (void)ptr; #define T(output,expect_ok,input) \ do { \ int ok; \ cp = tor_strdup(input); \ ok = get_parent_directory(cp); \ tt_int_op(expect_ok, ==, ok); \ if (ok==0) \ tt_str_op(output, ==, cp); \ tor_free(cp); \ } while (0); T("/home/wombat", 0, "/home/wombat/knish"); T("/home/wombat", 0, "/home/wombat/knish/"); T("/home/wombat", 0, "/home/wombat/knish///"); T("./home/wombat", 0, "./home/wombat/knish/"); T("/", 0, "/home"); T("/", 0, "/home//"); T(".", 0, "./wombat"); T(".", 0, "./wombat/"); T(".", 0, "./wombat//"); T("wombat", 0, "wombat/foo"); T("wombat/..", 0, "wombat/../foo"); T("wombat/../", 0, "wombat/..//foo"); /* Is this correct? */ T("wombat/.", 0, "wombat/./foo"); T("wombat/./", 0, "wombat/.//foo"); /* Is this correct? */ T("wombat", 0, "wombat/..//"); T("wombat", 0, "wombat/foo/"); T("wombat", 0, "wombat/.foo"); T("wombat", 0, "wombat/.foo/"); T("wombat", -1, ""); T("w", -1, ""); T("wombat", 0, "wombat/knish"); T("/", 0, "/"); T("/", 0, "////"); done: tor_free(cp); } #ifdef _WIN32 static void test_util_load_win_lib(void *ptr) { HANDLE h = load_windows_system_library(_T("advapi32.dll")); (void) ptr; tt_assert(h); done: if (h) FreeLibrary(h); } #endif static void clear_hex_errno(char *hex_errno) { memset(hex_errno, '\0', HEX_ERRNO_SIZE + 1); } static void test_util_exit_status(void *ptr) { /* Leave an extra byte for a \0 so we can do string comparison */ char hex_errno[HEX_ERRNO_SIZE + 1]; int n; (void)ptr; clear_hex_errno(hex_errno); n = format_helper_exit_status(0, 0, hex_errno); test_streq("0/0\n", hex_errno); test_eq(n, strlen(hex_errno)); clear_hex_errno(hex_errno); n = format_helper_exit_status(0, 0x7FFFFFFF, hex_errno); test_streq("0/7FFFFFFF\n", hex_errno); test_eq(n, strlen(hex_errno)); clear_hex_errno(hex_errno); n = format_helper_exit_status(0xFF, -0x80000000, hex_errno); test_streq("FF/-80000000\n", hex_errno); test_eq(n, strlen(hex_errno)); test_eq(n, HEX_ERRNO_SIZE); clear_hex_errno(hex_errno); n = format_helper_exit_status(0x7F, 0, hex_errno); test_streq("7F/0\n", hex_errno); test_eq(n, strlen(hex_errno)); clear_hex_errno(hex_errno); n = format_helper_exit_status(0x08, -0x242, hex_errno); test_streq("8/-242\n", hex_errno); test_eq(n, strlen(hex_errno)); done: ; } #ifndef _WIN32 /** Check that fgets waits until a full line, and not return a partial line, on * a EAGAIN with a non-blocking pipe */ static void test_util_fgets_eagain(void *ptr) { int test_pipe[2] = {-1, -1}; int retval; ssize_t retlen; char *retptr; FILE *test_stream = NULL; char buf[10]; (void)ptr; /* Set up a pipe to test on */ retval = pipe(test_pipe); tt_int_op(retval, >=, 0); /* Set up the read-end to be non-blocking */ retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK); tt_int_op(retval, >=, 0); /* Open it as a stdio stream */ test_stream = fdopen(test_pipe[0], "r"); tt_ptr_op(test_stream, !=, NULL); /* Send in a partial line */ retlen = write(test_pipe[1], "A", 1); tt_int_op(retlen, ==, 1); retptr = fgets(buf, sizeof(buf), test_stream); tt_want(retptr == NULL); tt_int_op(errno, ==, EAGAIN); /* Send in the rest */ retlen = write(test_pipe[1], "B\n", 2); tt_int_op(retlen, ==, 2); retptr = fgets(buf, sizeof(buf), test_stream); tt_ptr_op(retptr, ==, buf); tt_str_op(buf, ==, "AB\n"); /* Send in a full line */ retlen = write(test_pipe[1], "CD\n", 3); tt_int_op(retlen, ==, 3); retptr = fgets(buf, sizeof(buf), test_stream); tt_ptr_op(retptr, ==, buf); tt_str_op(buf, ==, "CD\n"); /* Send in a partial line */ retlen = write(test_pipe[1], "E", 1); tt_int_op(retlen, ==, 1); retptr = fgets(buf, sizeof(buf), test_stream); tt_ptr_op(retptr, ==, NULL); tt_int_op(errno, ==, EAGAIN); /* Send in the rest */ retlen = write(test_pipe[1], "F\n", 2); tt_int_op(retlen, ==, 2); retptr = fgets(buf, sizeof(buf), test_stream); tt_ptr_op(retptr, ==, buf); tt_str_op(buf, ==, "EF\n"); /* Send in a full line and close */ retlen = write(test_pipe[1], "GH", 2); tt_int_op(retlen, ==, 2); retval = close(test_pipe[1]); test_pipe[1] = -1; tt_int_op(retval, ==, 0); retptr = fgets(buf, sizeof(buf), test_stream); tt_ptr_op(retptr, ==, buf); tt_str_op(buf, ==, "GH"); /* Check for EOF */ retptr = fgets(buf, sizeof(buf), test_stream); tt_ptr_op(retptr, ==, NULL); tt_int_op(feof(test_stream), >, 0); done: if (test_stream != NULL) fclose(test_stream); if (test_pipe[0] != -1) close(test_pipe[0]); if (test_pipe[1] != -1) close(test_pipe[1]); } #endif /** Helper function for testing tor_spawn_background */ static void run_util_spawn_background(const char *argv[], const char *expected_out, const char *expected_err, int expected_exit, int expected_status) { int retval, exit_code; ssize_t pos; process_handle_t *process_handle=NULL; char stdout_buf[100], stderr_buf[100]; int status; /* Start the program */ #ifdef _WIN32 status = tor_spawn_background(NULL, argv, NULL, &process_handle); #else status = tor_spawn_background(argv[0], argv, NULL, &process_handle); #endif test_eq(expected_status, status); if (status == PROCESS_STATUS_ERROR) return; test_assert(process_handle != NULL); test_eq(expected_status, process_handle->status); #ifdef _WIN32 test_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE); test_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE); #else test_assert(process_handle->stdout_pipe > 0); test_assert(process_handle->stderr_pipe > 0); #endif /* Check stdout */ pos = tor_read_all_from_process_stdout(process_handle, stdout_buf, sizeof(stdout_buf) - 1); tt_assert(pos >= 0); stdout_buf[pos] = '\0'; test_eq(strlen(expected_out), pos); test_streq(expected_out, stdout_buf); /* Check it terminated correctly */ retval = tor_get_exit_code(process_handle, 1, &exit_code); test_eq(PROCESS_EXIT_EXITED, retval); test_eq(expected_exit, exit_code); // TODO: Make test-child exit with something other than 0 /* Check stderr */ pos = tor_read_all_from_process_stderr(process_handle, stderr_buf, sizeof(stderr_buf) - 1); test_assert(pos >= 0); stderr_buf[pos] = '\0'; test_streq(expected_err, stderr_buf); test_eq(strlen(expected_err), pos); done: if (process_handle) tor_process_handle_destroy(process_handle, 1); } /** Check that we can launch a process and read the output */ static void test_util_spawn_background_ok(void *ptr) { #ifdef _WIN32 const char *argv[] = {"test-child.exe", "--test", NULL}; const char *expected_out = "OUT\r\n--test\r\nSLEEPING\r\nDONE\r\n"; const char *expected_err = "ERR\r\n"; #else const char *argv[] = {BUILDDIR "/src/test/test-child", "--test", NULL}; const char *expected_out = "OUT\n--test\nSLEEPING\nDONE\n"; const char *expected_err = "ERR\n"; #endif (void)ptr; run_util_spawn_background(argv, expected_out, expected_err, 0, PROCESS_STATUS_RUNNING); } /** Check that failing to find the executable works as expected */ static void test_util_spawn_background_fail(void *ptr) { #ifndef BUILDDIR #define BUILDDIR "." #endif const char *argv[] = {BUILDDIR "/src/test/no-such-file", "--test", NULL}; const char *expected_err = ""; char expected_out[1024]; char code[32]; #ifdef _WIN32 const int expected_status = PROCESS_STATUS_ERROR; #else /* TODO: Once we can signal failure to exec, set this to be * PROCESS_STATUS_ERROR */ const int expected_status = PROCESS_STATUS_RUNNING; #endif (void)ptr; tor_snprintf(code, sizeof(code), "%x/%x", 9 /* CHILD_STATE_FAILEXEC */ , ENOENT); tor_snprintf(expected_out, sizeof(expected_out), "ERR: Failed to spawn background process - code %s\n", code); run_util_spawn_background(argv, expected_out, expected_err, 255, expected_status); } /** Test that reading from a handle returns a partial read rather than * blocking */ static void test_util_spawn_background_partial_read(void *ptr) { const int expected_exit = 0; const int expected_status = PROCESS_STATUS_RUNNING; int retval, exit_code; ssize_t pos = -1; process_handle_t *process_handle=NULL; int status; char stdout_buf[100], stderr_buf[100]; #ifdef _WIN32 const char *argv[] = {"test-child.exe", "--test", NULL}; const char *expected_out[] = { "OUT\r\n--test\r\nSLEEPING\r\n", "DONE\r\n", NULL }; const char *expected_err = "ERR\r\n"; #else const char *argv[] = {BUILDDIR "/src/test/test-child", "--test", NULL}; const char *expected_out[] = { "OUT\n--test\nSLEEPING\n", "DONE\n", NULL }; const char *expected_err = "ERR\n"; int eof = 0; #endif int expected_out_ctr; (void)ptr; /* Start the program */ #ifdef _WIN32 status = tor_spawn_background(NULL, argv, NULL, &process_handle); #else status = tor_spawn_background(argv[0], argv, NULL, &process_handle); #endif test_eq(expected_status, status); test_assert(process_handle); test_eq(expected_status, process_handle->status); /* Check stdout */ for (expected_out_ctr = 0; expected_out[expected_out_ctr] != NULL;) { #ifdef _WIN32 pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf, sizeof(stdout_buf) - 1, NULL); #else /* Check that we didn't read the end of file last time */ test_assert(!eof); pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf, sizeof(stdout_buf) - 1, NULL, &eof); #endif log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos); /* We would have blocked, keep on trying */ if (0 == pos) continue; test_assert(pos > 0); stdout_buf[pos] = '\0'; test_streq(expected_out[expected_out_ctr], stdout_buf); test_eq(strlen(expected_out[expected_out_ctr]), pos); expected_out_ctr++; } /* The process should have exited without writing more */ #ifdef _WIN32 pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf, sizeof(stdout_buf) - 1, process_handle); test_eq(0, pos); #else if (!eof) { /* We should have got all the data, but maybe not the EOF flag */ pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf, sizeof(stdout_buf) - 1, process_handle, &eof); test_eq(0, pos); test_assert(eof); } /* Otherwise, we got the EOF on the last read */ #endif /* Check it terminated correctly */ retval = tor_get_exit_code(process_handle, 1, &exit_code); test_eq(PROCESS_EXIT_EXITED, retval); test_eq(expected_exit, exit_code); // TODO: Make test-child exit with something other than 0 /* Check stderr */ pos = tor_read_all_from_process_stderr(process_handle, stderr_buf, sizeof(stderr_buf) - 1); test_assert(pos >= 0); stderr_buf[pos] = '\0'; test_streq(expected_err, stderr_buf); test_eq(strlen(expected_err), pos); done: tor_process_handle_destroy(process_handle, 1); } /** * Test for format_hex_number_for_helper_exit_status() */ static void test_util_format_hex_number(void *ptr) { int i, len; char buf[HEX_ERRNO_SIZE + 1]; const struct { const char *str; unsigned int x; } test_data[] = { {"0", 0}, {"1", 1}, {"273A", 0x273a}, {"FFFF", 0xffff}, #if UINT_MAX >= 0xffffffff {"31BC421D", 0x31bc421d}, {"FFFFFFFF", 0xffffffff}, #endif {NULL, 0} }; (void)ptr; for (i = 0; test_data[i].str != NULL; ++i) { len = format_hex_number_for_helper_exit_status(test_data[i].x, buf, HEX_ERRNO_SIZE); test_neq(len, 0); buf[len] = '\0'; test_streq(buf, test_data[i].str); } done: return; } /** * Test that we can properly format q Windows command line */ static void test_util_join_win_cmdline(void *ptr) { /* Based on some test cases from "Parsing C++ Command-Line Arguments" in * MSDN but we don't exercise all quoting rules because tor_join_win_cmdline * will try to only generate simple cases for the child process to parse; * i.e. we never embed quoted strings in arguments. */ const char *argvs[][4] = { {"a", "bb", "CCC", NULL}, // Normal {NULL, NULL, NULL, NULL}, // Empty argument list {"", NULL, NULL, NULL}, // Empty argument {"\"a", "b\"b", "CCC\"", NULL}, // Quotes {"a\tbc", "dd dd", "E", NULL}, // Whitespace {"a\\\\\\b", "de fg", "H", NULL}, // Backslashes {"a\\\"b", "\\c", "D\\", NULL}, // Backslashes before quote {"a\\\\b c", "d", "E", NULL}, // Backslashes not before quote { NULL } // Terminator }; const char *cmdlines[] = { "a bb CCC", "", "\"\"", "\\\"a b\\\"b CCC\\\"", "\"a\tbc\" \"dd dd\" E", "a\\\\\\b \"de fg\" H", "a\\\\\\\"b \\c D\\", "\"a\\\\b c\" d E", NULL // Terminator }; int i; char *joined_argv = NULL; (void)ptr; for (i=0; cmdlines[i]!=NULL; i++) { log_info(LD_GENERAL, "Joining argvs[%d], expecting <%s>", i, cmdlines[i]); joined_argv = tor_join_win_cmdline(argvs[i]); test_streq(cmdlines[i], joined_argv); tor_free(joined_argv); } done: tor_free(joined_argv); } #define MAX_SPLIT_LINE_COUNT 4 struct split_lines_test_t { const char *orig_line; // Line to be split (may contain \0's) int orig_length; // Length of orig_line const char *split_line[MAX_SPLIT_LINE_COUNT]; // Split lines }; /** * Test that we properly split a buffer into lines */ static void test_util_split_lines(void *ptr) { /* Test cases. orig_line of last test case must be NULL. * The last element of split_line[i] must be NULL. */ struct split_lines_test_t tests[] = { {"", 0, {NULL}}, {"foo", 3, {"foo", NULL}}, {"\n\rfoo\n\rbar\r\n", 12, {"foo", "bar", NULL}}, {"fo o\r\nb\tar", 10, {"fo o", "b.ar", NULL}}, {"\x0f""f\0o\0\n\x01""b\0r\0\r", 12, {".f.o.", ".b.r.", NULL}}, {"line 1\r\nline 2", 14, {"line 1", "line 2", NULL}}, {"line 1\r\n\r\nline 2", 16, {"line 1", "line 2", NULL}}, {"line 1\r\n\r\r\r\nline 2", 18, {"line 1", "line 2", NULL}}, {"line 1\r\n\n\n\n\rline 2", 18, {"line 1", "line 2", NULL}}, {"line 1\r\n\r\t\r\nline 3", 18, {"line 1", ".", "line 3", NULL}}, {"\n\t\r\t\nline 3", 11, {".", ".", "line 3", NULL}}, {NULL, 0, { NULL }} }; int i, j; char *orig_line=NULL; smartlist_t *sl=NULL; (void)ptr; for (i=0; tests[i].orig_line; i++) { sl = smartlist_new(); /* Allocate space for string and trailing NULL */ orig_line = tor_memdup(tests[i].orig_line, tests[i].orig_length + 1); tor_split_lines(sl, orig_line, tests[i].orig_length); j = 0; log_info(LD_GENERAL, "Splitting test %d of length %d", i, tests[i].orig_length); SMARTLIST_FOREACH_BEGIN(sl, const char *, line) { /* Check we have not got too many lines */ test_assert(j < MAX_SPLIT_LINE_COUNT); /* Check that there actually should be a line here */ test_assert(tests[i].split_line[j] != NULL); log_info(LD_GENERAL, "Line %d of test %d, should be <%s>", j, i, tests[i].split_line[j]); /* Check that the line is as expected */ test_streq(line, tests[i].split_line[j]); j++; } SMARTLIST_FOREACH_END(line); /* Check that we didn't miss some lines */ test_eq_ptr(NULL, tests[i].split_line[j]); tor_free(orig_line); smartlist_free(sl); sl = NULL; } done: tor_free(orig_line); smartlist_free(sl); } static void test_util_di_ops(void) { #define LT -1 #define GT 1 #define EQ 0 const struct { const char *a; int want_sign; const char *b; } examples[] = { { "Foo", EQ, "Foo" }, { "foo", GT, "bar", }, { "foobar", EQ ,"foobar" }, { "foobar", LT, "foobaw" }, { "foobar", GT, "f00bar" }, { "foobar", GT, "boobar" }, { "", EQ, "" }, { NULL, 0, NULL }, }; int i; for (i = 0; examples[i].a; ++i) { size_t len = strlen(examples[i].a); int eq1, eq2, neq1, neq2, cmp1, cmp2; test_eq(len, strlen(examples[i].b)); /* We do all of the operations, with operands in both orders. */ eq1 = tor_memeq(examples[i].a, examples[i].b, len); eq2 = tor_memeq(examples[i].b, examples[i].a, len); neq1 = tor_memneq(examples[i].a, examples[i].b, len); neq2 = tor_memneq(examples[i].b, examples[i].a, len); cmp1 = tor_memcmp(examples[i].a, examples[i].b, len); cmp2 = tor_memcmp(examples[i].b, examples[i].a, len); /* Check for correctness of cmp1 */ if (cmp1 < 0 && examples[i].want_sign != LT) test_fail(); else if (cmp1 > 0 && examples[i].want_sign != GT) test_fail(); else if (cmp1 == 0 && examples[i].want_sign != EQ) test_fail(); /* Check for consistency of everything else with cmp1 */ test_eq(eq1, eq2); test_eq(neq1, neq2); test_eq(cmp1, -cmp2); test_eq(eq1, cmp1 == 0); test_eq(neq1, !eq1); } tt_int_op(1, ==, safe_mem_is_zero("", 0)); tt_int_op(1, ==, safe_mem_is_zero("", 1)); tt_int_op(0, ==, safe_mem_is_zero("a", 1)); tt_int_op(0, ==, safe_mem_is_zero("a", 2)); tt_int_op(0, ==, safe_mem_is_zero("\0a", 2)); tt_int_op(1, ==, safe_mem_is_zero("\0\0a", 2)); tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0", 8)); tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 8)); tt_int_op(0, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 9)); done: ; } /** * Test counting high bits */ static void test_util_n_bits_set(void *ptr) { (void)ptr; test_eq(0, n_bits_set_u8(0)); test_eq(1, n_bits_set_u8(1)); test_eq(3, n_bits_set_u8(7)); test_eq(1, n_bits_set_u8(8)); test_eq(2, n_bits_set_u8(129)); test_eq(8, n_bits_set_u8(255)); done: ; } /** * Test LHS whitespace (and comment) eater */ static void test_util_eat_whitespace(void *ptr) { const char ws[] = { ' ', '\t', '\r' }; /* Except NL */ char str[80]; size_t i; (void)ptr; /* Try one leading ws */ strcpy(str, "fuubaar"); for (i = 0; i < sizeof(ws); ++i) { str[0] = ws[i]; test_eq_ptr(str + 1, eat_whitespace(str)); test_eq_ptr(str + 1, eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + 1, eat_whitespace_no_nl(str)); test_eq_ptr(str + 1, eat_whitespace_eos_no_nl(str, str + strlen(str))); } str[0] = '\n'; test_eq_ptr(str + 1, eat_whitespace(str)); test_eq_ptr(str + 1, eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str, eat_whitespace_no_nl(str)); test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Empty string */ strcpy(str, ""); test_eq_ptr(str, eat_whitespace(str)); test_eq_ptr(str, eat_whitespace_eos(str, str)); test_eq_ptr(str, eat_whitespace_no_nl(str)); test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str)); /* Only ws */ strcpy(str, " \t\r\n"); test_eq_ptr(str + strlen(str), eat_whitespace(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + strlen(str) - 1, eat_whitespace_no_nl(str)); test_eq_ptr(str + strlen(str) - 1, eat_whitespace_eos_no_nl(str, str + strlen(str))); strcpy(str, " \t\r "); test_eq_ptr(str + strlen(str), eat_whitespace(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + strlen(str), eat_whitespace_no_nl(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Multiple ws */ strcpy(str, "fuubaar"); for (i = 0; i < sizeof(ws); ++i) str[i] = ws[i]; test_eq_ptr(str + sizeof(ws), eat_whitespace(str)); test_eq_ptr(str + sizeof(ws), eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + sizeof(ws), eat_whitespace_no_nl(str)); test_eq_ptr(str + sizeof(ws), eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Eat comment */ strcpy(str, "# Comment \n No Comment"); test_streq("No Comment", eat_whitespace(str)); test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str, eat_whitespace_no_nl(str)); test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Eat comment & ws mix */ strcpy(str, " # \t Comment \n\t\nNo Comment"); test_streq("No Comment", eat_whitespace(str)); test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + 1, eat_whitespace_no_nl(str)); test_eq_ptr(str + 1, eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Eat entire comment */ strcpy(str, "#Comment"); test_eq_ptr(str + strlen(str), eat_whitespace(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str, eat_whitespace_no_nl(str)); test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Blank line, then comment */ strcpy(str, " \t\n # Comment"); test_eq_ptr(str + strlen(str), eat_whitespace(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + 2, eat_whitespace_no_nl(str)); test_eq_ptr(str + 2, eat_whitespace_eos_no_nl(str, str + strlen(str))); done: ; } /** Return a newly allocated smartlist containing the lines of text in * lines. The returned strings are heap-allocated, and must be * freed by the caller. * * XXXX? Move to container.[hc] ? */ static smartlist_t * smartlist_new_from_text_lines(const char *lines) { smartlist_t *sl = smartlist_new(); char *last_line; smartlist_split_string(sl, lines, "\n", 0, 0); last_line = smartlist_pop_last(sl); if (last_line != NULL && *last_line != '\0') { smartlist_add(sl, last_line); } return sl; } /** Test smartlist_new_from_text_lines */ static void test_util_sl_new_from_text_lines(void *ptr) { (void)ptr; { /* Normal usage */ smartlist_t *sl = smartlist_new_from_text_lines("foo\nbar\nbaz\n"); int sl_len = smartlist_len(sl); tt_want_int_op(sl_len, ==, 3); if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo"); if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), ==, "bar"); if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), ==, "baz"); SMARTLIST_FOREACH(sl, void *, x, tor_free(x)); smartlist_free(sl); } { /* No final newline */ smartlist_t *sl = smartlist_new_from_text_lines("foo\nbar\nbaz"); int sl_len = smartlist_len(sl); tt_want_int_op(sl_len, ==, 3); if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo"); if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), ==, "bar"); if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), ==, "baz"); SMARTLIST_FOREACH(sl, void *, x, tor_free(x)); smartlist_free(sl); } { /* No newlines */ smartlist_t *sl = smartlist_new_from_text_lines("foo"); int sl_len = smartlist_len(sl); tt_want_int_op(sl_len, ==, 1); if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo"); SMARTLIST_FOREACH(sl, void *, x, tor_free(x)); smartlist_free(sl); } { /* No text at all */ smartlist_t *sl = smartlist_new_from_text_lines(""); int sl_len = smartlist_len(sl); tt_want_int_op(sl_len, ==, 0); SMARTLIST_FOREACH(sl, void *, x, tor_free(x)); smartlist_free(sl); } } static void test_util_envnames(void *ptr) { (void) ptr; tt_assert(environment_variable_names_equal("abc", "abc")); tt_assert(environment_variable_names_equal("abc", "abc=")); tt_assert(environment_variable_names_equal("abc", "abc=def")); tt_assert(environment_variable_names_equal("abc=def", "abc")); tt_assert(environment_variable_names_equal("abc=def", "abc=ghi")); tt_assert(environment_variable_names_equal("abc", "abc")); tt_assert(environment_variable_names_equal("abc", "abc=")); tt_assert(environment_variable_names_equal("abc", "abc=def")); tt_assert(environment_variable_names_equal("abc=def", "abc")); tt_assert(environment_variable_names_equal("abc=def", "abc=ghi")); tt_assert(!environment_variable_names_equal("abc", "abcd")); tt_assert(!environment_variable_names_equal("abc=", "abcd")); tt_assert(!environment_variable_names_equal("abc=", "abcd")); tt_assert(!environment_variable_names_equal("abc=", "def")); tt_assert(!environment_variable_names_equal("abc=", "def=")); tt_assert(!environment_variable_names_equal("abc=x", "def=x")); tt_assert(!environment_variable_names_equal("", "a=def")); /* A bit surprising. */ tt_assert(environment_variable_names_equal("", "=def")); tt_assert(environment_variable_names_equal("=y", "=x")); done: ; } /** Test process_environment_make */ static void test_util_make_environment(void *ptr) { const char *env_vars_string = "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n" "HOME=/home/foozer\n"; const char expected_windows_env_block[] = "HOME=/home/foozer\000" "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\000" "\000"; size_t expected_windows_env_block_len = sizeof(expected_windows_env_block) - 1; smartlist_t *env_vars = smartlist_new_from_text_lines(env_vars_string); smartlist_t *env_vars_sorted = smartlist_new(); smartlist_t *env_vars_in_unixoid_env_block_sorted = smartlist_new(); process_environment_t *env; (void)ptr; env = process_environment_make(env_vars); /* Check that the Windows environment block is correct. */ tt_want(tor_memeq(expected_windows_env_block, env->windows_environment_block, expected_windows_env_block_len)); /* Now for the Unixoid environment block. We don't care which order * these environment variables are in, so we sort both lists first. */ smartlist_add_all(env_vars_sorted, env_vars); { char **v; for (v = env->unixoid_environment_block; *v; ++v) { smartlist_add(env_vars_in_unixoid_env_block_sorted, *v); } } smartlist_sort_strings(env_vars_sorted); smartlist_sort_strings(env_vars_in_unixoid_env_block_sorted); tt_want_int_op(smartlist_len(env_vars_sorted), ==, smartlist_len(env_vars_in_unixoid_env_block_sorted)); { int len = smartlist_len(env_vars_sorted); int i; if (smartlist_len(env_vars_in_unixoid_env_block_sorted) < len) { len = smartlist_len(env_vars_in_unixoid_env_block_sorted); } for (i = 0; i < len; ++i) { tt_want_str_op(smartlist_get(env_vars_sorted, i), ==, smartlist_get(env_vars_in_unixoid_env_block_sorted, i)); } } /* Clean up. */ smartlist_free(env_vars_in_unixoid_env_block_sorted); smartlist_free(env_vars_sorted); SMARTLIST_FOREACH(env_vars, char *, x, tor_free(x)); smartlist_free(env_vars); process_environment_free(env); } /** Test set_environment_variable_in_smartlist */ static void test_util_set_env_var_in_sl(void *ptr) { /* The environment variables in these strings are in arbitrary * order; we sort the resulting lists before comparing them. * * (They *will not* end up in the order shown in * expected_resulting_env_vars_string.) */ const char *base_env_vars_string = "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n" "HOME=/home/foozer\n" "TERM=xterm\n" "SHELL=/bin/ksh\n" "USER=foozer\n" "LOGNAME=foozer\n" "USERNAME=foozer\n" "LANG=en_US.utf8\n" ; const char *new_env_vars_string = "TERM=putty\n" "DISPLAY=:18.0\n" ; const char *expected_resulting_env_vars_string = "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n" "HOME=/home/foozer\n" "TERM=putty\n" "SHELL=/bin/ksh\n" "USER=foozer\n" "LOGNAME=foozer\n" "USERNAME=foozer\n" "LANG=en_US.utf8\n" "DISPLAY=:18.0\n" ; smartlist_t *merged_env_vars = smartlist_new_from_text_lines(base_env_vars_string); smartlist_t *new_env_vars = smartlist_new_from_text_lines(new_env_vars_string); smartlist_t *expected_resulting_env_vars = smartlist_new_from_text_lines(expected_resulting_env_vars_string); /* Elements of merged_env_vars are heap-allocated, and must be * freed. Some of them are (or should) be freed by * set_environment_variable_in_smartlist. * * Elements of new_env_vars are heap-allocated, but are copied into * merged_env_vars, so they are not freed separately at the end of * the function. * * Elements of expected_resulting_env_vars are heap-allocated, and * must be freed. */ (void)ptr; SMARTLIST_FOREACH(new_env_vars, char *, env_var, set_environment_variable_in_smartlist(merged_env_vars, env_var, tor_free_, 1)); smartlist_sort_strings(merged_env_vars); smartlist_sort_strings(expected_resulting_env_vars); tt_want_int_op(smartlist_len(merged_env_vars), ==, smartlist_len(expected_resulting_env_vars)); { int len = smartlist_len(merged_env_vars); int i; if (smartlist_len(expected_resulting_env_vars) < len) { len = smartlist_len(expected_resulting_env_vars); } for (i = 0; i < len; ++i) { tt_want_str_op(smartlist_get(merged_env_vars, i), ==, smartlist_get(expected_resulting_env_vars, i)); } } /* Clean up. */ SMARTLIST_FOREACH(merged_env_vars, char *, x, tor_free(x)); smartlist_free(merged_env_vars); smartlist_free(new_env_vars); SMARTLIST_FOREACH(expected_resulting_env_vars, char *, x, tor_free(x)); smartlist_free(expected_resulting_env_vars); } static void test_util_weak_random(void *arg) { int i, j, n[16]; tor_weak_rng_t rng; (void) arg; tor_init_weak_random(&rng, (unsigned)time(NULL)); for (i = 1; i <= 256; ++i) { for (j=0;j<100;++j) { int r = tor_weak_random_range(&rng, i); tt_int_op(0, <=, r); tt_int_op(r, <, i); } } memset(n,0,sizeof(n)); for (j=0;j<8192;++j) { n[tor_weak_random_range(&rng, 16)]++; } for (i=0;i<16;++i) tt_int_op(n[i], >, 0); done: ; } static void test_util_mathlog(void *arg) { double d; (void) arg; d = tor_mathlog(2.718281828); tt_double_op(fabs(d - 1.0), <, .000001); d = tor_mathlog(10); tt_double_op(fabs(d - 2.30258509), <, .000001); done: ; } #define UTIL_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name } #define UTIL_TEST(name, flags) \ { #name, test_util_ ## name, flags, NULL, NULL } struct testcase_t util_tests[] = { UTIL_LEGACY(time), UTIL_TEST(parse_http_time, 0), UTIL_LEGACY(config_line), UTIL_LEGACY(config_line_quotes), UTIL_LEGACY(config_line_comment_character), UTIL_LEGACY(config_line_escaped_content), #ifndef _WIN32 UTIL_LEGACY(expand_filename), #endif UTIL_LEGACY(strmisc), UTIL_LEGACY(pow2), UTIL_LEGACY(gzip), UTIL_LEGACY(datadir), UTIL_LEGACY(mempool), UTIL_LEGACY(memarea), UTIL_LEGACY(control_formats), UTIL_LEGACY(mmap), UTIL_LEGACY(threads), UTIL_LEGACY(sscanf), UTIL_LEGACY(path_is_relative), UTIL_LEGACY(strtok), UTIL_LEGACY(di_ops), UTIL_TEST(find_str_at_start_of_line, 0), UTIL_TEST(string_is_C_identifier, 0), UTIL_TEST(asprintf, 0), UTIL_TEST(listdir, 0), UTIL_TEST(parent_dir, 0), #ifdef _WIN32 UTIL_TEST(load_win_lib, 0), #endif UTIL_TEST(exit_status, 0), #ifndef _WIN32 UTIL_TEST(fgets_eagain, TT_SKIP), #endif UTIL_TEST(spawn_background_ok, 0), UTIL_TEST(spawn_background_fail, 0), UTIL_TEST(spawn_background_partial_read, 0), UTIL_TEST(format_hex_number, 0), UTIL_TEST(join_win_cmdline, 0), UTIL_TEST(split_lines, 0), UTIL_TEST(n_bits_set, 0), UTIL_TEST(eat_whitespace, 0), UTIL_TEST(sl_new_from_text_lines, 0), UTIL_TEST(envnames, 0), UTIL_TEST(make_environment, 0), UTIL_TEST(set_env_var_in_sl, 0), UTIL_TEST(read_file_eof_tiny_limit, 0), UTIL_TEST(read_file_eof_two_loops, 0), UTIL_TEST(read_file_eof_zero_bytes, 0), UTIL_TEST(mathlog, 0), UTIL_TEST(weak_random, 0), END_OF_TESTCASES }; tor-0.2.4.20/src/test/test_microdesc.c0000644000175000017500000002336312255512001014403 00000000000000/* Copyright (c) 2010-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #include "or.h" #include "config.h" #include "microdesc.h" #include "test.h" #ifdef _WIN32 /* For mkdir() */ #include #else #include #endif static const char test_md1[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAMjlHH/daN43cSVRaHBwgUfnszzAhg98EvivJ9Qxfv51mvQUxPjQ07es\n" "gV/3n8fyh3Kqr/ehi9jxkdgSRfSnmF7giaHL1SLZ29kA7KtST+pBvmTpDtHa3ykX\n" "Xorc7hJvIyTZoc1HU+5XSynj3gsBE5IGK1ZRzrNS688LnuZMVp1tAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n"; static const char test_md2[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAMIixIowh2DyPmDNMDwBX2DHcYcqdcH1zdIQJZkyV6c6rQHnvbcaDoSg\n" "jgFSLJKpnGmh71FVRqep+yVB0zI1JY43kuEnXry2HbZCD9UDo3d3n7t015X5S7ON\n" "bSSYtQGPwOr6Epf96IF6DoQxy4iDnPUAlejuhAG51s1y6/rZQ3zxAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n"; static const char test_md3[] = "@last-listed 2009-06-22\n" "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAMH3340d4ENNGrqx7UxT+lB7x6DNUKOdPEOn4teceE11xlMyZ9TPv41c\n" "qj2fRZzfxlc88G/tmiaHshmdtEpklZ740OFqaaJVj4LjPMKFNE+J7Xc1142BE9Ci\n" "KgsbjGYe2RY261aADRWLetJ8T9QDMm+JngL4288hc8pq1uB/3TAbAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "p accept 1-700,800-1000\n" "family nodeX nodeY nodeZ\n"; static void test_md_cache(void *data) { or_options_t *options = NULL; microdesc_cache_t *mc = NULL ; smartlist_t *added = NULL, *wanted = NULL; microdesc_t *md1, *md2, *md3; char d1[DIGEST256_LEN], d2[DIGEST256_LEN], d3[DIGEST256_LEN]; const char *test_md3_noannotation = strchr(test_md3, '\n')+1; time_t time1, time2, time3; char *fn = NULL, *s = NULL; (void)data; options = get_options_mutable(); tt_assert(options); time1 = time(NULL); time2 = time(NULL) - 2*24*60*60; time3 = time(NULL) - 15*24*60*60; /* Possibly, turn this into a test setup/cleanup pair */ tor_free(options->DataDirectory); options->DataDirectory = tor_strdup(get_fname("md_datadir_test")); #ifdef _WIN32 tt_int_op(0, ==, mkdir(options->DataDirectory)); #else tt_int_op(0, ==, mkdir(options->DataDirectory, 0700)); #endif tt_assert(!strcmpstart(test_md3_noannotation, "onion-key")); crypto_digest256(d1, test_md1, strlen(test_md1), DIGEST_SHA256); crypto_digest256(d2, test_md2, strlen(test_md1), DIGEST_SHA256); crypto_digest256(d3, test_md3_noannotation, strlen(test_md3_noannotation), DIGEST_SHA256); mc = get_microdesc_cache(); added = microdescs_add_to_cache(mc, test_md1, NULL, SAVED_NOWHERE, 0, time1, NULL); tt_int_op(1, ==, smartlist_len(added)); md1 = smartlist_get(added, 0); smartlist_free(added); added = NULL; wanted = smartlist_new(); added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0, time2, wanted); /* Should fail, since we didn't list test_md2's digest in wanted */ tt_int_op(0, ==, smartlist_len(added)); smartlist_free(added); added = NULL; smartlist_add(wanted, tor_memdup(d2, DIGEST256_LEN)); smartlist_add(wanted, tor_memdup(d3, DIGEST256_LEN)); added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0, time2, wanted); /* Now it can work. md2 should have been added */ tt_int_op(1, ==, smartlist_len(added)); md2 = smartlist_get(added, 0); /* And it should have gotten removed from 'wanted' */ tt_int_op(smartlist_len(wanted), ==, 1); test_mem_op(smartlist_get(wanted, 0), ==, d3, DIGEST256_LEN); smartlist_free(added); added = NULL; added = microdescs_add_to_cache(mc, test_md3, NULL, SAVED_NOWHERE, 0, -1, NULL); /* Must fail, since SAVED_NOWHERE precludes annotations */ tt_int_op(0, ==, smartlist_len(added)); smartlist_free(added); added = NULL; added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL, SAVED_NOWHERE, 0, time3, NULL); /* Now it can work */ tt_int_op(1, ==, smartlist_len(added)); md3 = smartlist_get(added, 0); smartlist_free(added); added = NULL; /* Okay. We added 1...3. Let's poke them to see how they look, and make * sure they're really in the journal. */ tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1)); tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2)); tt_ptr_op(md3, ==, microdesc_cache_lookup_by_digest256(mc, d3)); tt_int_op(md1->last_listed, ==, time1); tt_int_op(md2->last_listed, ==, time2); tt_int_op(md3->last_listed, ==, time3); tt_int_op(md1->saved_location, ==, SAVED_IN_JOURNAL); tt_int_op(md2->saved_location, ==, SAVED_IN_JOURNAL); tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL); tt_int_op(md1->bodylen, ==, strlen(test_md1)); tt_int_op(md2->bodylen, ==, strlen(test_md2)); tt_int_op(md3->bodylen, ==, strlen(test_md3_noannotation)); test_mem_op(md1->body, ==, test_md1, strlen(test_md1)); test_mem_op(md2->body, ==, test_md2, strlen(test_md2)); test_mem_op(md3->body, ==, test_md3_noannotation, strlen(test_md3_noannotation)); tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new", options->DataDirectory); s = read_file_to_str(fn, RFTS_BIN, NULL); tt_assert(s); test_mem_op(md1->body, ==, s + md1->off, md1->bodylen); test_mem_op(md2->body, ==, s + md2->off, md2->bodylen); test_mem_op(md3->body, ==, s + md3->off, md3->bodylen); tt_ptr_op(md1->family, ==, NULL); tt_ptr_op(md3->family, !=, NULL); tt_int_op(smartlist_len(md3->family), ==, 3); tt_str_op(smartlist_get(md3->family, 0), ==, "nodeX"); /* Now rebuild the cache! */ tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0); tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE); tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE); tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE); /* The journal should be empty now */ tor_free(s); s = read_file_to_str(fn, RFTS_BIN, NULL); tt_str_op(s, ==, ""); tor_free(s); tor_free(fn); /* read the cache. */ tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs", options->DataDirectory); s = read_file_to_str(fn, RFTS_BIN, NULL); test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1)); test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2)); test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation)); /* Okay, now we are going to forget about the cache entirely, and reload it * from the disk. */ microdesc_free_all(); mc = get_microdesc_cache(); md1 = microdesc_cache_lookup_by_digest256(mc, d1); md2 = microdesc_cache_lookup_by_digest256(mc, d2); md3 = microdesc_cache_lookup_by_digest256(mc, d3); test_assert(md1); test_assert(md2); test_assert(md3); test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1)); test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2)); test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation)); tt_int_op(md1->last_listed, ==, time1); tt_int_op(md2->last_listed, ==, time2); tt_int_op(md3->last_listed, ==, time3); /* Okay, now we are going to clear out everything older than a week old. * In practice, that means md3 */ microdesc_cache_clean(mc, time(NULL)-7*24*60*60, 1/*force*/); tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1)); tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2)); tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3)); md3 = NULL; /* it's history now! */ /* rebuild again, make sure it stays gone. */ tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0); tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1)); tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2)); tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3)); /* Re-add md3, and make sure we can rebuild the cache. */ added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL, SAVED_NOWHERE, 0, time3, NULL); tt_int_op(1, ==, smartlist_len(added)); md3 = smartlist_get(added, 0); smartlist_free(added); added = NULL; tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE); tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE); tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL); tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0); tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE); done: if (options) tor_free(options->DataDirectory); microdesc_free_all(); smartlist_free(added); if (wanted) SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp)); smartlist_free(wanted); tor_free(s); tor_free(fn); } static const char truncated_md[] = "@last-listed 2013-08-08 19:02:59\n" "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAM91vLFNaM+gGhnRIdz2Cm/Kl7Xz0cOobIdVzhS3cKUJfk867hCuTipS\n" "NveLBzNopvgXKruAAzEj3cACxk6Q8lv5UWOGCD1UolkgsWSE62RBjap44g+oc9J1\n" "RI9968xOTZw0VaBQg9giEILNXl0djoikQ+5tQRUvLDDa67gpa5Q1AgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "family @\n"; static void test_md_cache_broken(void *data) { or_options_t *options; char *fn=NULL; microdesc_cache_t *mc = NULL; (void)data; options = get_options_mutable(); tt_assert(options); options->DataDirectory = tor_strdup(get_fname("md_datadir_test2")); #ifdef _WIN32 tt_int_op(0, ==, mkdir(options->DataDirectory)); #else tt_int_op(0, ==, mkdir(options->DataDirectory, 0700)); #endif tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs", options->DataDirectory); write_str_to_file(fn, truncated_md, 1); mc = get_microdesc_cache(); tt_assert(mc); done: if (options) tor_free(options->DataDirectory); tor_free(fn); microdesc_free_all(); } struct testcase_t microdesc_tests[] = { { "cache", test_md_cache, TT_FORK, NULL, NULL }, { "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; tor-0.2.4.20/src/test/test_replay.c0000644000175000017500000000726512255745673013761 00000000000000/* Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define REPLAYCACHE_PRIVATE #include "orconfig.h" #include "or.h" #include "replaycache.h" #include "test.h" static const char *test_buffer = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed do eiusmod" " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim" " veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" " commodo consequat. Duis aute irure dolor in reprehenderit in voluptate" " velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint" " occaecat cupidatat non proident, sunt in culpa qui officia deserunt" " mollit anim id est laborum."; static void test_replaycache_alloc(void) { replaycache_t *r = NULL; r = replaycache_new(600, 300); test_assert(r != NULL); done: if (r) replaycache_free(r); return; } static void test_replaycache_miss(void) { replaycache_t *r = NULL; int result; r = replaycache_new(600, 300); test_assert(r != NULL); result = replaycache_add_and_test_internal(1200, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 0); done: if (r) replaycache_free(r); return; } static void test_replaycache_hit(void) { replaycache_t *r = NULL; int result; r = replaycache_new(600, 300); test_assert(r != NULL); result = replaycache_add_and_test_internal(1200, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 0); result = replaycache_add_and_test_internal(1300, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 1); done: if (r) replaycache_free(r); return; } static void test_replaycache_age(void) { replaycache_t *r = NULL; int result; r = replaycache_new(600, 300); test_assert(r != NULL); result = replaycache_add_and_test_internal(1200, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 0); result = replaycache_add_and_test_internal(1300, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 1); result = replaycache_add_and_test_internal(3000, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 0); done: if (r) replaycache_free(r); return; } static void test_replaycache_elapsed(void) { replaycache_t *r = NULL; int result; time_t elapsed; r = replaycache_new(600, 300); test_assert(r != NULL); result = replaycache_add_and_test_internal(1200, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 0); result = replaycache_add_and_test_internal(1300, r, test_buffer, (int)strlen(test_buffer), &elapsed); test_eq(result, 1); test_eq(elapsed, 100); done: if (r) replaycache_free(r); return; } static void test_replaycache_noexpire(void) { replaycache_t *r = NULL; int result; r = replaycache_new(0, 0); test_assert(r != NULL); result = replaycache_add_and_test_internal(1200, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 0); result = replaycache_add_and_test_internal(1300, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 1); result = replaycache_add_and_test_internal(3000, r, test_buffer, (int)strlen(test_buffer), NULL); test_eq(result, 1); done: if (r) replaycache_free(r); return; } #define REPLAYCACHE_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_replaycache_ ## name } struct testcase_t replaycache_tests[] = { REPLAYCACHE_LEGACY(alloc), REPLAYCACHE_LEGACY(miss), REPLAYCACHE_LEGACY(hit), REPLAYCACHE_LEGACY(age), REPLAYCACHE_LEGACY(elapsed), REPLAYCACHE_LEGACY(noexpire), END_OF_TESTCASES }; tor-0.2.4.20/src/test/test_pt.c0000644000175000017500000000660612255745673013106 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define PT_PRIVATE #include "or.h" #include "transports.h" #include "circuitbuild.h" #include "test.h" static void reset_mp(managed_proxy_t *mp) { mp->conf_state = PT_PROTO_LAUNCHED; SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_clear(mp->transports); } static void test_pt_parsing(void) { char line[200]; managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_INFANT; mp->transports = smartlist_new(); /* incomplete cmethod */ strcpy(line,"CMETHOD trebuchet"); test_assert(parse_cmethod_line(line, mp) < 0); reset_mp(mp); /* wrong proxy type */ strcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999"); test_assert(parse_cmethod_line(line, mp) < 0); reset_mp(mp); /* wrong addrport */ strcpy(line,"CMETHOD trebuchet socks4 abcd"); test_assert(parse_cmethod_line(line, mp) < 0); reset_mp(mp); /* correct line */ strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); test_assert(parse_cmethod_line(line, mp) == 0); test_assert(smartlist_len(mp->transports)); reset_mp(mp); /* incomplete smethod */ strcpy(line,"SMETHOD trebuchet"); test_assert(parse_smethod_line(line, mp) < 0); reset_mp(mp); /* wrong addr type */ strcpy(line,"SMETHOD trebuchet abcd"); test_assert(parse_smethod_line(line, mp) < 0); reset_mp(mp); /* cowwect */ strcpy(line,"SMETHOD trebuchy 127.0.0.1:1999"); test_assert(parse_smethod_line(line, mp) == 0); reset_mp(mp); /* unsupported version */ strcpy(line,"VERSION 666"); test_assert(parse_version(line, mp) < 0); /* incomplete VERSION */ strcpy(line,"VERSION "); test_assert(parse_version(line, mp) < 0); /* correct VERSION */ strcpy(line,"VERSION 1"); test_assert(parse_version(line, mp) == 0); done: tor_free(mp); } static void test_pt_protocol(void) { char line[200]; managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_LAUNCHED; mp->transports = smartlist_new(); mp->argv = tor_malloc_zero(sizeof(char*)*2); mp->argv[0] = tor_strdup(""); /* various wrong protocol runs: */ strcpy(line,"VERSION 1"); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); strcpy(line,"VERSION 1"); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_BROKEN); reset_mp(mp); strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_BROKEN); reset_mp(mp); /* correct protocol run: */ strcpy(line,"VERSION 1"); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); strcpy(line,"CMETHODS DONE"); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_CONFIGURED); done: tor_free(mp); } #define PT_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_pt_ ## name } struct testcase_t pt_tests[] = { PT_LEGACY(parsing), PT_LEGACY(protocol), END_OF_TESTCASES }; tor-0.2.4.20/src/test/test_addr.c0000644000175000017500000010324612255745673013373 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ADDRESSMAP_PRIVATE #include "orconfig.h" #include "or.h" #include "test.h" #include "addressmap.h" static void test_addr_basic(void) { uint32_t u32; uint16_t u16; char *cp; /* Test addr_port_lookup */ cp = NULL; u32 = 3; u16 = 3; test_assert(!addr_port_lookup(LOG_WARN, "1.2.3.4", &cp, &u32, &u16)); test_streq(cp, "1.2.3.4"); test_eq(u32, 0x01020304u); test_eq(u16, 0); tor_free(cp); test_assert(!addr_port_lookup(LOG_WARN, "4.3.2.1:99", &cp, &u32, &u16)); test_streq(cp, "4.3.2.1"); test_eq(u32, 0x04030201u); test_eq(u16, 99); tor_free(cp); test_assert(!addr_port_lookup(LOG_WARN, "nonexistent.address:4040", &cp, NULL, &u16)); test_streq(cp, "nonexistent.address"); test_eq(u16, 4040); tor_free(cp); test_assert(!addr_port_lookup(LOG_WARN, "localhost:9999", &cp, &u32, &u16)); test_streq(cp, "localhost"); test_eq(u32, 0x7f000001u); test_eq(u16, 9999); tor_free(cp); u32 = 3; test_assert(!addr_port_lookup(LOG_WARN, "localhost", NULL, &u32, &u16)); test_eq_ptr(cp, NULL); test_eq(u32, 0x7f000001u); test_eq(u16, 0); tor_free(cp); test_eq(0, addr_mask_get_bits(0x0u)); test_eq(32, addr_mask_get_bits(0xFFFFFFFFu)); test_eq(16, addr_mask_get_bits(0xFFFF0000u)); test_eq(31, addr_mask_get_bits(0xFFFFFFFEu)); test_eq(1, addr_mask_get_bits(0x80000000u)); /* Test inet_ntop */ { char tmpbuf[TOR_ADDR_BUF_LEN]; const char *ip = "176.192.208.224"; struct in_addr in; /* good round trip */ test_eq(tor_inet_pton(AF_INET, ip, &in), 1); test_eq_ptr(tor_inet_ntop(AF_INET, &in, tmpbuf, sizeof(tmpbuf)), &tmpbuf); test_streq(tmpbuf, ip); /* just enough buffer length */ test_streq(tor_inet_ntop(AF_INET, &in, tmpbuf, strlen(ip) + 1), ip); /* too short buffer */ test_eq_ptr(tor_inet_ntop(AF_INET, &in, tmpbuf, strlen(ip)), NULL); } done: ; } #define test_op_ip6_(a,op,b,e1,e2) \ STMT_BEGIN \ tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \ (memcmp(val1_->s6_addr, val2_->s6_addr, 16) op 0), \ char *, "%s", \ { int i; char *cp; \ cp = print_ = tor_malloc(64); \ for (i=0;i<16;++i) { \ tor_snprintf(cp, 3,"%02x", (unsigned)value_->s6_addr[i]);\ cp += 2; \ if (i != 15) *cp++ = ':'; \ } \ }, \ { tor_free(print_); }, \ TT_EXIT_TEST_FUNCTION \ ); \ STMT_END /** Helper: Assert that two strings both decode as IPv6 addresses with * tor_inet_pton(), and both decode to the same address. */ #define test_pton6_same(a,b) STMT_BEGIN \ test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \ test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \ test_op_ip6_(&a1,==,&a2,#a,#b); \ STMT_END /** Helper: Assert that a is recognized as a bad IPv6 address by * tor_inet_pton(). */ #define test_pton6_bad(a) \ test_eq(0, tor_inet_pton(AF_INET6, a, &a1)) /** Helper: assert that a, when parsed by tor_inet_pton() and displayed * with tor_inet_ntop(), yields b. Also assert that b parses to * the same value as a. */ #define test_ntop6_reduces(a,b) STMT_BEGIN \ test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \ test_streq(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), b); \ test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \ test_op_ip6_(&a1, ==, &a2, a, b); \ STMT_END /** Helper: assert that a parses by tor_inet_pton() into a address that * passes tor_addr_is_internal() with for_listening. */ #define test_internal_ip(a,for_listening) STMT_BEGIN \ test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \ t1.family = AF_INET6; \ if (!tor_addr_is_internal(&t1, for_listening)) \ test_fail_msg( a "was not internal."); \ STMT_END /** Helper: assert that a parses by tor_inet_pton() into a address that * does not pass tor_addr_is_internal() with for_listening. */ #define test_external_ip(a,for_listening) STMT_BEGIN \ test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \ t1.family = AF_INET6; \ if (tor_addr_is_internal(&t1, for_listening)) \ test_fail_msg(a "was not external."); \ STMT_END /** Helper: Assert that a and b, when parsed by * tor_inet_pton(), give addresses that compare in the order defined by * op with tor_addr_compare(). */ #define test_addr_compare(a, op, b) STMT_BEGIN \ test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \ test_eq(tor_inet_pton(AF_INET6, b, &t2.addr.in6_addr), 1); \ t1.family = t2.family = AF_INET6; \ r = tor_addr_compare(&t1,&t2,CMP_SEMANTIC); \ if (!(r op 0)) \ test_fail_msg("failed: tor_addr_compare("a","b") "#op" 0"); \ STMT_END /** Helper: Assert that a and b, when parsed by * tor_inet_pton(), give addresses that compare in the order defined by * op with tor_addr_compare_masked() with m masked. */ #define test_addr_compare_masked(a, op, b, m) STMT_BEGIN \ test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \ test_eq(tor_inet_pton(AF_INET6, b, &t2.addr.in6_addr), 1); \ t1.family = t2.family = AF_INET6; \ r = tor_addr_compare_masked(&t1,&t2,m,CMP_SEMANTIC); \ if (!(r op 0)) \ test_fail_msg("failed: tor_addr_compare_masked("a","b","#m") "#op" 0"); \ STMT_END /** Helper: assert that xx is parseable as a masked IPv6 address with * ports by tor_parse_mask_addr_ports(), with family f, IP address * as 4 32-bit words ip1...ip4, mask bits as mm, and port range * as pt1..pt2. */ #define test_addr_mask_ports_parse(xx, f, ip1, ip2, ip3, ip4, mm, pt1, pt2) \ STMT_BEGIN \ test_eq(tor_addr_parse_mask_ports(xx, 0, &t1, &mask, &port1, &port2), \ f); \ p1=tor_inet_ntop(AF_INET6, &t1.addr.in6_addr, bug, sizeof(bug)); \ test_eq(htonl(ip1), tor_addr_to_in6_addr32(&t1)[0]); \ test_eq(htonl(ip2), tor_addr_to_in6_addr32(&t1)[1]); \ test_eq(htonl(ip3), tor_addr_to_in6_addr32(&t1)[2]); \ test_eq(htonl(ip4), tor_addr_to_in6_addr32(&t1)[3]); \ test_eq(mask, mm); \ test_eq(port1, pt1); \ test_eq(port2, pt2); \ STMT_END /** Run unit tests for IPv6 encoding/decoding/manipulation functions. */ static void test_addr_ip6_helpers(void) { char buf[TOR_ADDR_BUF_LEN], bug[TOR_ADDR_BUF_LEN]; char rbuf[REVERSE_LOOKUP_NAME_BUF_LEN]; struct in6_addr a1, a2; tor_addr_t t1, t2; int r, i; uint16_t port1, port2; maskbits_t mask; const char *p1; struct sockaddr_storage sa_storage; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; /* Test tor_inet_ntop and tor_inet_pton: IPv6 */ { const char *ip = "2001::1234"; const char *ip_ffff = "::ffff:192.168.1.2"; /* good round trip */ test_eq(tor_inet_pton(AF_INET6, ip, &a1), 1); test_eq_ptr(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), &buf); test_streq(buf, ip); /* good round trip - ::ffff:0:0 style */ test_eq(tor_inet_pton(AF_INET6, ip_ffff, &a2), 1); test_eq_ptr(tor_inet_ntop(AF_INET6, &a2, buf, sizeof(buf)), &buf); test_streq(buf, ip_ffff); /* just long enough buffer (remember \0) */ test_streq(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)+1), ip); test_streq(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)+1), ip_ffff); /* too short buffer (remember \0) */ test_eq_ptr(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)), NULL); test_eq_ptr(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)), NULL); } /* ==== Converting to and from sockaddr_t. */ sin = (struct sockaddr_in *)&sa_storage; sin->sin_family = AF_INET; sin->sin_port = 9090; sin->sin_addr.s_addr = htonl(0x7f7f0102); /*127.127.1.2*/ tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL); test_eq(tor_addr_family(&t1), AF_INET); test_eq(tor_addr_to_ipv4h(&t1), 0x7f7f0102); memset(&sa_storage, 0, sizeof(sa_storage)); test_eq(sizeof(struct sockaddr_in), tor_addr_to_sockaddr(&t1, 1234, (struct sockaddr *)&sa_storage, sizeof(sa_storage))); test_eq(1234, ntohs(sin->sin_port)); test_eq(0x7f7f0102, ntohl(sin->sin_addr.s_addr)); memset(&sa_storage, 0, sizeof(sa_storage)); sin6 = (struct sockaddr_in6 *)&sa_storage; sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(7070); sin6->sin6_addr.s6_addr[0] = 128; tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL); test_eq(tor_addr_family(&t1), AF_INET6); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0); test_streq(p1, "8000::"); memset(&sa_storage, 0, sizeof(sa_storage)); test_eq(sizeof(struct sockaddr_in6), tor_addr_to_sockaddr(&t1, 9999, (struct sockaddr *)&sa_storage, sizeof(sa_storage))); test_eq(AF_INET6, sin6->sin6_family); test_eq(9999, ntohs(sin6->sin6_port)); test_eq(0x80000000, ntohl(S6_ADDR32(sin6->sin6_addr)[0])); /* ==== tor_addr_lookup: static cases. (Can't test dns without knowing we * have a good resolver. */ test_eq(0, tor_addr_lookup("127.128.129.130", AF_UNSPEC, &t1)); test_eq(AF_INET, tor_addr_family(&t1)); test_eq(tor_addr_to_ipv4h(&t1), 0x7f808182); test_eq(0, tor_addr_lookup("9000::5", AF_UNSPEC, &t1)); test_eq(AF_INET6, tor_addr_family(&t1)); test_eq(0x90, tor_addr_to_in6_addr8(&t1)[0]); test_assert(tor_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14)); test_eq(0x05, tor_addr_to_in6_addr8(&t1)[15]); /* === Test pton: valid af_inet6 */ /* Simple, valid parsing. */ r = tor_inet_pton(AF_INET6, "0102:0304:0506:0708:090A:0B0C:0D0E:0F10", &a1); test_assert(r==1); for (i=0;i<16;++i) { test_eq(i+1, (int)a1.s6_addr[i]); } /* ipv4 ending. */ test_pton6_same("0102:0304:0506:0708:090A:0B0C:0D0E:0F10", "0102:0304:0506:0708:090A:0B0C:13.14.15.16"); /* shortened words. */ test_pton6_same("0001:0099:BEEF:0000:0123:FFFF:0001:0001", "1:99:BEEF:0:0123:FFFF:1:1"); /* zeros at the beginning */ test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001", "::9:c0a8:1:1"); test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001", "::9:c0a8:0.1.0.1"); /* zeros in the middle. */ test_pton6_same("fe80:0000:0000:0000:0202:1111:0001:0001", "fe80::202:1111:1:1"); /* zeros at the end. */ test_pton6_same("1000:0001:0000:0007:0000:0000:0000:0000", "1000:1:0:7::"); /* === Test ntop: af_inet6 */ test_ntop6_reduces("0:0:0:0:0:0:0:0", "::"); test_ntop6_reduces("0001:0099:BEEF:0006:0123:FFFF:0001:0001", "1:99:beef:6:123:ffff:1:1"); //test_ntop6_reduces("0:0:0:0:0:0:c0a8:0101", "::192.168.1.1"); test_ntop6_reduces("0:0:0:0:0:ffff:c0a8:0101", "::ffff:192.168.1.1"); test_ntop6_reduces("002:0:0000:0:3::4", "2::3:0:0:4"); test_ntop6_reduces("0:0::1:0:3", "::1:0:3"); test_ntop6_reduces("008:0::0", "8::"); test_ntop6_reduces("0:0:0:0:0:ffff::1", "::ffff:0.0.0.1"); test_ntop6_reduces("abcd:0:0:0:0:0:7f00::", "abcd::7f00:0"); test_ntop6_reduces("0000:0000:0000:0000:0009:C0A8:0001:0001", "::9:c0a8:1:1"); test_ntop6_reduces("fe80:0000:0000:0000:0202:1111:0001:0001", "fe80::202:1111:1:1"); test_ntop6_reduces("1000:0001:0000:0007:0000:0000:0000:0000", "1000:1:0:7::"); /* Bad af param */ test_eq(tor_inet_pton(AF_UNSPEC, 0, 0), -1); /* === Test pton: invalid in6. */ test_pton6_bad("foobar."); test_pton6_bad("-1::"); test_pton6_bad("00001::"); test_pton6_bad("10000::"); test_pton6_bad("::10000"); test_pton6_bad("55555::"); test_pton6_bad("9:-60::"); test_pton6_bad("9:+60::"); test_pton6_bad("9|60::"); test_pton6_bad("0x60::"); test_pton6_bad("::0x60"); test_pton6_bad("9:0x60::"); test_pton6_bad("1:2:33333:4:0002:3::"); test_pton6_bad("1:2:3333:4:fish:3::"); test_pton6_bad("1:2:3:4:5:6:7:8:9"); test_pton6_bad("1:2:3:4:5:6:7"); test_pton6_bad("1:2:3:4:5:6:1.2.3.4.5"); test_pton6_bad("1:2:3:4:5:6:1.2.3"); test_pton6_bad("::1.2.3"); test_pton6_bad("::1.2.3.4.5"); test_pton6_bad("::ffff:0xff.0.0.0"); test_pton6_bad("::ffff:ff.0.0.0"); test_pton6_bad("::ffff:256.0.0.0"); test_pton6_bad("::ffff:-1.0.0.0"); test_pton6_bad("99"); test_pton6_bad(""); test_pton6_bad("."); test_pton6_bad(":"); test_pton6_bad("1::2::3:4"); test_pton6_bad("a:::b:c"); test_pton6_bad(":::a:b:c"); test_pton6_bad("a:b:c:::"); /* test internal checking */ test_external_ip("fbff:ffff::2:7", 0); test_internal_ip("fc01::2:7", 0); test_internal_ip("fc01::02:7", 0); test_internal_ip("fc01::002:7", 0); test_internal_ip("fc01::0002:7", 0); test_internal_ip("fdff:ffff::f:f", 0); test_external_ip("fe00::3:f", 0); test_external_ip("fe7f:ffff::2:7", 0); test_internal_ip("fe80::2:7", 0); test_internal_ip("febf:ffff::f:f", 0); test_internal_ip("fec0::2:7:7", 0); test_internal_ip("feff:ffff::e:7:7", 0); test_external_ip("ff00::e:7:7", 0); test_internal_ip("::", 0); test_internal_ip("::1", 0); test_internal_ip("::1", 1); test_internal_ip("::", 0); test_external_ip("::", 1); test_external_ip("::2", 0); test_external_ip("2001::", 0); test_external_ip("ffff::", 0); test_external_ip("::ffff:0.0.0.0", 1); test_internal_ip("::ffff:0.0.0.0", 0); test_internal_ip("::ffff:0.255.255.255", 0); test_external_ip("::ffff:1.0.0.0", 0); test_external_ip("::ffff:9.255.255.255", 0); test_internal_ip("::ffff:10.0.0.0", 0); test_internal_ip("::ffff:10.255.255.255", 0); test_external_ip("::ffff:11.0.0.0", 0); test_external_ip("::ffff:126.255.255.255", 0); test_internal_ip("::ffff:127.0.0.0", 0); test_internal_ip("::ffff:127.255.255.255", 0); test_external_ip("::ffff:128.0.0.0", 0); test_external_ip("::ffff:172.15.255.255", 0); test_internal_ip("::ffff:172.16.0.0", 0); test_internal_ip("::ffff:172.31.255.255", 0); test_external_ip("::ffff:172.32.0.0", 0); test_external_ip("::ffff:192.167.255.255", 0); test_internal_ip("::ffff:192.168.0.0", 0); test_internal_ip("::ffff:192.168.255.255", 0); test_external_ip("::ffff:192.169.0.0", 0); test_external_ip("::ffff:169.253.255.255", 0); test_internal_ip("::ffff:169.254.0.0", 0); test_internal_ip("::ffff:169.254.255.255", 0); test_external_ip("::ffff:169.255.0.0", 0); test_assert(is_internal_IP(0x7f000001, 0)); /* tor_addr_compare(tor_addr_t x2) */ test_addr_compare("ffff::", ==, "ffff::0"); test_addr_compare("0::3:2:1", <, "0::ffff:0.3.2.1"); test_addr_compare("0::2:2:1", <, "0::ffff:0.3.2.1"); test_addr_compare("0::ffff:0.3.2.1", >, "0::0:0:0"); test_addr_compare("0::ffff:5.2.2.1", <, "::ffff:6.0.0.0"); /* XXXX wrong. */ tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", 0, &t1, NULL, NULL, NULL); tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL); test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0); tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", 0, &t1, NULL, NULL, NULL); tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL); test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0); /* test compare_masked */ test_addr_compare_masked("ffff::", ==, "ffff::0", 128); test_addr_compare_masked("ffff::", ==, "ffff::0", 64); test_addr_compare_masked("0::2:2:1", <, "0::8000:2:1", 81); test_addr_compare_masked("0::2:2:1", ==, "0::8000:2:1", 80); /* Test undecorated tor_addr_to_str */ test_eq(AF_INET6, tor_addr_parse(&t1, "[123:45:6789::5005:11]")); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0); test_streq(p1, "123:45:6789::5005:11"); test_eq(AF_INET, tor_addr_parse(&t1, "18.0.0.1")); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0); test_streq(p1, "18.0.0.1"); /* Test decorated tor_addr_to_str */ test_eq(AF_INET6, tor_addr_parse(&t1, "[123:45:6789::5005:11]")); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1); test_streq(p1, "[123:45:6789::5005:11]"); test_eq(AF_INET, tor_addr_parse(&t1, "18.0.0.1")); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1); test_streq(p1, "18.0.0.1"); /* Test buffer bounds checking of tor_addr_to_str */ test_eq(AF_INET6, tor_addr_parse(&t1, "::")); /* 2 + \0 */ test_eq_ptr(tor_addr_to_str(buf, &t1, 2, 0), NULL); /* too short buf */ test_streq(tor_addr_to_str(buf, &t1, 3, 0), "::"); test_eq_ptr(tor_addr_to_str(buf, &t1, 4, 1), NULL); /* too short buf */ test_streq(tor_addr_to_str(buf, &t1, 5, 1), "[::]"); test_eq(AF_INET6, tor_addr_parse(&t1, "2000::1337")); /* 10 + \0 */ test_eq_ptr(tor_addr_to_str(buf, &t1, 10, 0), NULL); /* too short buf */ test_streq(tor_addr_to_str(buf, &t1, 11, 0), "2000::1337"); test_eq_ptr(tor_addr_to_str(buf, &t1, 12, 1), NULL); /* too short buf */ test_streq(tor_addr_to_str(buf, &t1, 13, 1), "[2000::1337]"); test_eq(AF_INET, tor_addr_parse(&t1, "1.2.3.4")); /* 7 + \0 */ test_eq_ptr(tor_addr_to_str(buf, &t1, 7, 0), NULL); /* too short buf */ test_streq(tor_addr_to_str(buf, &t1, 8, 0), "1.2.3.4"); test_eq(AF_INET, tor_addr_parse(&t1, "255.255.255.255")); /* 15 + \0 */ test_eq_ptr(tor_addr_to_str(buf, &t1, 15, 0), NULL); /* too short buf */ test_streq(tor_addr_to_str(buf, &t1, 16, 0), "255.255.255.255"); test_eq_ptr(tor_addr_to_str(buf, &t1, 15, 1), NULL); /* too short buf */ test_streq(tor_addr_to_str(buf, &t1, 16, 1), "255.255.255.255"); t1.family = AF_UNSPEC; test_eq_ptr(tor_addr_to_str(buf, &t1, sizeof(buf), 0), NULL); /* Test tor_addr_parse_PTR_name */ i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 0); test_eq(0, i); i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 1); test_eq(0, i); i = tor_addr_parse_PTR_name(&t1, "1.0.168.192.in-addr.arpa", AF_UNSPEC, 1); test_eq(1, i); test_eq(tor_addr_family(&t1), AF_INET); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1); test_streq(p1, "192.168.0.1"); i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 0); test_eq(0, i); i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 1); test_eq(1, i); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1); test_streq(p1, "192.168.0.99"); memset(&t1, 0, sizeof(t1)); i = tor_addr_parse_PTR_name(&t1, "0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f." "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9." "ip6.ARPA", AF_UNSPEC, 0); test_eq(1, i); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1); test_streq(p1, "[9dee:effe:ebe1:beef:fedc:ba98:7654:3210]"); /* Failing cases. */ i = tor_addr_parse_PTR_name(&t1, "6.7.8.9.a.b.c.d.e.f." "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9." "ip6.ARPA", AF_UNSPEC, 0); test_eq(i, -1); i = tor_addr_parse_PTR_name(&t1, "6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.f.0." "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9." "ip6.ARPA", AF_UNSPEC, 0); test_eq(i, -1); i = tor_addr_parse_PTR_name(&t1, "6.7.8.9.a.b.c.d.e.f.X.0.0.0.0.9." "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9." "ip6.ARPA", AF_UNSPEC, 0); test_eq(i, -1); i = tor_addr_parse_PTR_name(&t1, "32.1.1.in-addr.arpa", AF_UNSPEC, 0); test_eq(i, -1); i = tor_addr_parse_PTR_name(&t1, ".in-addr.arpa", AF_UNSPEC, 0); test_eq(i, -1); i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa", AF_UNSPEC, 0); test_eq(i, -1); i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa", AF_INET6, 0); test_eq(i, -1); i = tor_addr_parse_PTR_name(&t1, "6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.0." "f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9." "ip6.ARPA", AF_INET, 0); test_eq(i, -1); /* === Test tor_addr_to_PTR_name */ /* Stage IPv4 addr */ memset(&sa_storage, 0, sizeof(sa_storage)); sin = (struct sockaddr_in *)&sa_storage; sin->sin_family = AF_INET; sin->sin_addr.s_addr = htonl(0x7f010203); /* 127.1.2.3 */ tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL); /* Check IPv4 PTR - too short buffer */ test_eq(tor_addr_to_PTR_name(rbuf, 1, &t1), -1); test_eq(tor_addr_to_PTR_name(rbuf, strlen("3.2.1.127.in-addr.arpa") - 1, &t1), -1); /* Check IPv4 PTR - valid addr */ test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1), strlen("3.2.1.127.in-addr.arpa")); test_streq(rbuf, "3.2.1.127.in-addr.arpa"); /* Invalid addr family */ t1.family = AF_UNSPEC; test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1), -1); /* Stage IPv6 addr */ memset(&sa_storage, 0, sizeof(sa_storage)); sin6 = (struct sockaddr_in6 *)&sa_storage; sin6->sin6_family = AF_INET6; sin6->sin6_addr.s6_addr[0] = 0x80; /* 8000::abcd */ sin6->sin6_addr.s6_addr[14] = 0xab; sin6->sin6_addr.s6_addr[15] = 0xcd; tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL); { const char* addr_PTR = "d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0." "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.ip6.arpa"; /* Check IPv6 PTR - too short buffer */ test_eq(tor_addr_to_PTR_name(rbuf, 0, &t1), -1); test_eq(tor_addr_to_PTR_name(rbuf, strlen(addr_PTR) - 1, &t1), -1); /* Check IPv6 PTR - valid addr */ test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1), strlen(addr_PTR)); test_streq(rbuf, addr_PTR); } /* XXXX turn this into a separate function; it's not all IPv6. */ /* test tor_addr_parse_mask_ports */ test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6, 0, 0, 0, 0x0000000f, 17, 47, 95); test_streq(p1, "::f"); //test_addr_parse("[::fefe:4.1.1.7/120]:999-1000"); //test_addr_parse_check("::fefe:401:107", 120, 999, 1000); test_addr_mask_ports_parse("[::ffff:4.1.1.7]/120:443", AF_INET6, 0, 0, 0x0000ffff, 0x04010107, 120, 443, 443); test_streq(p1, "::ffff:4.1.1.7"); test_addr_mask_ports_parse("[abcd:2::44a:0]:2-65000", AF_INET6, 0xabcd0002, 0, 0, 0x044a0000, 128, 2, 65000); test_streq(p1, "abcd:2::44a:0"); /* Try some long addresses. */ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111]", 0, &t1, NULL, NULL, NULL); test_assert(r == AF_INET6); r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:11111]", 0, &t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111:1]", 0, &t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports( "[ffff:1111:1111:1111:1111:1111:1111:ffff:" "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:" "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:" "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]", 0, &t1, NULL, NULL, NULL); test_assert(r == -1); /* Try some failing cases. */ r=tor_addr_parse_mask_ports("[fefef::]/112", 0, &t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[fefe::/112", 0, &t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[fefe::", 0, &t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[fefe::X]", 0, &t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("efef::/112", 0, &t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]",0,&t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/fred",0,&t1,&mask, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/255.255.0.0", 0,&t1, NULL, NULL, NULL); test_assert(r == -1); /* This one will get rejected because it isn't a pure prefix. */ r=tor_addr_parse_mask_ports("1.1.2.3/255.255.64.0",0,&t1, &mask,NULL,NULL); test_assert(r == -1); /* Test for V4-mapped address with mask < 96. (arguably not valid) */ r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]",0,&t1, &mask, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("1.1.2.2/33",0,&t1, &mask, NULL, NULL); test_assert(r == -1); /* Try extended wildcard addresses with out TAPMP_EXTENDED_STAR*/ r=tor_addr_parse_mask_ports("*4",0,&t1, &mask, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("*6",0,&t1, &mask, NULL, NULL); test_assert(r == -1); #if 0 /* Try a mask with a wildcard. */ r=tor_addr_parse_mask_ports("*/16",0,&t1, &mask, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("*4/16",TAPMP_EXTENDED_STAR, &t1, &mask, NULL, NULL); test_assert(r == -1); r=tor_addr_parse_mask_ports("*6/30",TAPMP_EXTENDED_STAR, &t1, &mask, NULL, NULL); test_assert(r == -1); #endif /* Basic mask tests*/ r=tor_addr_parse_mask_ports("1.1.2.2/31",0,&t1, &mask, NULL, NULL); test_assert(r == AF_INET); tt_int_op(mask,==,31); tt_int_op(tor_addr_family(&t1),==,AF_INET); tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010202); r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2); test_assert(r == AF_INET); tt_int_op(mask,==,32); tt_int_op(tor_addr_family(&t1),==,AF_INET); tt_int_op(tor_addr_to_ipv4h(&t1),==,0x03041020); test_assert(port1 == 1); test_assert(port2 == 2); r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL); test_assert(r == AF_INET); tt_int_op(mask,==,17); tt_int_op(tor_addr_family(&t1),==,AF_INET); tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010203); r=tor_addr_parse_mask_ports("[efef::]/112",0,&t1, &mask, &port1, &port2); test_assert(r == AF_INET6); test_assert(port1 == 1); test_assert(port2 == 65535); /* Try regular wildcard behavior without TAPMP_EXTENDED_STAR */ r=tor_addr_parse_mask_ports("*:80-443",0,&t1,&mask,&port1,&port2); tt_int_op(r,==,AF_INET); /* Old users of this always get inet */ tt_int_op(tor_addr_family(&t1),==,AF_INET); tt_int_op(tor_addr_to_ipv4h(&t1),==,0); tt_int_op(mask,==,0); tt_int_op(port1,==,80); tt_int_op(port2,==,443); /* Now try wildcards *with* TAPMP_EXTENDED_STAR */ r=tor_addr_parse_mask_ports("*:8000-9000",TAPMP_EXTENDED_STAR, &t1,&mask,&port1,&port2); tt_int_op(r,==,AF_UNSPEC); tt_int_op(tor_addr_family(&t1),==,AF_UNSPEC); tt_int_op(mask,==,0); tt_int_op(port1,==,8000); tt_int_op(port2,==,9000); r=tor_addr_parse_mask_ports("*4:6667",TAPMP_EXTENDED_STAR, &t1,&mask,&port1,&port2); tt_int_op(r,==,AF_INET); tt_int_op(tor_addr_family(&t1),==,AF_INET); tt_int_op(tor_addr_to_ipv4h(&t1),==,0); tt_int_op(mask,==,0); tt_int_op(port1,==,6667); tt_int_op(port2,==,6667); r=tor_addr_parse_mask_ports("*6",TAPMP_EXTENDED_STAR, &t1,&mask,&port1,&port2); tt_int_op(r,==,AF_INET6); tt_int_op(tor_addr_family(&t1),==,AF_INET6); tt_assert(tor_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16)); tt_int_op(mask,==,0); tt_int_op(port1,==,1); tt_int_op(port2,==,65535); /* make sure inet address lengths >= max */ test_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255")); test_assert(TOR_ADDR_BUF_LEN >= sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")); test_assert(sizeof(tor_addr_t) >= sizeof(struct in6_addr)); /* get interface addresses */ r = get_interface_address6(LOG_DEBUG, AF_INET, &t1); i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2); TT_BLATHER(("v4 address: %s (family=%d)", fmt_addr(&t1), tor_addr_family(&t1))); TT_BLATHER(("v6 address: %s (family=%d)", fmt_addr(&t2), tor_addr_family(&t2))); done: ; } /** Test tor_addr_port_parse(). */ static void test_addr_parse(void) { int r; tor_addr_t addr; char buf[TOR_ADDR_BUF_LEN]; uint16_t port = 0; /* Correct call. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.1:1234", &addr, &port); test_assert(r == 0); tor_addr_to_str(buf, &addr, sizeof(buf), 0); test_streq(buf, "192.0.2.1"); test_eq(port, 1234); /* Domain name. */ r= tor_addr_port_parse(LOG_DEBUG, "torproject.org:1234", &addr, &port); test_assert(r == -1); /* Only IP. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.2", &addr, &port); test_assert(r == -1); /* Bad port. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.2:66666", &addr, &port); test_assert(r == -1); /* Only domain name */ r= tor_addr_port_parse(LOG_DEBUG, "torproject.org", &addr, &port); test_assert(r == -1); /* Bad IP address */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2:1234", &addr, &port); test_assert(r == -1); done: ; } static void update_difference(int ipv6, uint8_t *d, const tor_addr_t *a, const tor_addr_t *b) { const int n_bytes = ipv6 ? 16 : 4; uint8_t a_tmp[4], b_tmp[4]; const uint8_t *ba, *bb; int i; if (ipv6) { ba = tor_addr_to_in6_addr8(a); bb = tor_addr_to_in6_addr8(b); } else { set_uint32(a_tmp, tor_addr_to_ipv4n(a)); set_uint32(b_tmp, tor_addr_to_ipv4n(b)); ba = a_tmp; bb = b_tmp; } for (i = 0; i < n_bytes; ++i) { d[i] |= ba[i] ^ bb[i]; } } static void test_virtaddrmap(void *data) { /* Let's start with a bunch of random addresses. */ int ipv6, bits, iter, b; virtual_addr_conf_t cfg[2]; uint8_t bytes[16]; (void)data; tor_addr_parse(&cfg[0].addr, "64.65.0.0"); tor_addr_parse(&cfg[1].addr, "3491:c0c0::"); for (ipv6 = 0; ipv6 <= 1; ++ipv6) { for (bits = 0; bits < 18; ++bits) { tor_addr_t last_a; cfg[ipv6].bits = bits; memset(bytes, 0, sizeof(bytes)); tor_addr_copy(&last_a, &cfg[ipv6].addr); /* Generate 128 addresses with each addr/bits combination. */ for (iter = 0; iter < 128; ++iter) { tor_addr_t a; get_random_virtual_addr(&cfg[ipv6], &a); //printf("%s\n", fmt_addr(&a)); /* Make sure that the first b bits match the configured network */ tt_int_op(0, ==, tor_addr_compare_masked(&a, &cfg[ipv6].addr, bits, CMP_EXACT)); /* And track which bits have been different between pairs of * addresses */ update_difference(ipv6, bytes, &last_a, &a); } /* Now make sure all but the first 'bits' bits of bytes are true */ for (b = bits+1; b < (ipv6?128:32); ++b) { tt_assert(1 & (bytes[b/8] >> (7-(b&7)))); } } } done: ; } static void test_addr_is_loopback(void *data) { static const struct loopback_item { const char *name; int is_loopback; } loopback_items[] = { { "::1", 1 }, { "127.0.0.1", 1 }, { "127.99.100.101", 1 }, { "128.99.100.101", 0 }, { "8.8.8.8", 0 }, { "0.0.0.0", 0 }, { "::2", 0 }, { "::", 0 }, { "::1.0.0.0", 0 }, { NULL, 0 } }; int i; tor_addr_t addr; (void)data; for (i=0; loopback_items[i].name; ++i) { tt_int_op(tor_addr_parse(&addr, loopback_items[i].name), >=, 0); tt_int_op(tor_addr_is_loopback(&addr), ==, loopback_items[i].is_loopback); } tor_addr_make_unspec(&addr); tt_int_op(tor_addr_is_loopback(&addr), ==, 0); done: ; } #define ADDR_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name } struct testcase_t addr_tests[] = { ADDR_LEGACY(basic), ADDR_LEGACY(ip6_helpers), ADDR_LEGACY(parse), { "virtaddr", test_virtaddrmap, 0, NULL, NULL }, { "is_loopback", test_addr_is_loopback, 0, NULL, NULL }, END_OF_TESTCASES }; tor-0.2.4.20/src/or/0000755000175000017500000000000012255753765010772 500000000000000tor-0.2.4.20/src/or/microdesc.c0000644000175000017500000006432112255745673013033 00000000000000/* Copyright (c) 2009-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "or.h" #include "circuitbuild.h" #include "config.h" #include "directory.h" #include "dirserv.h" #include "entrynodes.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "policies.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" /** A data structure to hold a bunch of cached microdescriptors. There are * two active files in the cache: a "cache file" that we mmap, and a "journal * file" that we append to. Periodically, we rebuild the cache file to hold * only the microdescriptors that we want to keep */ struct microdesc_cache_t { /** Map from sha256-digest to microdesc_t for every microdesc_t in the * cache. */ HT_HEAD(microdesc_map, microdesc_t) map; /** Name of the cache file. */ char *cache_fname; /** Name of the journal file. */ char *journal_fname; /** Mmap'd contents of the cache file, or NULL if there is none. */ tor_mmap_t *cache_content; /** Number of bytes used in the journal file. */ size_t journal_len; /** Number of bytes in descriptors removed as too old. */ size_t bytes_dropped; /** Total bytes of microdescriptor bodies we have added to this cache */ uint64_t total_len_seen; /** Total number of microdescriptors we have added to this cache */ unsigned n_seen; }; /** Helper: computes a hash of md to place it in a hash table. */ static INLINE unsigned int microdesc_hash_(microdesc_t *md) { unsigned *d = (unsigned*)md->digest; #if SIZEOF_INT == 4 return d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7]; #else return d[0] ^ d[1] ^ d[2] ^ d[3]; #endif } /** Helper: compares a and for equality for hash-table purposes. */ static INLINE int microdesc_eq_(microdesc_t *a, microdesc_t *b) { return tor_memeq(a->digest, b->digest, DIGEST256_LEN); } HT_PROTOTYPE(microdesc_map, microdesc_t, node, microdesc_hash_, microdesc_eq_); HT_GENERATE(microdesc_map, microdesc_t, node, microdesc_hash_, microdesc_eq_, 0.6, malloc, realloc, free); /** Write the body of md into f, with appropriate annotations. * On success, return the total number of bytes written, and set * *annotation_len_out to the number of bytes written as * annotations. */ static ssize_t dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) { ssize_t r = 0; ssize_t written; if (md->body == NULL) { *annotation_len_out = 0; return 0; } /* XXXX drops unknown annotations. */ if (md->last_listed) { char buf[ISO_TIME_LEN+1]; char annotation[ISO_TIME_LEN+32]; format_iso_time(buf, md->last_listed); tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf); if (write_all(fd, annotation, strlen(annotation), 0) < 0) { log_warn(LD_DIR, "Couldn't write microdescriptor annotation: %s", strerror(errno)); return -1; } r += strlen(annotation); *annotation_len_out = r; } else { *annotation_len_out = 0; } md->off = tor_fd_getpos(fd); written = write_all(fd, md->body, md->bodylen, 0); if (written != (ssize_t)md->bodylen) { log_warn(LD_DIR, "Couldn't dump microdescriptor (wrote %ld out of %lu): %s", (long)written, (unsigned long)md->bodylen, strerror(errno)); return -1; } r += md->bodylen; return r; } /** Holds a pointer to the current microdesc_cache_t object, or NULL if no * such object has been allocated. */ static microdesc_cache_t *the_microdesc_cache = NULL; /** Return a pointer to the microdescriptor cache, loading it if necessary. */ microdesc_cache_t * get_microdesc_cache(void) { if (PREDICT_UNLIKELY(the_microdesc_cache==NULL)) { microdesc_cache_t *cache = tor_malloc_zero(sizeof(microdesc_cache_t)); HT_INIT(microdesc_map, &cache->map); cache->cache_fname = get_datadir_fname("cached-microdescs"); cache->journal_fname = get_datadir_fname("cached-microdescs.new"); microdesc_cache_reload(cache); the_microdesc_cache = cache; } return the_microdesc_cache; } /* There are three sources of microdescriptors: 1) Generated by us while acting as a directory authority. 2) Loaded from the cache on disk. 3) Downloaded. */ /** Decode the microdescriptors from the string starting at s and * ending at eos, and store them in cache. If no_save, * mark them as non-writable to disk. If where is SAVED_IN_CACHE, * leave their bodies as pointers to the mmap'd cache. If where is * SAVED_NOWHERE, do not allow annotations. If listed_at is positive, * set the last_listed field of every microdesc to listed_at. If * requested_digests is non-null, then it contains a list of digests we mean * to allow, so we should reject any non-requested microdesc with a different * digest, and alter the list to contain only the digests of those microdescs * we didn't find. * Return a newly allocated list of the added microdescriptors, or NULL */ smartlist_t * microdescs_add_to_cache(microdesc_cache_t *cache, const char *s, const char *eos, saved_location_t where, int no_save, time_t listed_at, smartlist_t *requested_digests256) { smartlist_t *descriptors, *added; const int allow_annotations = (where != SAVED_NOWHERE); descriptors = microdescs_parse_from_string(s, eos, allow_annotations, where); if (listed_at > 0) { SMARTLIST_FOREACH(descriptors, microdesc_t *, md, md->last_listed = listed_at); } if (requested_digests256) { digestmap_t *requested; /* XXXX actually we should just use a digest256map */ requested = digestmap_new(); SMARTLIST_FOREACH(requested_digests256, const char *, cp, digestmap_set(requested, cp, (void*)1)); SMARTLIST_FOREACH_BEGIN(descriptors, microdesc_t *, md) { if (digestmap_get(requested, md->digest)) { digestmap_set(requested, md->digest, (void*)2); } else { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Received non-requested microdesc"); microdesc_free(md); SMARTLIST_DEL_CURRENT(descriptors, md); } } SMARTLIST_FOREACH_END(md); SMARTLIST_FOREACH_BEGIN(requested_digests256, char *, cp) { if (digestmap_get(requested, cp) == (void*)2) { tor_free(cp); SMARTLIST_DEL_CURRENT(requested_digests256, cp); } } SMARTLIST_FOREACH_END(cp); digestmap_free(requested, NULL); } added = microdescs_add_list_to_cache(cache, descriptors, where, no_save); smartlist_free(descriptors); return added; } /** As microdescs_add_to_cache, but takes a list of microdescriptors instead of * a string to decode. Frees any members of descriptors that it does * not add. */ smartlist_t * microdescs_add_list_to_cache(microdesc_cache_t *cache, smartlist_t *descriptors, saved_location_t where, int no_save) { smartlist_t *added; open_file_t *open_file = NULL; int fd = -1; // int n_added = 0; ssize_t size = 0; if (where == SAVED_NOWHERE && !no_save) { fd = start_writing_to_file(cache->journal_fname, OPEN_FLAGS_APPEND|O_BINARY, 0600, &open_file); if (fd < 0) { log_warn(LD_DIR, "Couldn't append to journal in %s: %s", cache->journal_fname, strerror(errno)); } } added = smartlist_new(); SMARTLIST_FOREACH_BEGIN(descriptors, microdesc_t *, md) { microdesc_t *md2; md2 = HT_FIND(microdesc_map, &cache->map, md); if (md2) { /* We already had this one. */ if (md2->last_listed < md->last_listed) md2->last_listed = md->last_listed; microdesc_free(md); if (where != SAVED_NOWHERE) cache->bytes_dropped += size; continue; } /* Okay, it's a new one. */ if (fd >= 0) { size_t annotation_len; size = dump_microdescriptor(fd, md, &annotation_len); if (size < 0) { /* we already warned in dump_microdescriptor */ abort_writing_to_file(open_file); fd = -1; } else { md->saved_location = SAVED_IN_JOURNAL; cache->journal_len += size; } } else { md->saved_location = where; } md->no_save = no_save; HT_INSERT(microdesc_map, &cache->map, md); md->held_in_map = 1; smartlist_add(added, md); ++cache->n_seen; cache->total_len_seen += md->bodylen; } SMARTLIST_FOREACH_END(md); if (fd >= 0) { if (finish_writing_to_file(open_file) < 0) { log_warn(LD_DIR, "Error appending to microdescriptor file: %s", strerror(errno)); smartlist_clear(added); return added; } } { networkstatus_t *ns = networkstatus_get_latest_consensus(); if (ns && ns->flavor == FLAV_MICRODESC) SMARTLIST_FOREACH(added, microdesc_t *, md, nodelist_add_microdesc(md)); } if (smartlist_len(added)) router_dir_info_changed(); return added; } /** Remove every microdescriptor in cache. */ void microdesc_cache_clear(microdesc_cache_t *cache) { microdesc_t **entry, **next; for (entry = HT_START(microdesc_map, &cache->map); entry; entry = next) { microdesc_t *md = *entry; next = HT_NEXT_RMV(microdesc_map, &cache->map, entry); md->held_in_map = 0; microdesc_free(md); } HT_CLEAR(microdesc_map, &cache->map); if (cache->cache_content) { tor_munmap_file(cache->cache_content); cache->cache_content = NULL; } cache->total_len_seen = 0; cache->n_seen = 0; cache->bytes_dropped = 0; } /** Reload the contents of cache from disk. If it is empty, load it * for the first time. Return 0 on success, -1 on failure. */ int microdesc_cache_reload(microdesc_cache_t *cache) { struct stat st; char *journal_content; smartlist_t *added; tor_mmap_t *mm; int total = 0; microdesc_cache_clear(cache); mm = cache->cache_content = tor_mmap_file(cache->cache_fname); if (mm) { added = microdescs_add_to_cache(cache, mm->data, mm->data+mm->size, SAVED_IN_CACHE, 0, -1, NULL); if (added) { total += smartlist_len(added); smartlist_free(added); } } journal_content = read_file_to_str(cache->journal_fname, RFTS_IGNORE_MISSING, &st); if (journal_content) { cache->journal_len = (size_t) st.st_size; added = microdescs_add_to_cache(cache, journal_content, journal_content+st.st_size, SAVED_IN_JOURNAL, 0, -1, NULL); if (added) { total += smartlist_len(added); smartlist_free(added); } tor_free(journal_content); } log_info(LD_DIR, "Reloaded microdescriptor cache. Found %d descriptors.", total); microdesc_cache_rebuild(cache, 0 /* don't force */); return 0; } /** By default, we remove any microdescriptors that have gone at least this * long without appearing in a current consensus. */ #define TOLERATE_MICRODESC_AGE (7*24*60*60) /** Remove all microdescriptors from cache that haven't been listed for * a long time. Does not rebuild the cache on disk. If cutoff is * positive, specifically remove microdescriptors that have been unlisted * since cutoff. If force is true, remove microdescriptors even * if we have no current live microdescriptor consensus. */ void microdesc_cache_clean(microdesc_cache_t *cache, time_t cutoff, int force) { microdesc_t **mdp, *victim; int dropped=0, kept=0; size_t bytes_dropped = 0; time_t now = time(NULL); /* If we don't know a live consensus, don't believe last_listed values: we * might be starting up after being down for a while. */ if (! force && ! networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC)) return; if (cutoff <= 0) cutoff = now - TOLERATE_MICRODESC_AGE; for (mdp = HT_START(microdesc_map, &cache->map); mdp != NULL; ) { if ((*mdp)->last_listed < cutoff) { ++dropped; victim = *mdp; mdp = HT_NEXT_RMV(microdesc_map, &cache->map, mdp); victim->held_in_map = 0; bytes_dropped += victim->bodylen; microdesc_free(victim); } else { ++kept; mdp = HT_NEXT(microdesc_map, &cache->map, mdp); } } if (dropped) { log_info(LD_DIR, "Removed %d/%d microdescriptors as old.", dropped,dropped+kept); cache->bytes_dropped += bytes_dropped; } } static int should_rebuild_md_cache(microdesc_cache_t *cache) { const size_t old_len = cache->cache_content ? cache->cache_content->size : 0; const size_t journal_len = cache->journal_len; const size_t dropped = cache->bytes_dropped; if (journal_len < 16384) return 0; /* Don't bother, not enough has happened yet. */ if (dropped > (journal_len + old_len) / 3) return 1; /* We could save 1/3 or more of the currently used space. */ if (journal_len > old_len / 2) return 1; /* We should append to the regular file */ return 0; } /** * Mark md as having no body, and release any storage previously held * by its body. */ static void microdesc_wipe_body(microdesc_t *md) { if (!md) return; if (md->saved_location != SAVED_IN_CACHE) tor_free(md->body); md->off = 0; md->saved_location = SAVED_NOWHERE; md->body = NULL; md->bodylen = 0; md->no_save = 1; } /** Regenerate the main cache file for cache, clear the journal file, * and update every microdesc_t in the cache with pointers to its new * location. If force is true, do this unconditionally. If * force is false, do it only if we expect to save space on disk. */ int microdesc_cache_rebuild(microdesc_cache_t *cache, int force) { open_file_t *open_file; int fd = -1; microdesc_t **mdp; smartlist_t *wrote; ssize_t size; off_t off = 0, off_real; int orig_size, new_size; if (cache == NULL) { cache = the_microdesc_cache; if (cache == NULL) return 0; } /* Remove dead descriptors */ microdesc_cache_clean(cache, 0/*cutoff*/, 0/*force*/); if (!force && !should_rebuild_md_cache(cache)) return 0; log_info(LD_DIR, "Rebuilding the microdescriptor cache..."); orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0); orig_size += (int)cache->journal_len; fd = start_writing_to_file(cache->cache_fname, OPEN_FLAGS_REPLACE|O_BINARY, 0600, &open_file); if (fd < 0) return -1; wrote = smartlist_new(); HT_FOREACH(mdp, microdesc_map, &cache->map) { microdesc_t *md = *mdp; size_t annotation_len; if (md->no_save || !md->body) continue; size = dump_microdescriptor(fd, md, &annotation_len); if (size < 0) { microdesc_wipe_body(md); /* rewind, in case it was a partial write. */ tor_fd_setpos(fd, off); continue; } tor_assert(((size_t)size) == annotation_len + md->bodylen); md->off = off + annotation_len; off += size; off_real = tor_fd_getpos(fd); if (off_real != off) { log_warn(LD_BUG, "Discontinuity in position in microdescriptor cache." "By my count, I'm at "I64_FORMAT ", but I should be at "I64_FORMAT, I64_PRINTF_ARG(off), I64_PRINTF_ARG(off_real)); off = off_real; } if (md->saved_location != SAVED_IN_CACHE) { tor_free(md->body); md->saved_location = SAVED_IN_CACHE; } smartlist_add(wrote, md); } /* We must do this unmap _before_ we call finish_writing_to_file(), or * windows will not actually replace the file. */ if (cache->cache_content) tor_munmap_file(cache->cache_content); if (finish_writing_to_file(open_file) < 0) { log_warn(LD_DIR, "Error rebuilding microdescriptor cache: %s", strerror(errno)); /* Okay. Let's prevent from making things worse elsewhere. */ cache->cache_content = NULL; HT_FOREACH(mdp, microdesc_map, &cache->map) { microdesc_t *md = *mdp; if (md->saved_location == SAVED_IN_CACHE) { microdesc_wipe_body(md); } } return -1; } cache->cache_content = tor_mmap_file(cache->cache_fname); if (!cache->cache_content && smartlist_len(wrote)) { log_err(LD_DIR, "Couldn't map file that we just wrote to %s!", cache->cache_fname); smartlist_free(wrote); return -1; } SMARTLIST_FOREACH_BEGIN(wrote, microdesc_t *, md) { tor_assert(md->saved_location == SAVED_IN_CACHE); md->body = (char*)cache->cache_content->data + md->off; if (PREDICT_UNLIKELY( md->bodylen < 9 || fast_memneq(md->body, "onion-key", 9) != 0)) { /* XXXX once bug 2022 is solved, we can kill this block and turn it * into just the tor_assert(fast_memeq) */ off_t avail = cache->cache_content->size - md->off; char *bad_str; tor_assert(avail >= 0); bad_str = tor_strndup(md->body, MIN(128, (size_t)avail)); log_err(LD_BUG, "After rebuilding microdesc cache, offsets seem wrong. " " At offset %d, I expected to find a microdescriptor starting " " with \"onion-key\". Instead I got %s.", (int)md->off, escaped(bad_str)); tor_free(bad_str); tor_assert(fast_memeq(md->body, "onion-key", 9)); } } SMARTLIST_FOREACH_END(md); smartlist_free(wrote); write_str_to_file(cache->journal_fname, "", 1); cache->journal_len = 0; cache->bytes_dropped = 0; new_size = cache->cache_content ? (int)cache->cache_content->size : 0; log_info(LD_DIR, "Done rebuilding microdesc cache. " "Saved %d bytes; %d still used.", orig_size-new_size, new_size); return 0; } /** Make sure that the reference count of every microdescriptor in cache is * accurate. */ void microdesc_check_counts(void) { microdesc_t **mdp; if (!the_microdesc_cache) return; HT_FOREACH(mdp, microdesc_map, &the_microdesc_cache->map) { microdesc_t *md = *mdp; unsigned int found=0; const smartlist_t *nodes = nodelist_get_list(); SMARTLIST_FOREACH(nodes, node_t *, node, { if (node->md == md) { ++found; } }); tor_assert(found == md->held_by_nodes); } } /** Deallocate a single microdescriptor. Note: the microdescriptor MUST have * previously been removed from the cache if it had ever been inserted. */ void microdesc_free_(microdesc_t *md, const char *fname, int lineno) { if (!md) return; /* Make sure that the microdesc was really removed from the appropriate data structures. */ if (md->held_in_map) { microdesc_cache_t *cache = get_microdesc_cache(); microdesc_t *md2 = HT_FIND(microdesc_map, &cache->map, md); if (md2 == md) { log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still " "in microdesc_map", fname, lineno); HT_REMOVE(microdesc_map, &cache->map, md); } else { log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_in_map " "set, but microdesc was not in the map.", fname, lineno); } tor_fragile_assert(); } if (md->held_by_nodes) { int found=0; const smartlist_t *nodes = nodelist_get_list(); SMARTLIST_FOREACH(nodes, node_t *, node, { if (node->md == md) { ++found; node->md = NULL; } }); if (found) { log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still " "referenced %d node(s); held_by_nodes == %u", fname, lineno, found, md->held_by_nodes); } else { log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_by_nodes " "set to %u, but md was not referenced by any nodes", fname, lineno, md->held_by_nodes); } tor_fragile_assert(); } //tor_assert(md->held_in_map == 0); //tor_assert(md->held_by_nodes == 0); if (md->onion_pkey) crypto_pk_free(md->onion_pkey); tor_free(md->onion_curve25519_pkey); if (md->body && md->saved_location != SAVED_IN_CACHE) tor_free(md->body); if (md->family) { SMARTLIST_FOREACH(md->family, char *, cp, tor_free(cp)); smartlist_free(md->family); } short_policy_free(md->exit_policy); short_policy_free(md->ipv6_exit_policy); tor_free(md); } /** Free all storage held in the microdesc.c module. */ void microdesc_free_all(void) { if (the_microdesc_cache) { microdesc_cache_clear(the_microdesc_cache); tor_free(the_microdesc_cache->cache_fname); tor_free(the_microdesc_cache->journal_fname); tor_free(the_microdesc_cache); } } /** If there is a microdescriptor in cache whose sha256 digest is * d, return it. Otherwise return NULL. */ microdesc_t * microdesc_cache_lookup_by_digest256(microdesc_cache_t *cache, const char *d) { microdesc_t *md, search; if (!cache) cache = get_microdesc_cache(); memcpy(search.digest, d, DIGEST256_LEN); md = HT_FIND(microdesc_map, &cache->map, &search); return md; } /** Return the mean size of decriptors added to cache since it was last * cleared. Used to estimate the size of large downloads. */ size_t microdesc_average_size(microdesc_cache_t *cache) { if (!cache) cache = get_microdesc_cache(); if (!cache->n_seen) return 512; return (size_t)(cache->total_len_seen / cache->n_seen); } /** Return a smartlist of all the sha256 digest of the microdescriptors that * are listed in ns but not present in cache. Returns pointers * to internals of ns; you should not free the members of the resulting * smartlist. Omit all microdescriptors whose digest appear in skip. */ smartlist_t * microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache, int downloadable_only, digestmap_t *skip) { smartlist_t *result = smartlist_new(); time_t now = time(NULL); tor_assert(ns->flavor == FLAV_MICRODESC); SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { if (microdesc_cache_lookup_by_digest256(cache, rs->descriptor_digest)) continue; if (downloadable_only && !download_status_is_ready(&rs->dl_status, now, MAX_MICRODESC_DOWNLOAD_FAILURES)) continue; if (skip && digestmap_get(skip, rs->descriptor_digest)) continue; if (tor_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN)) continue; /* XXXX Also skip if we're a noncache and wouldn't use this router. * XXXX NM Microdesc */ smartlist_add(result, rs->descriptor_digest); } SMARTLIST_FOREACH_END(rs); return result; } /** Launch download requests for microdescriptors as appropriate. * * Specifically, we should launch download requests if we are configured to * download mirodescriptors, and there are some microdescriptors listed the * current microdesc consensus that we don't have, and either we never asked * for them, or we failed to download them but we're willing to retry. */ void update_microdesc_downloads(time_t now) { const or_options_t *options = get_options(); networkstatus_t *consensus; smartlist_t *missing; digestmap_t *pending; if (should_delay_dir_fetches(options)) return; if (directory_too_idle_to_fetch_descriptors(options, now)) return; consensus = networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC); if (!consensus) return; if (!we_fetch_microdescriptors(options)) return; pending = digestmap_new(); list_pending_microdesc_downloads(pending); missing = microdesc_list_missing_digest256(consensus, get_microdesc_cache(), 1, pending); digestmap_free(pending, NULL); launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC, missing, NULL, now); smartlist_free(missing); } /** For every microdescriptor listed in the current microdecriptor consensus, * update its last_listed field to be at least as recent as the publication * time of the current microdescriptor consensus. */ void update_microdescs_from_networkstatus(time_t now) { microdesc_cache_t *cache = get_microdesc_cache(); microdesc_t *md; networkstatus_t *ns = networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC); if (! ns) return; tor_assert(ns->flavor == FLAV_MICRODESC); SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { md = microdesc_cache_lookup_by_digest256(cache, rs->descriptor_digest); if (md && ns->valid_after > md->last_listed) md->last_listed = ns->valid_after; } SMARTLIST_FOREACH_END(rs); } /** Return true iff we should prefer to use microdescriptors rather than * routerdescs for building circuits. */ int we_use_microdescriptors_for_circuits(const or_options_t *options) { int ret = options->UseMicrodescriptors; if (ret == -1) { /* UseMicrodescriptors is "auto"; we need to decide: */ /* If we are configured to use bridges and none of our bridges * know what a microdescriptor is, the answer is no. */ if (options->UseBridges && !any_bridge_supports_microdescriptors()) return 0; /* Otherwise, we decide that we'll use microdescriptors iff we are * not a server, and we're not autofetching everything. */ /* XXX023 what does not being a server have to do with it? also there's * a partitioning issue here where bridges differ from clients. */ ret = !server_mode(options) && !options->FetchUselessDescriptors; } return ret; } /** Return true iff we should try to download microdescriptors at all. */ int we_fetch_microdescriptors(const or_options_t *options) { if (directory_caches_dir_info(options)) return 1; if (options->FetchUselessDescriptors) return 1; return we_use_microdescriptors_for_circuits(options); } /** Return true iff we should try to download router descriptors at all. */ int we_fetch_router_descriptors(const or_options_t *options) { if (directory_caches_dir_info(options)) return 1; if (options->FetchUselessDescriptors) return 1; return ! we_use_microdescriptors_for_circuits(options); } /** Return the consensus flavor we actually want to use to build circuits. */ int usable_consensus_flavor(void) { if (we_use_microdescriptors_for_circuits(get_options())) { return FLAV_MICRODESC; } else { return FLAV_NS; } } tor-0.2.4.20/src/or/config.h0000644000175000017500000001022212255745673012324 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file config.h * \brief Header file for config.c. **/ #ifndef TOR_CONFIG_H #define TOR_CONFIG_H const char *get_dirportfrontpage(void); const or_options_t *get_options(void); or_options_t *get_options_mutable(void); int set_options(or_options_t *new_val, char **msg); void config_free_all(void); const char *safe_str_client(const char *address); const char *safe_str(const char *address); const char *escaped_safe_str_client(const char *address); const char *escaped_safe_str(const char *address); const char *get_version(void); const char *get_short_version(void); setopt_err_t options_trial_assign(config_line_t *list, int use_defaults, int clear_first, char **msg); uint32_t get_last_resolved_addr(void); int resolve_my_address(int warn_severity, const or_options_t *options, uint32_t *addr_out, const char **method_out, char **hostname_out); int is_local_addr(const tor_addr_t *addr); void options_init(or_options_t *options); char *options_dump(const or_options_t *options, int minimal); int options_init_from_torrc(int argc, char **argv); setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf, int command, const char *command_arg, char **msg); int option_is_recognized(const char *key); const char *option_get_canonical_name(const char *key); config_line_t *option_get_assignment(const or_options_t *options, const char *key); int options_save_current(void); const char *get_torrc_fname(int defaults_fname); char *options_get_datadir_fname2_suffix(const or_options_t *options, const char *sub1, const char *sub2, const char *suffix); #define get_datadir_fname2_suffix(sub1, sub2, suffix) \ options_get_datadir_fname2_suffix(get_options(), (sub1), (sub2), (suffix)) /** Return a newly allocated string containing datadir/sub1. See * get_datadir_fname2_suffix. */ #define get_datadir_fname(sub1) get_datadir_fname2_suffix((sub1), NULL, NULL) /** Return a newly allocated string containing datadir/sub1/sub2. See * get_datadir_fname2_suffix. */ #define get_datadir_fname2(sub1,sub2) \ get_datadir_fname2_suffix((sub1), (sub2), NULL) /** Return a newly allocated string containing datadir/sub1suffix. See * get_datadir_fname2_suffix. */ #define get_datadir_fname_suffix(sub1, suffix) \ get_datadir_fname2_suffix((sub1), NULL, (suffix)) int get_num_cpus(const or_options_t *options); const smartlist_t *get_configured_ports(void); int get_first_advertised_port_by_type_af(int listener_type, int address_family); #define get_primary_or_port() \ (get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, AF_INET)) #define get_primary_dir_port() \ (get_first_advertised_port_by_type_af(CONN_TYPE_DIR_LISTENER, AF_INET)) char *get_first_listener_addrport_string(int listener_type); int options_need_geoip_info(const or_options_t *options, const char **reason_out); smartlist_t *get_list_of_ports_to_forward(void); int getinfo_helper_config(control_connection_t *conn, const char *question, char **answer, const char **errmsg); const char *tor_get_digests(void); uint32_t get_effective_bwrate(const or_options_t *options); uint32_t get_effective_bwburst(const or_options_t *options); char *get_transport_bindaddr_from_config(const char *transport); #ifdef CONFIG_PRIVATE /* Used only by config.c and test.c */ or_options_t *options_new(void); #endif void config_register_addressmaps(const or_options_t *options); /* XXXX024 move to connection_edge.h */ int addressmap_register_auto(const char *from, const char *to, time_t expires, addressmap_entry_source_t addrmap_source, const char **msg); #endif tor-0.2.4.20/src/or/rephist.h0000644000175000017500000001052712240762314012526 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file rephist.h * \brief Header file for rephist.c. **/ #ifndef TOR_REPHIST_H #define TOR_REPHIST_H void rep_hist_init(void); void rep_hist_note_connect_failed(const char* nickname, time_t when); void rep_hist_note_connect_succeeded(const char* nickname, time_t when); void rep_hist_note_disconnect(const char* nickname, time_t when); void rep_hist_note_connection_died(const char* nickname, time_t when); void rep_hist_note_extend_succeeded(const char *from_name, const char *to_name); void rep_hist_note_extend_failed(const char *from_name, const char *to_name); void rep_hist_dump_stats(time_t now, int severity); void rep_hist_note_bytes_read(size_t num_bytes, time_t when); void rep_hist_note_bytes_written(size_t num_bytes, time_t when); void rep_hist_make_router_pessimal(const char *id, time_t when); void rep_hist_note_dir_bytes_read(size_t num_bytes, time_t when); void rep_hist_note_dir_bytes_written(size_t num_bytes, time_t when); int rep_hist_bandwidth_assess(void); char *rep_hist_get_bandwidth_lines(void); void rep_hist_update_state(or_state_t *state); int rep_hist_load_state(or_state_t *state, char **err); void rep_history_clean(time_t before); void rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr, const uint16_t at_port, time_t when); void rep_hist_note_router_unreachable(const char *id, time_t when); int rep_hist_record_mtbf_data(time_t now, int missing_means_down); int rep_hist_load_mtbf_data(time_t now); time_t rep_hist_downrate_old_runs(time_t now); long rep_hist_get_uptime(const char *id, time_t when); double rep_hist_get_stability(const char *id, time_t when); double rep_hist_get_weighted_fractional_uptime(const char *id, time_t when); long rep_hist_get_weighted_time_known(const char *id, time_t when); int rep_hist_have_measured_enough_stability(void); const char *rep_hist_get_router_stability_doc(time_t now); void rep_hist_note_used_port(time_t now, uint16_t port); smartlist_t *rep_hist_get_predicted_ports(time_t now); void rep_hist_remove_predicted_ports(const smartlist_t *rmv_ports); void rep_hist_note_used_resolve(time_t now); void rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity); int rep_hist_get_predicted_internal(time_t now, int *need_uptime, int *need_capacity); int any_predicted_circuits(time_t now); int rep_hist_circbuilding_dormant(time_t now); void note_crypto_pk_op(pk_op_t operation); void dump_pk_ops(int severity); void rep_hist_exit_stats_init(time_t now); void rep_hist_reset_exit_stats(time_t now); void rep_hist_exit_stats_term(void); char *rep_hist_format_exit_stats(time_t now); time_t rep_hist_exit_stats_write(time_t now); void rep_hist_note_exit_bytes(uint16_t port, size_t num_written, size_t num_read); void rep_hist_note_exit_stream_opened(uint16_t port); void rep_hist_buffer_stats_init(time_t now); void rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval); time_t rep_hist_buffer_stats_write(time_t now); void rep_hist_buffer_stats_term(void); void rep_hist_add_buffer_stats(double mean_num_cells_in_queue, double mean_time_cells_in_queue, uint32_t processed_cells); char *rep_hist_format_buffer_stats(time_t now); void rep_hist_reset_buffer_stats(time_t now); void rep_hist_desc_stats_init(time_t now); void rep_hist_note_desc_served(const char * desc); void rep_hist_desc_stats_term(void); time_t rep_hist_desc_stats_write(time_t now); void rep_hist_conn_stats_init(time_t now); void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read, size_t num_written, time_t when); void rep_hist_reset_conn_stats(time_t now); char *rep_hist_format_conn_stats(time_t now); time_t rep_hist_conn_stats_write(time_t now); void rep_hist_conn_stats_term(void); void rep_hist_note_circuit_handshake_requested(uint16_t type); void rep_hist_note_circuit_handshake_completed(uint16_t type); void rep_hist_log_circuit_handshake_stats(time_t now); void rep_hist_free_all(void); #endif tor-0.2.4.20/src/or/directory.c0000644000175000017500000045511412255745673013073 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "or.h" #include "buffers.h" #include "circuitbuild.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "control.h" #include "directory.h" #include "dirserv.h" #include "dirvote.h" #include "entrynodes.h" #include "geoip.h" #include "main.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "policies.h" #include "rendclient.h" #include "rendcommon.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" #include "routerset.h" #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) #ifndef OPENBSD #include #endif #endif /** * \file directory.c * \brief Code to send and fetch directories and router * descriptors via HTTP. Directories use dirserv.c to generate the * results; clients use routers.c to parse them. **/ /* In-points to directory.c: * * - directory_post_to_dirservers(), called from * router_upload_dir_desc_to_dirservers() in router.c * upload_service_descriptor() in rendservice.c * - directory_get_from_dirserver(), called from * rend_client_refetch_renddesc() in rendclient.c * run_scheduled_events() in main.c * do_hup() in main.c * - connection_dir_process_inbuf(), called from * connection_process_inbuf() in connection.c * - connection_dir_finished_flushing(), called from * connection_finished_flushing() in connection.c * - connection_dir_finished_connecting(), called from * connection_finished_connecting() in connection.c */ static void directory_send_command(dir_connection_t *conn, int purpose, int direct, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since); static int directory_handle_command(dir_connection_t *conn); static int body_is_plausible(const char *body, size_t body_len, int purpose); static int purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose); static char *http_get_header(const char *headers, const char *which); static void http_set_address_origin(const char *headers, connection_t *conn); static void connection_dir_download_v2_networkstatus_failed( dir_connection_t *conn, int status_code); static void connection_dir_download_routerdesc_failed(dir_connection_t *conn); static void connection_dir_bridge_routerdesc_failed(dir_connection_t *conn); static void connection_dir_download_cert_failed( dir_connection_t *conn, int status_code); static void connection_dir_retry_bridges(smartlist_t *descs); static void dir_networkstatus_download_failed(smartlist_t *failed, int status_code); static void dir_routerdesc_download_failed(smartlist_t *failed, int status_code, int router_purpose, int was_extrainfo, int was_descriptor_digests); static void dir_microdesc_download_failed(smartlist_t *failed, int status_code); static void note_client_request(int purpose, int compressed, size_t bytes); static int client_likes_consensus(networkstatus_t *v, const char *want_url); static void directory_initiate_command_rend(const char *address, const tor_addr_t *addr, uint16_t or_port, uint16_t dir_port, const char *digest, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since, const rend_data_t *rend_query); /********* START VARIABLES **********/ /** How far in the future do we allow a directory server to tell us it is * before deciding that one of us has the wrong time? */ #define ALLOW_DIRECTORY_TIME_SKEW (30*60) #define X_ADDRESS_HEADER "X-Your-Address-Is: " /** HTTP cache control: how long do we tell proxies they can cache each * kind of document we serve? */ #define FULL_DIR_CACHE_LIFETIME (60*60) #define RUNNINGROUTERS_CACHE_LIFETIME (20*60) #define DIRPORTFRONTPAGE_CACHE_LIFETIME (20*60) #define NETWORKSTATUS_CACHE_LIFETIME (5*60) #define ROUTERDESC_CACHE_LIFETIME (30*60) #define ROUTERDESC_BY_DIGEST_CACHE_LIFETIME (48*60*60) #define ROBOTS_CACHE_LIFETIME (24*60*60) #define MICRODESC_CACHE_LIFETIME (48*60*60) /********* END VARIABLES ************/ /** Return true iff the directory purpose dir_purpose (and if it's * fetching descriptors, it's fetching them for router_purpose) * must use an anonymous connection to a directory. */ static int purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose) { if (get_options()->AllDirActionsPrivate) return 1; if (router_purpose == ROUTER_PURPOSE_BRIDGE) return 1; /* if no circuits yet, this might break bootstrapping, but it's * needed to be safe. */ if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR || dir_purpose == DIR_PURPOSE_UPLOAD_VOTE || dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES || dir_purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS || dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE || dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES || dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS || dir_purpose == DIR_PURPOSE_FETCH_CERTIFICATE || dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC || dir_purpose == DIR_PURPOSE_FETCH_EXTRAINFO || dir_purpose == DIR_PURPOSE_FETCH_MICRODESC) return 0; return 1; } /** Return a newly allocated string describing auth. Only describes * authority features. */ static char * authdir_type_to_string(dirinfo_type_t auth) { char *result; smartlist_t *lst = smartlist_new(); if (auth & V1_DIRINFO) smartlist_add(lst, (void*)"V1"); if (auth & V2_DIRINFO) smartlist_add(lst, (void*)"V2"); if (auth & V3_DIRINFO) smartlist_add(lst, (void*)"V3"); if (auth & BRIDGE_DIRINFO) smartlist_add(lst, (void*)"Bridge"); if (auth & HIDSERV_DIRINFO) smartlist_add(lst, (void*)"Hidden service"); if (smartlist_len(lst)) { result = smartlist_join_strings(lst, ", ", 0, NULL); } else { result = tor_strdup("[Not an authority]"); } smartlist_free(lst); return result; } /** Return a string describing a given directory connection purpose. */ static const char * dir_conn_purpose_to_string(int purpose) { switch (purpose) { case DIR_PURPOSE_FETCH_RENDDESC: return "hidden-service descriptor fetch"; case DIR_PURPOSE_UPLOAD_DIR: return "server descriptor upload"; case DIR_PURPOSE_UPLOAD_RENDDESC: return "hidden-service descriptor upload"; case DIR_PURPOSE_UPLOAD_VOTE: return "server vote upload"; case DIR_PURPOSE_UPLOAD_SIGNATURES: return "consensus signature upload"; case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS: return "network-status fetch"; case DIR_PURPOSE_FETCH_SERVERDESC: return "server descriptor fetch"; case DIR_PURPOSE_FETCH_EXTRAINFO: return "extra-info fetch"; case DIR_PURPOSE_FETCH_CONSENSUS: return "consensus network-status fetch"; case DIR_PURPOSE_FETCH_CERTIFICATE: return "authority cert fetch"; case DIR_PURPOSE_FETCH_STATUS_VOTE: return "status vote fetch"; case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: return "consensus signature fetch"; case DIR_PURPOSE_FETCH_RENDDESC_V2: return "hidden-service v2 descriptor fetch"; case DIR_PURPOSE_UPLOAD_RENDDESC_V2: return "hidden-service v2 descriptor upload"; case DIR_PURPOSE_FETCH_MICRODESC: return "microdescriptor fetch"; } log_warn(LD_BUG, "Called with unknown purpose %d", purpose); return "(unknown)"; } /** Return true iff identity_digest is the digest of a router we * believe to support extrainfo downloads. (If is_authority we do * additional checking that's only valid for authorities.) */ int router_supports_extrainfo(const char *identity_digest, int is_authority) { const node_t *node = node_get_by_id(identity_digest); if (node && node->ri) { if (node->ri->caches_extra_info) return 1; } if (is_authority) { return 1; } return 0; } /** Return true iff any trusted directory authority has accepted our * server descriptor. * * We consider any authority sufficient because waiting for all of * them means it never happens while any authority is down; we don't * go for something more complex in the middle (like \>1/3 or \>1/2 or * \>=1/2) because that doesn't seem necessary yet. */ int directories_have_accepted_server_descriptor(void) { const smartlist_t *servers = router_get_trusted_dir_servers(); const or_options_t *options = get_options(); SMARTLIST_FOREACH(servers, dir_server_t *, d, { if ((d->type & options->PublishServerDescriptor_) && d->has_accepted_serverdesc) { return 1; } }); return 0; } /** Start a connection to every suitable directory authority, using * connection purpose dir_purpose and uploading payload * (of length payload_len). The dir_purpose should be one of * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'. * * router_purpose describes the type of descriptor we're * publishing, if we're publishing a descriptor -- e.g. general or bridge. * * type specifies what sort of dir authorities (V1, V2, * HIDSERV, BRIDGE) we should upload to. * * If extrainfo_len is nonzero, the first payload_len bytes of * payload hold a router descriptor, and the next extrainfo_len * bytes of payload hold an extra-info document. Upload the descriptor * to all authorities, and the extra-info document to all authorities that * support it. */ void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, dirinfo_type_t type, const char *payload, size_t payload_len, size_t extrainfo_len) { const or_options_t *options = get_options(); int post_via_tor; const smartlist_t *dirservers = router_get_trusted_dir_servers(); int found = 0; const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE || dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES); tor_assert(dirservers); /* This tries dirservers which we believe to be down, but ultimately, that's * harmless, and we may as well err on the side of getting things uploaded. */ SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) { routerstatus_t *rs = &(ds->fake_status); size_t upload_len = payload_len; tor_addr_t ds_addr; if ((type & ds->type) == 0) continue; if (exclude_self && router_digest_is_me(ds->digest)) continue; if (options->StrictNodes && routerset_contains_routerstatus(options->ExcludeNodes, rs, -1)) { log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but " "it's in our ExcludedNodes list and StrictNodes is set. " "Skipping.", ds->nickname, dir_conn_purpose_to_string(dir_purpose)); continue; } found = 1; /* at least one authority of this type was listed */ if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR) ds->has_accepted_serverdesc = 0; if (extrainfo_len && router_supports_extrainfo(ds->digest, 1)) { upload_len += extrainfo_len; log_info(LD_DIR, "Uploading an extrainfo too (length %d)", (int) extrainfo_len); } tor_addr_from_ipv4h(&ds_addr, ds->addr); post_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose) || !fascist_firewall_allows_address_dir(&ds_addr, ds->dir_port); directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose, post_via_tor, NULL, payload, upload_len, 0); } SMARTLIST_FOREACH_END(ds); if (!found) { char *s = authdir_type_to_string(type); log_warn(LD_DIR, "Publishing server descriptor to directory authorities " "of type '%s', but no authorities of that type listed!", s); tor_free(s); } } /** Return true iff, according to the values in options, we should be * using directory guards for direct downloads of directory information. */ static int should_use_directory_guards(const or_options_t *options) { /* Public (non-bridge) servers never use directory guards. */ if (public_server_mode(options)) return 0; /* If guards are disabled, or directory guards are disabled, we can't * use directory guards. */ if (!options->UseEntryGuards || !options->UseEntryGuardsAsDirGuards) return 0; /* If we're configured to fetch directory info aggressively or of a * nonstandard type, don't use directory guards. */ if (options->DownloadExtraInfo || options->FetchDirInfoEarly || options->FetchDirInfoExtraEarly || options->FetchUselessDescriptors || options->FetchV2Networkstatus) return 0; if (! options->PreferTunneledDirConns) return 0; return 1; } /** Pick an unconsetrained directory server from among our guards, the latest * networkstatus, or the fallback dirservers, for use in downloading * information of type type, and return its routerstatus. */ static const routerstatus_t * directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags, uint8_t dir_purpose) { const routerstatus_t *rs = NULL; const or_options_t *options = get_options(); if (options->UseBridges) log_warn(LD_BUG, "Called when we have UseBridges set."); if (should_use_directory_guards(options)) { const node_t *node = choose_random_dirguard(type); if (node) rs = node->rs; } else { /* anybody with a non-zero dirport will do */ rs = router_pick_directory_server(type, pds_flags); } if (!rs) { log_info(LD_DIR, "No router found for %s; falling back to " "dirserver list.", dir_conn_purpose_to_string(dir_purpose)); rs = router_pick_fallback_dirserver(type, pds_flags); } return rs; } /** Start a connection to a random running directory server, using * connection purpose dir_purpose, intending to fetch descriptors * of purpose router_purpose, and requesting resource. * Use pds_flags as arguments to router_pick_directory_server() * or router_pick_trusteddirserver(). */ void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose, const char *resource, int pds_flags) { const routerstatus_t *rs = NULL; const or_options_t *options = get_options(); int prefer_authority = directory_fetches_from_authorities(options); int require_authority = 0; int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose); dirinfo_type_t type; time_t if_modified_since = 0; /* FFFF we could break this switch into its own function, and call * it elsewhere in directory.c. -RD */ switch (dir_purpose) { case DIR_PURPOSE_FETCH_EXTRAINFO: type = EXTRAINFO_DIRINFO | (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO : V3_DIRINFO); break; case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS: type = V2_DIRINFO; prefer_authority = 1; /* Only v2 authorities have these anyway. */ require_authority = 1; /* Don't fallback to asking a non-authority */ break; case DIR_PURPOSE_FETCH_SERVERDESC: type = (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO : V3_DIRINFO); break; case DIR_PURPOSE_FETCH_RENDDESC: type = HIDSERV_DIRINFO; break; case DIR_PURPOSE_FETCH_STATUS_VOTE: case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: case DIR_PURPOSE_FETCH_CERTIFICATE: type = V3_DIRINFO; break; case DIR_PURPOSE_FETCH_CONSENSUS: type = V3_DIRINFO; if (resource && !strcmp(resource,"microdesc")) type |= MICRODESC_DIRINFO; break; case DIR_PURPOSE_FETCH_MICRODESC: type = MICRODESC_DIRINFO; break; default: log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose); return; } if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) { int flav = FLAV_NS; networkstatus_t *v; if (resource) flav = networkstatus_parse_flavor_name(resource); if (flav != -1) { /* IF we have a parsed consensus of this type, we can do an * if-modified-time based on it. */ v = networkstatus_get_latest_consensus_by_flavor(flav); if (v) if_modified_since = v->valid_after + 180; } else { /* Otherwise it might be a consensus we don't parse, but which we * do cache. Look at the cached copy, perhaps. */ cached_dir_t *cd = dirserv_get_consensus(resource); if (cd) if_modified_since = cd->published + 180; } } if (!options->FetchServerDescriptors && type != HIDSERV_DIRINFO) return; if (!get_via_tor) { if (options->UseBridges && type != BRIDGE_DIRINFO) { /* We want to ask a running bridge for which we have a descriptor. * * When we ask choose_random_entry() for a bridge, we specify what * sort of dir fetch we'll be doing, so it won't return a bridge * that can't answer our question. */ /* XXX024 Not all bridges handle conditional consensus downloading, * so, for now, never assume the server supports that. -PP */ const node_t *node = choose_random_dirguard(type); if (node && node->ri) { /* every bridge has a routerinfo. */ tor_addr_t addr; routerinfo_t *ri = node->ri; node_get_addr(node, &addr); directory_initiate_command(ri->address, &addr, ri->or_port, 0/*no dirport*/, ri->cache_info.identity_digest, dir_purpose, router_purpose, DIRIND_ONEHOP, resource, NULL, 0, if_modified_since); } else log_notice(LD_DIR, "Ignoring directory request, since no bridge " "nodes are available yet."); return; } else { if (prefer_authority || type == BRIDGE_DIRINFO) { /* only ask authdirservers, and don't ask myself */ rs = router_pick_trusteddirserver(type, pds_flags); if (rs == NULL && (pds_flags & (PDS_NO_EXISTING_SERVERDESC_FETCH| PDS_NO_EXISTING_MICRODESC_FETCH))) { /* We don't want to fetch from any authorities that we're currently * fetching server descriptors from, and we got no match. Did we * get no match because all the authorities have connections * fetching server descriptors (in which case we should just * return,) or because all the authorities are down or on fire or * unreachable or something (in which case we should go on with * our fallback code)? */ pds_flags &= ~(PDS_NO_EXISTING_SERVERDESC_FETCH| PDS_NO_EXISTING_MICRODESC_FETCH); rs = router_pick_trusteddirserver(type, pds_flags); if (rs) { log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities " "are in use."); return; } } if (rs == NULL && require_authority) { log_info(LD_DIR, "No authorities were available for %s: will try " "later.", dir_conn_purpose_to_string(dir_purpose)); return; } } if (!rs && type != BRIDGE_DIRINFO) { /* */ rs = directory_pick_generic_dirserver(type, pds_flags, dir_purpose); if (!rs) { /*XXXX024 I'm pretty sure this can never do any good, since * rs isn't set. */ get_via_tor = 1; /* last resort: try routing it via Tor */ } } } } else { /* get_via_tor */ /* Never use fascistfirewall; we're going via Tor. */ if (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) { /* only ask hidserv authorities, any of them will do */ pds_flags |= PDS_IGNORE_FASCISTFIREWALL|PDS_ALLOW_SELF; rs = router_pick_trusteddirserver(HIDSERV_DIRINFO, pds_flags); } else { /* anybody with a non-zero dirport will do. Disregard firewalls. */ pds_flags |= PDS_IGNORE_FASCISTFIREWALL; rs = router_pick_directory_server(type, pds_flags); /* If we have any hope of building an indirect conn, we know some router * descriptors. If (rs==NULL), we can't build circuits anyway, so * there's no point in falling back to the authorities in this case. */ } } if (rs) { const dir_indirection_t indirection = get_via_tor ? DIRIND_ANONYMOUS : DIRIND_ONEHOP; directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose, indirection, resource, NULL, 0, if_modified_since); } else { log_notice(LD_DIR, "While fetching directory info, " "no running dirservers known. Will try again later. " "(purpose %d)", dir_purpose); if (!purpose_needs_anonymity(dir_purpose, router_purpose)) { /* remember we tried them all and failed. */ directory_all_unreachable(time(NULL)); } } } /** As directory_get_from_dirserver, but initiates a request to every * directory authority other than ourself. Only for use by authorities when * searching for missing information while voting. */ void directory_get_from_all_authorities(uint8_t dir_purpose, uint8_t router_purpose, const char *resource) { tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE || dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES); SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(), dir_server_t *, ds) { routerstatus_t *rs; if (router_digest_is_me(ds->digest)) continue; if (!(ds->type & V3_DIRINFO)) continue; rs = &ds->fake_status; directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose, DIRIND_ONEHOP, resource, NULL, 0, 0); } SMARTLIST_FOREACH_END(ds); } /** Return true iff ind requires a multihop circuit. */ static int dirind_is_anon(dir_indirection_t ind) { return ind == DIRIND_ANON_DIRPORT || ind == DIRIND_ANONYMOUS; } /** Same as directory_initiate_command_routerstatus(), but accepts * rendezvous data to fetch a hidden service descriptor. */ void directory_initiate_command_routerstatus_rend(const routerstatus_t *status, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since, const rend_data_t *rend_query) { const or_options_t *options = get_options(); const node_t *node; char address_buf[INET_NTOA_BUF_LEN+1]; struct in_addr in; const char *address; tor_addr_t addr; const int anonymized_connection = dirind_is_anon(indirection); node = node_get_by_id(status->identity_digest); if (!node && anonymized_connection) { log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we " "don't have its router descriptor.", routerstatus_describe(status)); return; } else if (node) { node_get_address_string(node, address_buf, sizeof(address_buf)); address = address_buf; } else { in.s_addr = htonl(status->addr); tor_inet_ntoa(&in, address_buf, sizeof(address_buf)); address = address_buf; } tor_addr_from_ipv4h(&addr, status->addr); if (options->ExcludeNodes && options->StrictNodes && routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) { log_warn(LD_DIR, "Wanted to contact directory mirror %s for %s, but " "it's in our ExcludedNodes list and StrictNodes is set. " "Skipping. This choice might make your Tor not work.", routerstatus_describe(status), dir_conn_purpose_to_string(dir_purpose)); return; } directory_initiate_command_rend(address, &addr, status->or_port, status->dir_port, status->identity_digest, dir_purpose, router_purpose, indirection, resource, payload, payload_len, if_modified_since, rend_query); } /** Launch a new connection to the directory server status to * upload or download a server or rendezvous * descriptor. dir_purpose determines what * kind of directory connection we're launching, and must be one of * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC|RENDDESC_V2}. router_purpose * specifies the descriptor purposes we have in mind (currently only * used for FETCH_DIR). * * When uploading, payload and payload_len determine the content * of the HTTP post. Otherwise, payload should be NULL. * * When fetching a rendezvous descriptor, resource is the service ID we * want to fetch. */ void directory_initiate_command_routerstatus(const routerstatus_t *status, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since) { directory_initiate_command_routerstatus_rend(status, dir_purpose, router_purpose, indirection, resource, payload, payload_len, if_modified_since, NULL); } /** Return true iff conn is the client side of a directory connection * we launched to ourself in order to determine the reachability of our * dir_port. */ static int directory_conn_is_self_reachability_test(dir_connection_t *conn) { if (conn->requested_resource && !strcmpstart(conn->requested_resource,"authority")) { const routerinfo_t *me = router_get_my_routerinfo(); if (me && router_digest_is_me(conn->identity_digest) && tor_addr_eq_ipv4h(&conn->base_.addr, me->addr) && /*XXXX prop 118*/ me->dir_port == conn->base_.port) return 1; } return 0; } /** Called when we are unable to complete the client's request to a directory * server due to a network error: Mark the router as down and try again if * possible. */ static void connection_dir_request_failed(dir_connection_t *conn) { if (directory_conn_is_self_reachability_test(conn)) { return; /* this was a test fetch. don't retry. */ } if (!entry_list_is_constrained(get_options())) router_set_status(conn->identity_digest, 0); /* don't try him again */ if (conn->base_.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) { log_info(LD_DIR, "Giving up on directory server at '%s'; retrying", conn->base_.address); connection_dir_download_v2_networkstatus_failed(conn, -1); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from " "directory server at '%s'; retrying", conn->base_.address); if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE) connection_dir_bridge_routerdesc_failed(conn); connection_dir_download_routerdesc_failed(conn); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { if (conn->requested_resource) networkstatus_consensus_download_failed(0, conn->requested_resource); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { log_info(LD_DIR, "Giving up on certificate fetch from directory server " "at '%s'; retrying", conn->base_.address); connection_dir_download_cert_failed(conn, 0); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { log_info(LD_DIR, "Giving up downloading detached signatures from '%s'", conn->base_.address); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { log_info(LD_DIR, "Giving up downloading votes from '%s'", conn->base_.address); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) { log_info(LD_DIR, "Giving up on downloading microdescriptors from " " directory server at '%s'; will retry", conn->base_.address); connection_dir_download_routerdesc_failed(conn); } } /** Called when an attempt to download one or more network status * documents on connection conn failed. Decide whether to * retry the fetch now, later, or never. */ static void connection_dir_download_v2_networkstatus_failed(dir_connection_t *conn, int status_code) { if (!conn->requested_resource) { /* We never reached directory_send_command, which means that we never * opened a network connection. Either we're out of sockets, or the * network is down. Either way, retrying would be pointless. */ return; } if (!strcmpstart(conn->requested_resource, "all")) { /* We're a non-authoritative directory cache; try again. Ignore status * code, since we don't want to keep trying forever in a tight loop * if all the authorities are shutting us out. */ const smartlist_t *trusted_dirs = router_get_trusted_dir_servers(); SMARTLIST_FOREACH(trusted_dirs, dir_server_t *, ds, download_status_failed(&ds->v2_ns_dl_status, 0)); directory_get_from_dirserver(conn->base_.purpose, conn->router_purpose, "all.z", 0 /* don't retry_if_no_servers */); } else if (!strcmpstart(conn->requested_resource, "fp/")) { /* We were trying to download by fingerprint; mark them all as having * failed, and possibly retry them later.*/ smartlist_t *failed = smartlist_new(); dir_split_resource_into_fingerprints(conn->requested_resource+3, failed, NULL, 0); if (smartlist_len(failed)) { dir_networkstatus_download_failed(failed, status_code); SMARTLIST_FOREACH(failed, char *, cp, tor_free(cp)); } smartlist_free(failed); } } /** Helper: Attempt to fetch directly the descriptors of each bridge * listed in failed. */ static void connection_dir_retry_bridges(smartlist_t *descs) { char digest[DIGEST_LEN]; SMARTLIST_FOREACH(descs, const char *, cp, { if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) { log_warn(LD_BUG, "Malformed fingerprint in list: %s", escaped(cp)); continue; } retry_bridge_descriptor_fetch_directly(digest); }); } /** Called when an attempt to download one or more router descriptors * or extra-info documents on connection conn failed. */ static void connection_dir_download_routerdesc_failed(dir_connection_t *conn) { /* No need to increment the failure count for routerdescs, since * it's not their fault. */ /* No need to relaunch descriptor downloads here: we already do it * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */ tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); (void) conn; } /** Called when an attempt to download a bridge's routerdesc from * one of the authorities failed due to a network error. If * possible attempt to download descriptors from the bridge directly. */ static void connection_dir_bridge_routerdesc_failed(dir_connection_t *conn) { smartlist_t *which = NULL; /* Requests for bridge descriptors are in the form 'fp/', so ignore anything else. */ if (!conn->requested_resource || strcmpstart(conn->requested_resource,"fp/")) return; which = smartlist_new(); dir_split_resource_into_fingerprints(conn->requested_resource + strlen("fp/"), which, NULL, 0); tor_assert(conn->base_.purpose != DIR_PURPOSE_FETCH_EXTRAINFO); if (smartlist_len(which)) { connection_dir_retry_bridges(which); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); } smartlist_free(which); } /** Called when an attempt to fetch a certificate fails. */ static void connection_dir_download_cert_failed(dir_connection_t *conn, int status) { const char *fp_pfx = "fp/"; const char *fpsk_pfx = "fp-sk/"; smartlist_t *failed; tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE); if (!conn->requested_resource) return; failed = smartlist_new(); /* * We have two cases download by fingerprint (resource starts * with "fp/") or download by fingerprint/signing key pair * (resource starts with "fp-sk/"). */ if (!strcmpstart(conn->requested_resource, fp_pfx)) { /* Download by fingerprint case */ dir_split_resource_into_fingerprints(conn->requested_resource + strlen(fp_pfx), failed, NULL, DSR_HEX); SMARTLIST_FOREACH_BEGIN(failed, char *, cp) { /* Null signing key digest indicates download by fp only */ authority_cert_dl_failed(cp, NULL, status); tor_free(cp); } SMARTLIST_FOREACH_END(cp); } else if (!strcmpstart(conn->requested_resource, fpsk_pfx)) { /* Download by (fp,sk) pairs */ dir_split_resource_into_fingerprint_pairs(conn->requested_resource + strlen(fpsk_pfx), failed); SMARTLIST_FOREACH_BEGIN(failed, fp_pair_t *, cp) { authority_cert_dl_failed(cp->first, cp->second, status); tor_free(cp); } SMARTLIST_FOREACH_END(cp); } else { log_warn(LD_DIR, "Don't know what to do with failure for cert fetch %s", conn->requested_resource); } smartlist_free(failed); update_certificate_downloads(time(NULL)); } /** Evaluate the situation and decide if we should use an encrypted * "begindir-style" connection for this directory request. * 1) If or_port is 0, or it's a direct conn and or_port is firewalled * or we're a dir mirror, no. * 2) If we prefer to avoid begindir conns, and we're not fetching or * publishing a bridge relay descriptor, no. * 3) Else yes. */ static int directory_command_should_use_begindir(const or_options_t *options, const tor_addr_t *addr, int or_port, uint8_t router_purpose, dir_indirection_t indirection) { if (!or_port) return 0; /* We don't know an ORPort -- no chance. */ if (indirection == DIRIND_DIRECT_CONN || indirection == DIRIND_ANON_DIRPORT) return 0; if (indirection == DIRIND_ONEHOP) if (!fascist_firewall_allows_address_or(addr, or_port) || directory_fetches_from_authorities(options)) return 0; /* We're firewalled or are acting like a relay -- also no. */ if (!options->TunnelDirConns && router_purpose != ROUTER_PURPOSE_BRIDGE) return 0; /* We prefer to avoid using begindir conns. Fine. */ return 1; } /** Helper for directory_initiate_command_routerstatus: send the * command to a server whose address is address, whose IP is * addr, whose directory port is dir_port, whose tor version * supports_begindir, and whose identity key digest is * digest. */ void directory_initiate_command(const char *address, const tor_addr_t *_addr, uint16_t or_port, uint16_t dir_port, const char *digest, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since) { directory_initiate_command_rend(address, _addr, or_port, dir_port, digest, dir_purpose, router_purpose, indirection, resource, payload, payload_len, if_modified_since, NULL); } /** Return non-zero iff a directory connection with purpose * dir_purpose reveals sensitive information about a Tor * instance's client activities. (Such connections must be performed * through normal three-hop Tor circuits.) */ static int is_sensitive_dir_purpose(uint8_t dir_purpose) { return ((dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) || (dir_purpose == DIR_PURPOSE_HAS_FETCHED_RENDDESC) || (dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC) || (dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) || (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC_V2)); } /** Same as directory_initiate_command(), but accepts rendezvous data to * fetch a hidden service descriptor. */ static void directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, uint16_t or_port, uint16_t dir_port, const char *digest, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since, const rend_data_t *rend_query) { dir_connection_t *conn; const or_options_t *options = get_options(); int socket_error = 0; int use_begindir = directory_command_should_use_begindir(options, _addr, or_port, router_purpose, indirection); const int anonymized_connection = dirind_is_anon(indirection); tor_addr_t addr; tor_assert(address); tor_assert(_addr); tor_assert(or_port || dir_port); tor_assert(digest); tor_addr_copy(&addr, _addr); log_debug(LD_DIR, "anonymized %d, use_begindir %d.", anonymized_connection, use_begindir); log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose)); #ifndef NON_ANONYMOUS_MODE_ENABLED tor_assert(!(is_sensitive_dir_purpose(dir_purpose) && !anonymized_connection)); #else (void)is_sensitive_dir_purpose; #endif /* ensure that we don't make direct connections when a SOCKS server is * configured. */ if (!anonymized_connection && !use_begindir && !options->HTTPProxy && (options->Socks4Proxy || options->Socks5Proxy)) { log_warn(LD_DIR, "Cannot connect to a directory server through a " "SOCKS proxy!"); return; } conn = dir_connection_new(tor_addr_family(&addr)); /* set up conn so it's got all the data we need to remember */ tor_addr_copy(&conn->base_.addr, &addr); conn->base_.port = use_begindir ? or_port : dir_port; conn->base_.address = tor_strdup(address); memcpy(conn->identity_digest, digest, DIGEST_LEN); conn->base_.purpose = dir_purpose; conn->router_purpose = router_purpose; /* give it an initial state */ conn->base_.state = DIR_CONN_STATE_CONNECTING; /* decide whether we can learn our IP address from this conn */ /* XXXX This is a bad name for this field now. */ conn->dirconn_direct = !anonymized_connection; /* copy rendezvous data, if any */ if (rend_query) conn->rend_data = rend_data_dup(rend_query); if (!anonymized_connection && !use_begindir) { /* then we want to connect to dirport directly */ if (options->HTTPProxy) { tor_addr_copy(&addr, &options->HTTPProxyAddr); dir_port = options->HTTPProxyPort; } switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr, dir_port, &socket_error)) { case -1: connection_dir_request_failed(conn); /* retry if we want */ /* XXX we only pass 'conn' above, not 'resource', 'payload', * etc. So in many situations it can't retry! -RD */ connection_free(TO_CONN(conn)); return; case 1: /* start flushing conn */ conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* fall through */ case 0: /* queue the command on the outbuf */ directory_send_command(conn, dir_purpose, 1, resource, payload, payload_len, if_modified_since); connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT); /* writable indicates finish, readable indicates broken link, error indicates broken link in windowsland. */ } } else { /* we want to connect via a tor connection */ entry_connection_t *linked_conn; /* Anonymized tunneled connections can never share a circuit. * One-hop directory connections can share circuits with each other * but nothing else. */ int iso_flags = anonymized_connection ? ISO_STREAM : ISO_SESSIONGRP; /* If it's an anonymized connection, remember the fact that we * wanted it for later: maybe we'll want it again soon. */ if (anonymized_connection && use_begindir) rep_hist_note_used_internal(time(NULL), 0, 1); else if (anonymized_connection && !use_begindir) rep_hist_note_used_port(time(NULL), conn->base_.port); /* make an AP connection * populate it and add it at the right state * hook up both sides */ linked_conn = connection_ap_make_link(TO_CONN(conn), conn->base_.address, conn->base_.port, digest, SESSION_GROUP_DIRCONN, iso_flags, use_begindir, conn->dirconn_direct); if (!linked_conn) { log_warn(LD_NET,"Making tunnel to dirserver failed."); connection_mark_for_close(TO_CONN(conn)); return; } if (connection_add(TO_CONN(conn)) < 0) { log_warn(LD_NET,"Unable to add connection for link to dirserver."); connection_mark_for_close(TO_CONN(conn)); return; } conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* queue the command on the outbuf */ directory_send_command(conn, dir_purpose, 0, resource, payload, payload_len, if_modified_since); connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT); IF_HAS_BUFFEREVENT(ENTRY_TO_CONN(linked_conn), { connection_watch_events(ENTRY_TO_CONN(linked_conn), READ_EVENT|WRITE_EVENT); }) ELSE_IF_NO_BUFFEREVENT connection_start_reading(ENTRY_TO_CONN(linked_conn)); } } /** Return true iff anything we say on conn is being encrypted before * we send it to the client/server. */ int connection_dir_is_encrypted(dir_connection_t *conn) { /* Right now it's sufficient to see if conn is or has been linked, since * the only thing it could be linked to is an edge connection on a * circuit, and the only way it could have been unlinked is at the edge * connection getting closed. */ return TO_CONN(conn)->linked; } /** Helper for sorting * * sort strings alphabetically */ static int compare_strs_(const void **a, const void **b) { const char *s1 = *a, *s2 = *b; return strcmp(s1, s2); } #define CONDITIONAL_CONSENSUS_FPR_LEN 3 #if (CONDITIONAL_CONSENSUS_FPR_LEN > DIGEST_LEN) #error "conditional consensus fingerprint length is larger than digest length" #endif /** Return the URL we should use for a consensus download. * * This url depends on whether or not the server we go to * is sufficiently new to support conditional consensus downloading, * i.e. GET .../consensus/fpr+fpr+fpr * * If 'resource' is provided, it is the name of a consensus flavor to request. */ static char * directory_get_consensus_url(const char *resource) { char *url = NULL; const char *hyphen, *flavor; if (resource==NULL || strcmp(resource, "ns")==0) { flavor = ""; /* Request ns consensuses as "", so older servers will work*/ hyphen = ""; } else { flavor = resource; hyphen = "-"; } { char *authority_id_list; smartlist_t *authority_digests = smartlist_new(); SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(), dir_server_t *, ds) { char *hex; if (!(ds->type & V3_DIRINFO)) continue; hex = tor_malloc(2*CONDITIONAL_CONSENSUS_FPR_LEN+1); base16_encode(hex, 2*CONDITIONAL_CONSENSUS_FPR_LEN+1, ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN); smartlist_add(authority_digests, hex); } SMARTLIST_FOREACH_END(ds); smartlist_sort(authority_digests, compare_strs_); authority_id_list = smartlist_join_strings(authority_digests, "+", 0, NULL); tor_asprintf(&url, "/tor/status-vote/current/consensus%s%s/%s.z", hyphen, flavor, authority_id_list); SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp)); smartlist_free(authority_digests); tor_free(authority_id_list); } return url; } /** Queue an appropriate HTTP command on conn-\>outbuf. The other args * are as in directory_initiate_command(). */ static void directory_send_command(dir_connection_t *conn, int purpose, int direct, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since) { char proxystring[256]; char hoststring[128]; smartlist_t *headers = smartlist_new(); char *url; char request[8192]; const char *httpcommand = NULL; tor_assert(conn); tor_assert(conn->base_.type == CONN_TYPE_DIR); tor_free(conn->requested_resource); if (resource) conn->requested_resource = tor_strdup(resource); /* come up with a string for which Host: we want */ if (conn->base_.port == 80) { strlcpy(hoststring, conn->base_.address, sizeof(hoststring)); } else { tor_snprintf(hoststring, sizeof(hoststring),"%s:%d", conn->base_.address, conn->base_.port); } /* Format if-modified-since */ if (if_modified_since) { char b[RFC1123_TIME_LEN+1]; format_rfc1123_time(b, if_modified_since); smartlist_add_asprintf(headers, "If-Modified-Since: %s\r\n", b); } /* come up with some proxy lines, if we're using one. */ if (direct && get_options()->HTTPProxy) { char *base64_authenticator=NULL; const char *authenticator = get_options()->HTTPProxyAuthenticator; tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring); if (authenticator) { base64_authenticator = alloc_http_authenticator(authenticator); if (!base64_authenticator) log_warn(LD_BUG, "Encoding http authenticator failed"); } if (base64_authenticator) { smartlist_add_asprintf(headers, "Proxy-Authorization: Basic %s\r\n", base64_authenticator); tor_free(base64_authenticator); } } else { proxystring[0] = 0; } switch (purpose) { case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS: tor_assert(resource); httpcommand = "GET"; tor_asprintf(&url, "/tor/status/%s", resource); break; case DIR_PURPOSE_FETCH_CONSENSUS: /* resource is optional. If present, it's a flavor name */ tor_assert(!payload); httpcommand = "GET"; url = directory_get_consensus_url(resource); log_info(LD_DIR, "Downloading consensus from %s using %s", hoststring, url); break; case DIR_PURPOSE_FETCH_CERTIFICATE: tor_assert(resource); tor_assert(!payload); httpcommand = "GET"; tor_asprintf(&url, "/tor/keys/%s", resource); break; case DIR_PURPOSE_FETCH_STATUS_VOTE: tor_assert(resource); tor_assert(!payload); httpcommand = "GET"; tor_asprintf(&url, "/tor/status-vote/next/%s.z", resource); break; case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: tor_assert(!resource); tor_assert(!payload); httpcommand = "GET"; url = tor_strdup("/tor/status-vote/next/consensus-signatures.z"); break; case DIR_PURPOSE_FETCH_SERVERDESC: tor_assert(resource); httpcommand = "GET"; tor_asprintf(&url, "/tor/server/%s", resource); break; case DIR_PURPOSE_FETCH_EXTRAINFO: tor_assert(resource); httpcommand = "GET"; tor_asprintf(&url, "/tor/extra/%s", resource); break; case DIR_PURPOSE_FETCH_MICRODESC: tor_assert(resource); httpcommand = "GET"; tor_asprintf(&url, "/tor/micro/%s", resource); break; case DIR_PURPOSE_UPLOAD_DIR: { const char *why = router_get_descriptor_gen_reason(); tor_assert(!resource); tor_assert(payload); httpcommand = "POST"; url = tor_strdup("/tor/"); if (why) { smartlist_add_asprintf(headers, "X-Desc-Gen-Reason: %s\r\n", why); } break; } case DIR_PURPOSE_UPLOAD_VOTE: tor_assert(!resource); tor_assert(payload); httpcommand = "POST"; url = tor_strdup("/tor/post/vote"); break; case DIR_PURPOSE_UPLOAD_SIGNATURES: tor_assert(!resource); tor_assert(payload); httpcommand = "POST"; url = tor_strdup("/tor/post/consensus-signature"); break; case DIR_PURPOSE_FETCH_RENDDESC_V2: tor_assert(resource); tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32); tor_assert(!payload); httpcommand = "GET"; tor_asprintf(&url, "/tor/rendezvous2/%s", resource); break; case DIR_PURPOSE_UPLOAD_RENDDESC: tor_assert(!resource); tor_assert(payload); httpcommand = "POST"; url = tor_strdup("/tor/rendezvous/publish"); break; case DIR_PURPOSE_UPLOAD_RENDDESC_V2: tor_assert(!resource); tor_assert(payload); httpcommand = "POST"; url = tor_strdup("/tor/rendezvous2/publish"); break; default: tor_assert(0); return; } if (strlen(proxystring) + strlen(url) >= 4096) { log_warn(LD_BUG, "Squid does not like URLs longer than 4095 bytes, and this " "one is %d bytes long: %s%s", (int)(strlen(proxystring) + strlen(url)), proxystring, url); } tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring); connection_write_to_buf(request, strlen(request), TO_CONN(conn)); connection_write_to_buf(url, strlen(url), TO_CONN(conn)); tor_free(url); if (!strcmp(httpcommand, "POST") || payload) { smartlist_add_asprintf(headers, "Content-Length: %lu\r\n", payload ? (unsigned long)payload_len : 0); } { char *header = smartlist_join_strings(headers, "", 0, NULL); tor_snprintf(request, sizeof(request), " HTTP/1.0\r\nHost: %s\r\n%s\r\n", hoststring, header); tor_free(header); } connection_write_to_buf(request, strlen(request), TO_CONN(conn)); if (payload) { /* then send the payload afterwards too */ connection_write_to_buf(payload, payload_len, TO_CONN(conn)); } SMARTLIST_FOREACH(headers, char *, h, tor_free(h)); smartlist_free(headers); } /** Parse an HTTP request string headers of the form * \verbatim * "\%s [http[s]://]\%s HTTP/1..." * \endverbatim * If it's well-formed, strdup the second \%s into *url, and * nul-terminate it. If the url doesn't start with "/tor/", rewrite it * so it does. Return 0. * Otherwise, return -1. */ static int parse_http_url(const char *headers, char **url) { char *s, *start, *tmp; s = (char *)eat_whitespace_no_nl(headers); if (!*s) return -1; s = (char *)find_whitespace(s); /* get past GET/POST */ if (!*s) return -1; s = (char *)eat_whitespace_no_nl(s); if (!*s) return -1; start = s; /* this is it, assuming it's valid */ s = (char *)find_whitespace(start); if (!*s) return -1; /* tolerate the http[s] proxy style of putting the hostname in the url */ if (s-start >= 4 && !strcmpstart(start,"http")) { tmp = start + 4; if (*tmp == 's') tmp++; if (s-tmp >= 3 && !strcmpstart(tmp,"://")) { tmp = strchr(tmp+3, '/'); if (tmp && tmp < s) { log_debug(LD_DIR,"Skipping over 'http[s]://hostname/' string"); start = tmp; } } } if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */ *url = tor_malloc(s - start + 5); strlcpy(*url,"/tor", s-start+5); strlcat((*url)+4, start, s-start+1); } else { *url = tor_strndup(start, s-start); } return 0; } /** Return a copy of the first HTTP header in headers whose key is * which. The key should be given with a terminating colon and space; * this function copies everything after, up to but not including the * following \\r\\n. */ static char * http_get_header(const char *headers, const char *which) { const char *cp = headers; while (cp) { if (!strcasecmpstart(cp, which)) { char *eos; cp += strlen(which); if ((eos = strchr(cp,'\r'))) return tor_strndup(cp, eos-cp); else return tor_strdup(cp); } cp = strchr(cp, '\n'); if (cp) ++cp; } return NULL; } /** If headers indicates that a proxy was involved, then rewrite * conn-\>address to describe our best guess of the address that * originated this HTTP request. */ static void http_set_address_origin(const char *headers, connection_t *conn) { char *fwd; fwd = http_get_header(headers, "Forwarded-For: "); if (!fwd) fwd = http_get_header(headers, "X-Forwarded-For: "); if (fwd) { struct in_addr in; if (!tor_inet_aton(fwd, &in) || is_internal_IP(ntohl(in.s_addr), 0)) { log_debug(LD_DIR, "Ignoring unrecognized or internal IP %s", escaped(fwd)); tor_free(fwd); return; } tor_free(conn->address); conn->address = tor_strdup(fwd); tor_free(fwd); } } /** Parse an HTTP response string headers of the form * \verbatim * "HTTP/1.\%d \%d\%s\r\n...". * \endverbatim * * If it's well-formed, assign the status code to *code and * return 0. Otherwise, return -1. * * On success: If date is provided, set *date to the Date * header in the http headers, or 0 if no such header is found. If * compression is provided, set *compression to the * compression method given in the Content-Encoding header, or 0 if no * such header is found, or -1 if the value of the header is not * recognized. If reason is provided, strdup the reason string * into it. */ int parse_http_response(const char *headers, int *code, time_t *date, compress_method_t *compression, char **reason) { unsigned n1, n2; char datestr[RFC1123_TIME_LEN+1]; smartlist_t *parsed_headers; tor_assert(headers); tor_assert(code); while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */ if (tor_sscanf(headers, "HTTP/1.%u %u", &n1, &n2) < 2 || (n1 != 0 && n1 != 1) || (n2 < 100 || n2 >= 600)) { log_warn(LD_HTTP,"Failed to parse header %s",escaped(headers)); return -1; } *code = n2; parsed_headers = smartlist_new(); smartlist_split_string(parsed_headers, headers, "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); if (reason) { smartlist_t *status_line_elements = smartlist_new(); tor_assert(smartlist_len(parsed_headers)); smartlist_split_string(status_line_elements, smartlist_get(parsed_headers, 0), " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3); tor_assert(smartlist_len(status_line_elements) <= 3); if (smartlist_len(status_line_elements) == 3) { *reason = smartlist_get(status_line_elements, 2); smartlist_set(status_line_elements, 2, NULL); /* Prevent free */ } SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp)); smartlist_free(status_line_elements); } if (date) { *date = 0; SMARTLIST_FOREACH(parsed_headers, const char *, s, if (!strcmpstart(s, "Date: ")) { strlcpy(datestr, s+6, sizeof(datestr)); /* This will do nothing on failure, so we don't need to check the result. We shouldn't warn, since there are many other valid date formats besides the one we use. */ parse_rfc1123_time(datestr, date); break; }); } if (compression) { const char *enc = NULL; SMARTLIST_FOREACH(parsed_headers, const char *, s, if (!strcmpstart(s, "Content-Encoding: ")) { enc = s+18; break; }); if (!enc || !strcmp(enc, "identity")) { *compression = NO_METHOD; } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) { *compression = ZLIB_METHOD; } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) { *compression = GZIP_METHOD; } else { log_info(LD_HTTP, "Unrecognized content encoding: %s. Trying to deal.", escaped(enc)); *compression = UNKNOWN_METHOD; } } SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s)); smartlist_free(parsed_headers); return 0; } /** Return true iff body doesn't start with a plausible router or * running-list or directory opening. This is a sign of possible compression. **/ static int body_is_plausible(const char *body, size_t len, int purpose) { int i; if (len == 0) return 1; /* empty bodies don't need decompression */ if (len < 32) return 0; if (purpose == DIR_PURPOSE_FETCH_MICRODESC) { return (!strcmpstart(body,"onion-key")); } if (purpose != DIR_PURPOSE_FETCH_RENDDESC) { if (!strcmpstart(body,"router") || !strcmpstart(body,"signed-directory") || !strcmpstart(body,"network-status") || !strcmpstart(body,"running-routers")) return 1; for (i=0;i<32;++i) { if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i])) return 0; } return 1; } else { return 1; } } /** Called when we've just fetched a bunch of router descriptors in * body. The list which, if present, holds digests for * descriptors we requested: descriptor digests if descriptor_digests * is true, or identity digests otherwise. Parse the descriptors, validate * them, and annotate them as having purpose purpose and as having been * downloaded from source. * * Return the number of routers actually added. */ static int load_downloaded_routers(const char *body, smartlist_t *which, int descriptor_digests, int router_purpose, const char *source) { char buf[256]; char time_buf[ISO_TIME_LEN+1]; int added = 0; int general = router_purpose == ROUTER_PURPOSE_GENERAL; format_iso_time(time_buf, time(NULL)); tor_assert(source); if (tor_snprintf(buf, sizeof(buf), "@downloaded-at %s\n" "@source %s\n" "%s%s%s", time_buf, escaped(source), !general ? "@purpose " : "", !general ? router_purpose_to_string(router_purpose) : "", !general ? "\n" : "")<0) return added; added = router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which, descriptor_digests, buf); control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, count_loading_descriptors_progress()); return added; } /** We are a client, and we've finished reading the server's * response. Parse it and act appropriately. * * If we're still happy with using this directory server in the future, return * 0. Otherwise return -1; and the caller should consider trying the request * again. * * The caller will take care of marking the connection for close. */ static int connection_dir_client_reached_eof(dir_connection_t *conn) { char *body; char *headers; char *reason = NULL; size_t body_len=0, orig_len=0; int status_code; time_t date_header=0; long delta; compress_method_t compression; int plausible; int skewed=0; int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); int was_compressed=0; time_t now = time(NULL); int src_code; switch (connection_fetch_from_buf_http(TO_CONN(conn), &headers, MAX_HEADERS_SIZE, &body, &body_len, MAX_DIR_DL_SIZE, allow_partial)) { case -1: /* overflow */ log_warn(LD_PROTOCOL, "'fetch' response too large (server '%s:%d'). Closing.", conn->base_.address, conn->base_.port); return -1; case 0: log_info(LD_HTTP, "'fetch' response not all here, but we're at eof. Closing."); return -1; /* case 1, fall through */ } orig_len = body_len; if (parse_http_response(headers, &status_code, &date_header, &compression, &reason) < 0) { log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.", conn->base_.address, conn->base_.port); tor_free(body); tor_free(headers); return -1; } if (!reason) reason = tor_strdup("[no reason given]"); log_debug(LD_DIR, "Received response from directory server '%s:%d': %d %s " "(purpose: %d)", conn->base_.address, conn->base_.port, status_code, escaped(reason), conn->base_.purpose); /* now check if it's got any hints for us about our IP address. */ if (conn->dirconn_direct) { char *guess = http_get_header(headers, X_ADDRESS_HEADER); if (guess) { router_new_address_suggestion(guess, conn); tor_free(guess); } } if (date_header > 0) { /* The date header was written very soon after we sent our request, * so compute the skew as the difference between sending the request * and the date header. (We used to check now-date_header, but that's * inaccurate if we spend a lot of time downloading.) */ delta = conn->base_.timestamp_lastwritten - date_header; if (labs(delta)>ALLOW_DIRECTORY_TIME_SKEW) { char dbuf[64]; int trusted = router_digest_is_trusted_dir(conn->identity_digest); format_time_interval(dbuf, sizeof(dbuf), delta); log_fn(trusted ? LOG_WARN : LOG_INFO, LD_HTTP, "Received directory with skewed time (server '%s:%d'): " "It seems that our clock is %s by %s, or that theirs is %s. " "Tor requires an accurate clock to work: please check your time, " "timezone, and date settings.", conn->base_.address, conn->base_.port, delta>0 ? "ahead" : "behind", dbuf, delta>0 ? "behind" : "ahead"); skewed = 1; /* don't check the recommended-versions line */ if (trusted) control_event_general_status(LOG_WARN, "CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d", delta, conn->base_.address, conn->base_.port); } else { log_debug(LD_HTTP, "Time on received directory is within tolerance; " "we are %ld seconds skewed. (That's okay.)", delta); } } (void) skewed; /* skewed isn't used yet. */ if (status_code == 503) { routerstatus_t *rs; dir_server_t *ds; const char *id_digest = conn->identity_digest; log_info(LD_DIR,"Received http status code %d (%s) from server " "'%s:%d'. I'll try again soon.", status_code, escaped(reason), conn->base_.address, conn->base_.port); if ((rs = router_get_mutable_consensus_status_by_id(id_digest))) rs->last_dir_503_at = now; if ((ds = router_get_fallback_dirserver_by_digest(id_digest))) ds->fake_status.last_dir_503_at = now; tor_free(body); tor_free(headers); tor_free(reason); return -1; } plausible = body_is_plausible(body, body_len, conn->base_.purpose); if (compression != NO_METHOD || !plausible) { char *new_body = NULL; size_t new_len = 0; compress_method_t guessed = detect_compression_method(body, body_len); if (compression == UNKNOWN_METHOD || guessed != compression) { /* Tell the user if we don't believe what we're told about compression.*/ const char *description1, *description2; if (compression == ZLIB_METHOD) description1 = "as deflated"; else if (compression == GZIP_METHOD) description1 = "as gzipped"; else if (compression == NO_METHOD) description1 = "as uncompressed"; else description1 = "with an unknown Content-Encoding"; if (guessed == ZLIB_METHOD) description2 = "deflated"; else if (guessed == GZIP_METHOD) description2 = "gzipped"; else if (!plausible) description2 = "confusing binary junk"; else description2 = "uncompressed"; log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, " "but it seems to be %s.%s", conn->base_.address, conn->base_.port, description1, description2, (compression>0 && guessed>0)?" Trying both.":""); } /* Try declared compression first if we can. */ if (compression == GZIP_METHOD || compression == ZLIB_METHOD) tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression, !allow_partial, LOG_PROTOCOL_WARN); /* Okay, if that didn't work, and we think that it was compressed * differently, try that. */ if (!new_body && (guessed == GZIP_METHOD || guessed == ZLIB_METHOD) && compression != guessed) tor_gzip_uncompress(&new_body, &new_len, body, body_len, guessed, !allow_partial, LOG_PROTOCOL_WARN); /* If we're pretty sure that we have a compressed directory, and * we didn't manage to uncompress it, then warn and bail. */ if (!plausible && !new_body) { log_fn(LOG_PROTOCOL_WARN, LD_HTTP, "Unable to decompress HTTP body (server '%s:%d').", conn->base_.address, conn->base_.port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } if (new_body) { tor_free(body); body = new_body; body_len = new_len; was_compressed = 1; } } if (conn->base_.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) { smartlist_t *which = NULL; v2_networkstatus_source_t source; char *cp; log_info(LD_DIR,"Received networkstatus objects (size %d) from server " "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); if (status_code != 200) { static ratelim_t warning_limit = RATELIM_INIT(3600); char *m; if ((m = rate_limit_log(&warning_limit, now))) { log_warn(LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching \"/tor/status/%s\". " "I'll try again soon.%s", status_code, escaped(reason), conn->base_.address, conn->base_.port, conn->requested_resource, m); tor_free(m); } tor_free(body); tor_free(headers); tor_free(reason); connection_dir_download_v2_networkstatus_failed(conn, status_code); return -1; } if (conn->requested_resource && !strcmpstart(conn->requested_resource,"fp/")) { source = NS_FROM_DIR_BY_FP; which = smartlist_new(); dir_split_resource_into_fingerprints(conn->requested_resource+3, which, NULL, 0); } else if (conn->requested_resource && !strcmpstart(conn->requested_resource, "all")) { source = NS_FROM_DIR_ALL; which = smartlist_new(); SMARTLIST_FOREACH(router_get_trusted_dir_servers(), dir_server_t *, ds, { char *hex = tor_malloc(HEX_DIGEST_LEN+1); base16_encode(hex, HEX_DIGEST_LEN+1, ds->digest, DIGEST_LEN); smartlist_add(which, hex); }); } else { /* XXXX Can we even end up here? -- weasel*/ source = NS_FROM_DIR_BY_FP; log_warn(LD_BUG, "We received a networkstatus but we didn't ask " "for it by fp, nor did we ask for all."); } cp = body; while (*cp) { char *next = strstr(cp, "\nnetwork-status-version"); if (next) next[1] = '\0'; /* learn from it, and then remove it from 'which' */ if (router_set_networkstatus_v2(cp, now, source, which)<0) break; if (next) { next[1] = 'n'; cp = next+1; } else break; } /* launches router downloads as needed */ routers_update_all_from_networkstatus(now, 2); directory_info_has_arrived(now, 0); if (which) { if (smartlist_len(which)) { dir_networkstatus_download_failed(which, status_code); } SMARTLIST_FOREACH(which, char *, s, tor_free(s)); smartlist_free(which); } } if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { int r; const char *flavname = conn->requested_resource; if (status_code != 200) { int severity = (status_code == 304) ? LOG_INFO : LOG_WARN; tor_log(severity, LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching consensus directory.", status_code, escaped(reason), conn->base_.address, conn->base_.port); tor_free(body); tor_free(headers); tor_free(reason); networkstatus_consensus_download_failed(status_code, flavname); return -1; } log_info(LD_DIR,"Received consensus directory (size %d) from server " "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); if ((r=networkstatus_set_current_consensus(body, flavname, 0))<0) { log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR, "Unable to load %s consensus directory downloaded from " "server '%s:%d'. I'll try again soon.", flavname, conn->base_.address, conn->base_.port); tor_free(body); tor_free(headers); tor_free(reason); networkstatus_consensus_download_failed(0, flavname); return -1; } /* launches router downloads as needed */ routers_update_all_from_networkstatus(now, 3); update_microdescs_from_networkstatus(now); update_microdesc_downloads(now); directory_info_has_arrived(now, 0); log_info(LD_DIR, "Successfully loaded consensus."); } if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching \"/tor/keys/%s\".", status_code, escaped(reason), conn->base_.address, conn->base_.port, conn->requested_resource); connection_dir_download_cert_failed(conn, status_code); tor_free(body); tor_free(headers); tor_free(reason); return -1; } log_info(LD_DIR,"Received authority certificates (size %d) from server " "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); /* * Tell trusted_dirs_load_certs_from_string() whether it was by fp * or fp-sk pair. */ src_code = -1; if (!strcmpstart(conn->requested_resource, "fp/")) { src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST; } else if (!strcmpstart(conn->requested_resource, "fp-sk/")) { src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST; } if (src_code != -1) { if (trusted_dirs_load_certs_from_string(body, src_code, 1)<0) { log_warn(LD_DIR, "Unable to parse fetched certificates"); /* if we fetched more than one and only some failed, the successful * ones got flushed to disk so it's safe to call this on them */ connection_dir_download_cert_failed(conn, status_code); } else { directory_info_has_arrived(now, 0); log_info(LD_DIR, "Successfully loaded certificates from fetch."); } } else { log_warn(LD_DIR, "Couldn't figure out what to do with fetched certificates for " "unknown resource %s", conn->requested_resource); connection_dir_download_cert_failed(conn, status_code); } } if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { const char *msg; int st; log_info(LD_DIR,"Got votes (size %d) from server %s:%d", (int)body_len, conn->base_.address, conn->base_.port); if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server " "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".", status_code, escaped(reason), conn->base_.address, conn->base_.port, conn->requested_resource); tor_free(body); tor_free(headers); tor_free(reason); return -1; } dirvote_add_vote(body, &msg, &st); if (st > 299) { log_warn(LD_DIR, "Error adding retrieved vote: %s", msg); } else { log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg); } } if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { const char *msg = NULL; log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d", (int)body_len, conn->base_.address, conn->base_.port); if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server '%s:%d' while fetching " "\"/tor/status-vote/next/consensus-signatures.z\".", status_code, escaped(reason), conn->base_.address, conn->base_.port); tor_free(body); tor_free(headers); tor_free(reason); return -1; } if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) { log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s", conn->base_.address, conn->base_.port, msg?msg:"???"); } } if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { int was_ei = conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO; smartlist_t *which = NULL; int n_asked_for = 0; int descriptor_digests = conn->requested_resource && !strcmpstart(conn->requested_resource,"d/"); log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'", was_ei ? "extra server info" : "server info", (int)body_len, conn->base_.address, conn->base_.port); if (conn->requested_resource && (!strcmpstart(conn->requested_resource,"d/") || !strcmpstart(conn->requested_resource,"fp/"))) { which = smartlist_new(); dir_split_resource_into_fingerprints(conn->requested_resource + (descriptor_digests ? 2 : 3), which, NULL, 0); n_asked_for = smartlist_len(which); } if (status_code != 200) { int dir_okay = status_code == 404 || (status_code == 400 && !strcmp(reason, "Servers unavailable.")); /* 404 means that it didn't have them; no big deal. * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */ log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR, "Received http status code %d (%s) from server '%s:%d' " "while fetching \"/tor/server/%s\". I'll try again soon.", status_code, escaped(reason), conn->base_.address, conn->base_.port, conn->requested_resource); if (!which) { connection_dir_download_routerdesc_failed(conn); } else { dir_routerdesc_download_failed(which, status_code, conn->router_purpose, was_ei, descriptor_digests); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); } tor_free(body); tor_free(headers); tor_free(reason); return dir_okay ? 0 : -1; } /* Learn the routers, assuming we requested by fingerprint or "all" * or "authority". * * We use "authority" to fetch our own descriptor for * testing, and to fetch bridge descriptors for bootstrapping. Ignore * the output of "authority" requests unless we are using bridges, * since otherwise they'll be the response from reachability tests, * and we don't really want to add that to our routerlist. */ if (which || (conn->requested_resource && (!strcmpstart(conn->requested_resource, "all") || (!strcmpstart(conn->requested_resource, "authority") && get_options()->UseBridges)))) { /* as we learn from them, we remove them from 'which' */ if (was_ei) { router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which, descriptor_digests); } else { //router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which, // descriptor_digests, conn->router_purpose); if (load_downloaded_routers(body, which, descriptor_digests, conn->router_purpose, conn->base_.address)) directory_info_has_arrived(now, 0); } } if (which) { /* mark remaining ones as failed */ log_info(LD_DIR, "Received %d/%d %s requested from %s:%d", n_asked_for-smartlist_len(which), n_asked_for, was_ei ? "extra-info documents" : "router descriptors", conn->base_.address, (int)conn->base_.port); if (smartlist_len(which)) { dir_routerdesc_download_failed(which, status_code, conn->router_purpose, was_ei, descriptor_digests); } SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); } if (directory_conn_is_self_reachability_test(conn)) router_dirport_found_reachable(); } if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) { smartlist_t *which = NULL; log_info(LD_DIR,"Received answer to microdescriptor request (status %d, " "size %d) from server '%s:%d'", status_code, (int)body_len, conn->base_.address, conn->base_.port); tor_assert(conn->requested_resource && !strcmpstart(conn->requested_resource, "d/")); which = smartlist_new(); dir_split_resource_into_fingerprints(conn->requested_resource+2, which, NULL, DSR_DIGEST256|DSR_BASE64); if (status_code != 200) { log_info(LD_DIR, "Received status code %d (%s) from server " "'%s:%d' while fetching \"/tor/micro/%s\". I'll try again " "soon.", status_code, escaped(reason), conn->base_.address, (int)conn->base_.port, conn->requested_resource); dir_microdesc_download_failed(which, status_code); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); tor_free(body); tor_free(headers); tor_free(reason); return 0; } else { smartlist_t *mds; mds = microdescs_add_to_cache(get_microdesc_cache(), body, body+body_len, SAVED_NOWHERE, 0, now, which); if (smartlist_len(which)) { /* Mark remaining ones as failed. */ dir_microdesc_download_failed(which, status_code); } control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, count_loading_descriptors_progress()); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); smartlist_free(mds); } } if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_DIR) { switch (status_code) { case 200: { dir_server_t *ds = router_get_trusteddirserver_by_digest(conn->identity_digest); char *rejected_hdr = http_get_header(headers, "X-Descriptor-Not-New: "); if (rejected_hdr) { if (!strcmp(rejected_hdr, "Yes")) { log_info(LD_GENERAL, "Authority '%s' declined our descriptor (not new)", ds->nickname); /* XXXX use this information; be sure to upload next one * sooner. -NM */ /* XXXX023 On further thought, the task above implies that we're * basing our regenerate-descriptor time on when we uploaded the * last descriptor, not on the published time of the last * descriptor. If those are different, that's a bad thing to * do. -NM */ } tor_free(rejected_hdr); } log_info(LD_GENERAL,"eof (status 200) after uploading server " "descriptor: finished."); control_event_server_status( LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d", conn->base_.address, conn->base_.port); ds->has_accepted_serverdesc = 1; if (directories_have_accepted_server_descriptor()) control_event_server_status(LOG_NOTICE, "GOOD_SERVER_DESCRIPTOR"); } break; case 400: log_warn(LD_GENERAL,"http status 400 (%s) response from " "dirserver '%s:%d'. Please correct.", escaped(reason), conn->base_.address, conn->base_.port); control_event_server_status(LOG_WARN, "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"", conn->base_.address, conn->base_.port, escaped(reason)); break; default: log_warn(LD_GENERAL, "http status %d (%s) reason unexpected while uploading " "descriptor to server '%s:%d').", status_code, escaped(reason), conn->base_.address, conn->base_.port); break; } /* return 0 in all cases, since we don't want to mark any * dirservers down just because they don't like us. */ } if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE) { switch (status_code) { case 200: { log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d", conn->base_.address, conn->base_.port); } break; case 400: log_warn(LD_DIR,"http status 400 (%s) response after uploading " "vote to dirserver '%s:%d'. Please correct.", escaped(reason), conn->base_.address, conn->base_.port); break; default: log_warn(LD_GENERAL, "http status %d (%s) reason unexpected while uploading " "vote to server '%s:%d').", status_code, escaped(reason), conn->base_.address, conn->base_.port); break; } /* return 0 in all cases, since we don't want to mark any * dirservers down just because they don't like us. */ } if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) { switch (status_code) { case 200: { log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d", conn->base_.address, conn->base_.port); } break; case 400: log_warn(LD_DIR,"http status 400 (%s) response after uploading " "signatures to dirserver '%s:%d'. Please correct.", escaped(reason), conn->base_.address, conn->base_.port); break; default: log_warn(LD_GENERAL, "http status %d (%s) reason unexpected while uploading " "signatures to server '%s:%d').", status_code, escaped(reason), conn->base_.address, conn->base_.port); break; } /* return 0 in all cases, since we don't want to mark any * dirservers down just because they don't like us. */ } if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC) { tor_assert(conn->rend_data); log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " "(%s))", (int)body_len, status_code, escaped(reason)); switch (status_code) { case 200: if (rend_cache_store(body, body_len, 0, conn->rend_data->onion_address) < -1) { log_warn(LD_REND,"Failed to parse rendezvous descriptor."); /* Any pending rendezvous attempts will notice when * connection_about_to_close_connection() * cleans this dir conn up. */ /* We could retry. But since v0 descriptors are going out of * style, it isn't worth the hassle. We'll do better in v2. */ } else { /* Success, or at least there's a v2 descriptor already * present. Notify pending connections about this. */ conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; rend_client_desc_trynow(conn->rend_data->onion_address); } break; case 404: /* Not there. Pending connections will be notified when * connection_about_to_close_connection() cleans this conn up. */ break; case 400: log_warn(LD_REND, "http status 400 (%s). Dirserver didn't like our " "rendezvous query?", escaped(reason)); break; default: log_warn(LD_REND,"http status %d (%s) response unexpected while " "fetching hidden service descriptor (server '%s:%d').", status_code, escaped(reason), conn->base_.address, conn->base_.port); break; } } if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) { tor_assert(conn->rend_data); log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " "(%s))", (int)body_len, status_code, escaped(reason)); switch (status_code) { case 200: switch (rend_cache_store_v2_desc_as_client(body, conn->rend_data)) { case -2: log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. " "Retrying at another directory."); /* We'll retry when connection_about_to_close_connection() * cleans this dir conn up. */ break; case -1: /* We already have a v0 descriptor here. Ignoring this one * and _not_ performing another request. */ log_info(LD_REND, "Successfully fetched v2 rendezvous " "descriptor, but we already have a v0 descriptor."); conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; break; default: /* success. notify pending connections about this. */ log_info(LD_REND, "Successfully fetched v2 rendezvous " "descriptor."); conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; rend_client_desc_trynow(conn->rend_data->onion_address); break; } break; case 404: /* Not there. We'll retry when * connection_about_to_close_connection() cleans this conn up. */ log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: " "Retrying at another directory."); break; case 400: log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " "http status 400 (%s). Dirserver didn't like our " "v2 rendezvous query? Retrying at another directory.", escaped(reason)); break; default: log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " "http status %d (%s) response unexpected while " "fetching v2 hidden service descriptor (server '%s:%d'). " "Retrying at another directory.", status_code, escaped(reason), conn->base_.address, conn->base_.port); break; } } if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC || conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) { log_info(LD_REND,"Uploaded rendezvous descriptor (status %d " "(%s))", status_code, escaped(reason)); switch (status_code) { case 200: log_info(LD_REND, "Uploading rendezvous descriptor: finished with status " "200 (%s)", escaped(reason)); break; case 400: log_warn(LD_REND,"http status 400 (%s) response from dirserver " "'%s:%d'. Malformed rendezvous descriptor?", escaped(reason), conn->base_.address, conn->base_.port); break; default: log_warn(LD_REND,"http status %d (%s) response unexpected (server " "'%s:%d').", status_code, escaped(reason), conn->base_.address, conn->base_.port); break; } } note_client_request(conn->base_.purpose, was_compressed, orig_len); tor_free(body); tor_free(headers); tor_free(reason); return 0; } /** Called when a directory connection reaches EOF. */ int connection_dir_reached_eof(dir_connection_t *conn) { int retval; if (conn->base_.state != DIR_CONN_STATE_CLIENT_READING) { log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.", conn->base_.state); connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */ connection_mark_for_close(TO_CONN(conn)); return -1; } retval = connection_dir_client_reached_eof(conn); if (retval == 0) /* success */ conn->base_.state = DIR_CONN_STATE_CLIENT_FINISHED; connection_mark_for_close(TO_CONN(conn)); return retval; } /** If any directory object is arriving, and it's over 10MB large, we're * getting DoS'd. (As of 0.1.2.x, raw directories are about 1MB, and we never * ask for more than 96 router descriptors at a time.) */ #define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20)) /** Read handler for directory connections. (That's connections to * directory servers and connections at directory servers.) */ int connection_dir_process_inbuf(dir_connection_t *conn) { tor_assert(conn); tor_assert(conn->base_.type == CONN_TYPE_DIR); /* Directory clients write, then read data until they receive EOF; * directory servers read data until they get an HTTP command, then * write their response (when it's finished flushing, they mark for * close). */ /* If we're on the dirserver side, look for a command. */ if (conn->base_.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) { if (directory_handle_command(conn) < 0) { connection_mark_for_close(TO_CONN(conn)); return -1; } return 0; } if (connection_get_inbuf_len(TO_CONN(conn)) > MAX_DIRECTORY_OBJECT_SIZE) { log_warn(LD_HTTP, "Too much data received from directory connection: " "denial of service attempt, or you need to upgrade?"); connection_mark_for_close(TO_CONN(conn)); return -1; } if (!conn->base_.inbuf_reached_eof) log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf."); return 0; } /** Called when we're about to finally unlink and free a directory connection: * perform necessary accounting and cleanup */ void connection_dir_about_to_close(dir_connection_t *dir_conn) { connection_t *conn = TO_CONN(dir_conn); if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) { /* It's a directory connection and connecting or fetching * failed: forget about this router, and maybe try again. */ connection_dir_request_failed(dir_conn); } /* If we were trying to fetch a v2 rend desc and did not succeed, * retry as needed. (If a fetch is successful, the connection state * is changed to DIR_PURPOSE_HAS_FETCHED_RENDDESC to mark that * refetching is unnecessary.) */ if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 && dir_conn->rend_data && strlen(dir_conn->rend_data->onion_address) == REND_SERVICE_ID_LEN_BASE32) rend_client_refetch_v2_renddesc(dir_conn->rend_data); } /** Create an http response for the client conn out of * status and reason_phrase. Write it to conn. */ static void write_http_status_line(dir_connection_t *conn, int status, const char *reason_phrase) { char buf[256]; if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n\r\n", status, reason_phrase ? reason_phrase : "OK") < 0) { log_warn(LD_BUG,"status line too long."); return; } connection_write_to_buf(buf, strlen(buf), TO_CONN(conn)); } /** Write the header for an HTTP/1.0 response onto conn-\>outbuf, * with type as the Content-Type. * * If length is nonnegative, it is the Content-Length. * If encoding is provided, it is the Content-Encoding. * If cache_lifetime is greater than 0, the content may be cached for * up to cache_lifetime seconds. Otherwise, the content may not be cached. */ static void write_http_response_header_impl(dir_connection_t *conn, ssize_t length, const char *type, const char *encoding, const char *extra_headers, long cache_lifetime) { char date[RFC1123_TIME_LEN+1]; char tmp[1024]; char *cp; time_t now = time(NULL); tor_assert(conn); format_rfc1123_time(date, now); cp = tmp; tor_snprintf(cp, sizeof(tmp), "HTTP/1.0 200 OK\r\nDate: %s\r\n", date); cp += strlen(tmp); if (type) { tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type); cp += strlen(cp); } if (!is_local_addr(&conn->base_.addr)) { /* Don't report the source address for a nearby/private connection. * Otherwise we tend to mis-report in cases where incoming ports are * being forwarded to a Tor server running behind the firewall. */ tor_snprintf(cp, sizeof(tmp)-(cp-tmp), X_ADDRESS_HEADER "%s\r\n", conn->base_.address); cp += strlen(cp); } if (encoding) { tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Encoding: %s\r\n", encoding); cp += strlen(cp); } if (length >= 0) { tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Length: %ld\r\n", (long)length); cp += strlen(cp); } if (cache_lifetime > 0) { char expbuf[RFC1123_TIME_LEN+1]; format_rfc1123_time(expbuf, now + cache_lifetime); /* We could say 'Cache-control: max-age=%d' here if we start doing * http/1.1 */ tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Expires: %s\r\n", expbuf); cp += strlen(cp); } else if (cache_lifetime == 0) { /* We could say 'Cache-control: no-cache' here if we start doing * http/1.1 */ strlcpy(cp, "Pragma: no-cache\r\n", sizeof(tmp)-(cp-tmp)); cp += strlen(cp); } if (extra_headers) { strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp)); cp += strlen(cp); } if (sizeof(tmp)-(cp-tmp) > 3) memcpy(cp, "\r\n", 3); else tor_assert(0); connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn)); } /** As write_http_response_header_impl, but sets encoding and content-typed * based on whether the response will be compressed or not. */ static void write_http_response_header(dir_connection_t *conn, ssize_t length, int compressed, long cache_lifetime) { write_http_response_header_impl(conn, length, compressed?"application/octet-stream":"text/plain", compressed?"deflate":"identity", NULL, cache_lifetime); } #if defined(INSTRUMENT_DOWNLOADS) || defined(RUNNING_DOXYGEN) /* DOCDOC */ typedef struct request_t { uint64_t bytes; /**< How many bytes have we transferred? */ uint64_t count; /**< How many requests have we made? */ } request_t; /** Map used to keep track of how much data we've up/downloaded in what kind * of request. Maps from request type to pointer to request_t. */ static strmap_t *request_map = NULL; /** Record that a client request of purpose was made, and that * bytes bytes of possibly compressed data were sent/received. * Used to keep track of how much we've up/downloaded in what kind of * request. */ static void note_client_request(int purpose, int compressed, size_t bytes) { char *key; const char *kind = NULL; switch (purpose) { case DIR_PURPOSE_FETCH_V2_NETWORKSTATUS: kind = "dl/status"; break; case DIR_PURPOSE_FETCH_CONSENSUS: kind = "dl/consensus"; break; case DIR_PURPOSE_FETCH_CERTIFICATE: kind = "dl/cert"; break; case DIR_PURPOSE_FETCH_STATUS_VOTE: kind = "dl/vote"; break; case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: kind = "dl/detached_sig"; break; case DIR_PURPOSE_FETCH_SERVERDESC: kind = "dl/server"; break; case DIR_PURPOSE_FETCH_EXTRAINFO: kind = "dl/extra"; break; case DIR_PURPOSE_UPLOAD_DIR: kind = "dl/ul-dir"; break; case DIR_PURPOSE_UPLOAD_VOTE: kind = "dl/ul-vote"; break; case DIR_PURPOSE_UPLOAD_SIGNATURES: kind = "dl/ul-sig"; break; case DIR_PURPOSE_FETCH_RENDDESC: kind = "dl/rend"; break; case DIR_PURPOSE_FETCH_RENDDESC_V2: kind = "dl/rend2"; break; case DIR_PURPOSE_UPLOAD_RENDDESC: kind = "dl/ul-rend"; break; case DIR_PURPOSE_UPLOAD_RENDDESC_V2: kind = "dl/ul-rend2"; break; } if (kind) { tor_asprintf(&key, "%s%s", kind, compressed?".z":""); } else { tor_asprintf(&key, "unknown purpose (%d)%s", purpose, compressed?".z":""); } note_request(key, bytes); tor_free(key); } /** Helper: initialize the request map to instrument downloads. */ static void ensure_request_map_initialized(void) { if (!request_map) request_map = strmap_new(); } /** Called when we just transmitted or received bytes worth of data * because of a request of type key (an arbitrary identifier): adds * bytes to the total associated with key. */ void note_request(const char *key, size_t bytes) { request_t *r; ensure_request_map_initialized(); r = strmap_get(request_map, key); if (!r) { r = tor_malloc_zero(sizeof(request_t)); strmap_set(request_map, key, r); } r->bytes += bytes; r->count++; } /** Return a newly allocated string holding a summary of bytes used per * request type. */ char * directory_dump_request_log(void) { smartlist_t *lines; char *result; strmap_iter_t *iter; ensure_request_map_initialized(); lines = smartlist_new(); for (iter = strmap_iter_init(request_map); !strmap_iter_done(iter); iter = strmap_iter_next(request_map, iter)) { const char *key; void *val; request_t *r; strmap_iter_get(iter, &key, &val); r = val; smartlist_add_asprintf(lines, "%s "U64_FORMAT" "U64_FORMAT"\n", key, U64_PRINTF_ARG(r->bytes), U64_PRINTF_ARG(r->count)); } smartlist_sort_strings(lines); result = smartlist_join_strings(lines, "", 0, NULL); SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); smartlist_free(lines); return result; } #else static void note_client_request(int purpose, int compressed, size_t bytes) { (void)purpose; (void)compressed; (void)bytes; } void note_request(const char *key, size_t bytes) { (void)key; (void)bytes; } char * directory_dump_request_log(void) { return tor_strdup("Not supported."); } #endif /** Decide whether a client would accept the consensus we have. * * Clients can say they only want a consensus if it's signed by more * than half the authorities in a list. They pass this list in * the url as "...consensus/fpr+fpr+fpr". * * fpr may be an abbreviated fingerprint, i.e. only a left substring * of the full authority identity digest. (Only strings of even length, * i.e. encodings of full bytes, are handled correctly. In the case * of an odd number of hex digits the last one is silently ignored.) * * Returns 1 if more than half of the requested authorities signed the * consensus, 0 otherwise. */ int client_likes_consensus(networkstatus_t *v, const char *want_url) { smartlist_t *want_authorities = smartlist_new(); int need_at_least; int have = 0; dir_split_resource_into_fingerprints(want_url, want_authorities, NULL, 0); need_at_least = smartlist_len(want_authorities)/2+1; SMARTLIST_FOREACH_BEGIN(want_authorities, const char *, d) { char want_digest[DIGEST_LEN]; size_t want_len = strlen(d)/2; if (want_len > DIGEST_LEN) want_len = DIGEST_LEN; if (base16_decode(want_digest, DIGEST_LEN, d, want_len*2) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Failed to decode requested authority digest %s.", d); continue; }; SMARTLIST_FOREACH_BEGIN(v->voters, networkstatus_voter_info_t *, vi) { if (smartlist_len(vi->sigs) && tor_memeq(vi->identity_digest, want_digest, want_len)) { have++; break; }; } SMARTLIST_FOREACH_END(vi); /* early exit, if we already have enough */ if (have >= need_at_least) break; } SMARTLIST_FOREACH_END(d); SMARTLIST_FOREACH(want_authorities, char *, d, tor_free(d)); smartlist_free(want_authorities); return (have >= need_at_least); } /** Helper function: called when a dirserver gets a complete HTTP GET * request. Look for a request for a directory or for a rendezvous * service descriptor. On finding one, write a response into * conn-\>outbuf. If the request is unrecognized, send a 400. * Always return 0. */ static int directory_handle_command_get(dir_connection_t *conn, const char *headers, const char *req_body, size_t req_body_len) { size_t dlen; char *url, *url_mem, *header; const or_options_t *options = get_options(); time_t if_modified_since = 0; int compressed; size_t url_len; /* We ignore the body of a GET request. */ (void)req_body; (void)req_body_len; log_debug(LD_DIRSERV,"Received GET command."); conn->base_.state = DIR_CONN_STATE_SERVER_WRITING; if (parse_http_url(headers, &url) < 0) { write_http_status_line(conn, 400, "Bad request"); return 0; } if ((header = http_get_header(headers, "If-Modified-Since: "))) { struct tm tm; if (parse_http_time(header, &tm) == 0) { if (tor_timegm(&tm, &if_modified_since)<0) if_modified_since = 0; } /* The correct behavior on a malformed If-Modified-Since header is to * act as if no If-Modified-Since header had been given. */ tor_free(header); } log_debug(LD_DIRSERV,"rewritten url as '%s'.", url); url_mem = url; url_len = strlen(url); compressed = url_len > 2 && !strcmp(url+url_len-2, ".z"); if (compressed) { url[url_len-2] = '\0'; url_len -= 2; } if (!strcmp(url,"/tor/")) { const char *frontpage = get_dirportfrontpage(); if (frontpage) { dlen = strlen(frontpage); /* Let's return a disclaimer page (users shouldn't use V1 anymore, and caches don't fetch '/', so this is safe). */ /* [We don't check for write_bucket_low here, since we want to serve * this page no matter what.] */ note_request(url, dlen); write_http_response_header_impl(conn, dlen, "text/html", "identity", NULL, DIRPORTFRONTPAGE_CACHE_LIFETIME); connection_write_to_buf(frontpage, dlen, TO_CONN(conn)); goto done; } /* if no disclaimer file, fall through and continue */ } if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir")) { /* v1 dir fetch */ cached_dir_t *d = dirserv_get_directory(); if (!d) { log_info(LD_DIRSERV,"Client asked for the mirrored directory, but we " "don't have a good one yet. Sending 503 Dir not available."); write_http_status_line(conn, 503, "Directory unavailable"); goto done; } if (d->published < if_modified_since) { write_http_status_line(conn, 304, "Not modified"); goto done; } dlen = compressed ? d->dir_z_len : d->dir_len; if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) { log_debug(LD_DIRSERV, "Client asked for the mirrored directory, but we've been " "writing too many bytes lately. Sending 503 Dir busy."); write_http_status_line(conn, 503, "Directory busy, try again later"); goto done; } note_request(url, dlen); log_debug(LD_DIRSERV,"Dumping %sdirectory to client.", compressed?"compressed ":""); write_http_response_header(conn, dlen, compressed, FULL_DIR_CACHE_LIFETIME); conn->cached_dir = d; conn->cached_dir_offset = 0; if (!compressed) conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD); ++d->refcnt; /* Prime the connection with some data. */ conn->dir_spool_src = DIR_SPOOL_CACHED_DIR; connection_dirserv_flushed_some(conn); goto done; } if (!strcmp(url,"/tor/running-routers")) { /* running-routers fetch */ cached_dir_t *d = dirserv_get_runningrouters(); if (!d) { write_http_status_line(conn, 503, "Directory unavailable"); goto done; } if (d->published < if_modified_since) { write_http_status_line(conn, 304, "Not modified"); goto done; } dlen = compressed ? d->dir_z_len : d->dir_len; if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) { log_info(LD_DIRSERV, "Client asked for running-routers, but we've been " "writing too many bytes lately. Sending 503 Dir busy."); write_http_status_line(conn, 503, "Directory busy, try again later"); goto done; } note_request(url, dlen); write_http_response_header(conn, dlen, compressed, RUNNINGROUTERS_CACHE_LIFETIME); connection_write_to_buf(compressed ? d->dir_z : d->dir, dlen, TO_CONN(conn)); goto done; } if (!strcmpstart(url,"/tor/status/") || !strcmpstart(url, "/tor/status-vote/current/consensus")) { /* v2 or v3 network status fetch. */ smartlist_t *dir_fps = smartlist_new(); int is_v3 = !strcmpstart(url, "/tor/status-vote"); const char *request_type = NULL; const char *key = url + strlen("/tor/status/"); long lifetime = NETWORKSTATUS_CACHE_LIFETIME; if (options->DisableV2DirectoryInfo_ && !is_v3) { static ratelim_t reject_v2_ratelim = RATELIM_INIT(1800); char *m; write_http_status_line(conn, 404, "Not found"); smartlist_free(dir_fps); geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND); if ((m = rate_limit_log(&reject_v2_ratelim, approx_time()))) { log_notice(LD_DIR, "Rejected a v2 networkstatus request.%s", m); tor_free(m); } goto done; } if (!is_v3) { dirserv_get_networkstatus_v2_fingerprints(dir_fps, key); if (!strcmpstart(key, "fp/")) request_type = compressed?"/tor/status/fp.z":"/tor/status/fp"; else if (!strcmpstart(key, "authority")) request_type = compressed?"/tor/status/authority.z": "/tor/status/authority"; else if (!strcmpstart(key, "all")) request_type = compressed?"/tor/status/all.z":"/tor/status/all"; else request_type = "/tor/status/?"; } else { networkstatus_t *v; time_t now = time(NULL); const char *want_fps = NULL; char *flavor = NULL; int flav = FLAV_NS; #define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/" #define CONSENSUS_FLAVORED_PREFIX "/tor/status-vote/current/consensus-" /* figure out the flavor if any, and who we wanted to sign the thing */ if (!strcmpstart(url, CONSENSUS_FLAVORED_PREFIX)) { const char *f, *cp; f = url + strlen(CONSENSUS_FLAVORED_PREFIX); cp = strchr(f, '/'); if (cp) { want_fps = cp+1; flavor = tor_strndup(f, cp-f); } else { flavor = tor_strdup(f); } flav = networkstatus_parse_flavor_name(flavor); if (flav < 0) flav = FLAV_NS; } else { if (!strcmpstart(url, CONSENSUS_URL_PREFIX)) want_fps = url+strlen(CONSENSUS_URL_PREFIX); } v = networkstatus_get_latest_consensus_by_flavor(flav); if (v && want_fps && !client_likes_consensus(v, want_fps)) { write_http_status_line(conn, 404, "Consensus not signed by sufficient " "number of requested authorities"); smartlist_free(dir_fps); geoip_note_ns_response(GEOIP_REJECT_NOT_ENOUGH_SIGS); tor_free(flavor); goto done; } { char *fp = tor_malloc_zero(DIGEST_LEN); if (flavor) strlcpy(fp, flavor, DIGEST_LEN); tor_free(flavor); smartlist_add(dir_fps, fp); } request_type = compressed?"v3.z":"v3"; lifetime = (v && v->fresh_until > now) ? v->fresh_until - now : 0; } if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */ write_http_status_line(conn, 503, "Network status object unavailable"); smartlist_free(dir_fps); if (is_v3) geoip_note_ns_response(GEOIP_REJECT_UNAVAILABLE); goto done; } if (!dirserv_remove_old_statuses(dir_fps, if_modified_since)) { write_http_status_line(conn, 404, "Not found"); SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp)); smartlist_free(dir_fps); if (is_v3) geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND); goto done; } else if (!smartlist_len(dir_fps)) { write_http_status_line(conn, 304, "Not modified"); SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp)); smartlist_free(dir_fps); if (is_v3) geoip_note_ns_response(GEOIP_REJECT_NOT_MODIFIED); goto done; } dlen = dirserv_estimate_data_size(dir_fps, 0, compressed); if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) { log_debug(LD_DIRSERV, "Client asked for network status lists, but we've been " "writing too many bytes lately. Sending 503 Dir busy."); write_http_status_line(conn, 503, "Directory busy, try again later"); SMARTLIST_FOREACH(dir_fps, char *, fp, tor_free(fp)); smartlist_free(dir_fps); if (is_v3) geoip_note_ns_response(GEOIP_REJECT_BUSY); goto done; } if (is_v3) { struct in_addr in; tor_addr_t addr; if (tor_inet_aton((TO_CONN(conn))->address, &in)) { tor_addr_from_ipv4h(&addr, ntohl(in.s_addr)); geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, time(NULL)); geoip_note_ns_response(GEOIP_SUCCESS); /* Note that a request for a network status has started, so that we * can measure the download time later on. */ if (conn->dirreq_id) geoip_start_dirreq(conn->dirreq_id, dlen, DIRREQ_TUNNELED); else geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen, DIRREQ_DIRECT); } } // note_request(request_type,dlen); (void) request_type; write_http_response_header(conn, -1, compressed, smartlist_len(dir_fps) == 1 ? lifetime : 0); conn->fingerprint_stack = dir_fps; if (! compressed) conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD); /* Prime the connection with some data. */ conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS; connection_dirserv_flushed_some(conn); goto done; } if (!strcmpstart(url,"/tor/status-vote/current/") || !strcmpstart(url,"/tor/status-vote/next/")) { /* XXXX If-modified-since is only implemented for the current * consensus: that's probably fine, since it's the only vote document * people fetch much. */ int current; ssize_t body_len = 0; ssize_t estimated_len = 0; smartlist_t *items = smartlist_new(); smartlist_t *dir_items = smartlist_new(); int lifetime = 60; /* XXXX023 should actually use vote intervals. */ url += strlen("/tor/status-vote/"); current = !strcmpstart(url, "current/"); url = strchr(url, '/'); tor_assert(url); ++url; if (!strcmp(url, "consensus")) { const char *item; tor_assert(!current); /* we handle current consensus specially above, * since it wants to be spooled. */ if ((item = dirvote_get_pending_consensus(FLAV_NS))) smartlist_add(items, (char*)item); } else if (!current && !strcmp(url, "consensus-signatures")) { /* XXXX the spec says that we should implement * current/consensus-signatures too. It doesn't seem to be needed, * though. */ const char *item; if ((item=dirvote_get_pending_detached_signatures())) smartlist_add(items, (char*)item); } else if (!strcmp(url, "authority")) { const cached_dir_t *d; int flags = DGV_BY_ID | (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING); if ((d=dirvote_get_vote(NULL, flags))) smartlist_add(dir_items, (cached_dir_t*)d); } else { const cached_dir_t *d; smartlist_t *fps = smartlist_new(); int flags; if (!strcmpstart(url, "d/")) { url += 2; flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS; } else { flags = DGV_BY_ID | (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING); } dir_split_resource_into_fingerprints(url, fps, NULL, DSR_HEX|DSR_SORT_UNIQ); SMARTLIST_FOREACH(fps, char *, fp, { if ((d = dirvote_get_vote(fp, flags))) smartlist_add(dir_items, (cached_dir_t*)d); tor_free(fp); }); smartlist_free(fps); } if (!smartlist_len(dir_items) && !smartlist_len(items)) { write_http_status_line(conn, 404, "Not found"); goto vote_done; } SMARTLIST_FOREACH(dir_items, cached_dir_t *, d, body_len += compressed ? d->dir_z_len : d->dir_len); estimated_len += body_len; SMARTLIST_FOREACH(items, const char *, item, { size_t ln = strlen(item); if (compressed) { estimated_len += ln/2; } else { body_len += ln; estimated_len += ln; } }); if (global_write_bucket_low(TO_CONN(conn), estimated_len, 2)) { write_http_status_line(conn, 503, "Directory busy, try again later."); goto vote_done; } write_http_response_header(conn, body_len ? body_len : -1, compressed, lifetime); if (smartlist_len(items)) { if (compressed) { conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); SMARTLIST_FOREACH(items, const char *, c, connection_write_to_buf_zlib(c, strlen(c), conn, 0)); connection_write_to_buf_zlib("", 0, conn, 1); } else { SMARTLIST_FOREACH(items, const char *, c, connection_write_to_buf(c, strlen(c), TO_CONN(conn))); } } else { SMARTLIST_FOREACH(dir_items, cached_dir_t *, d, connection_write_to_buf(compressed ? d->dir_z : d->dir, compressed ? d->dir_z_len : d->dir_len, TO_CONN(conn))); } vote_done: smartlist_free(items); smartlist_free(dir_items); goto done; } if (!strcmpstart(url, "/tor/micro/d/")) { smartlist_t *fps = smartlist_new(); dir_split_resource_into_fingerprints(url+strlen("/tor/micro/d/"), fps, NULL, DSR_DIGEST256|DSR_BASE64|DSR_SORT_UNIQ); if (!dirserv_have_any_microdesc(fps)) { write_http_status_line(conn, 404, "Not found"); SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp)); smartlist_free(fps); goto done; } dlen = dirserv_estimate_microdesc_size(fps, compressed); if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) { log_info(LD_DIRSERV, "Client asked for server descriptors, but we've been " "writing too many bytes lately. Sending 503 Dir busy."); write_http_status_line(conn, 503, "Directory busy, try again later"); SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp)); smartlist_free(fps); goto done; } write_http_response_header(conn, -1, compressed, MICRODESC_CACHE_LIFETIME); conn->dir_spool_src = DIR_SPOOL_MICRODESC; conn->fingerprint_stack = fps; if (compressed) conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); connection_dirserv_flushed_some(conn); goto done; } if (!strcmpstart(url,"/tor/server/") || (!options->BridgeAuthoritativeDir && !options->BridgeRelay && !strcmpstart(url,"/tor/extra/"))) { int res; const char *msg; const char *request_type = NULL; int cache_lifetime = 0; int is_extra = !strcmpstart(url,"/tor/extra/"); url += is_extra ? strlen("/tor/extra/") : strlen("/tor/server/"); conn->fingerprint_stack = smartlist_new(); res = dirserv_get_routerdesc_fingerprints(conn->fingerprint_stack, url, &msg, !connection_dir_is_encrypted(conn), is_extra); if (!strcmpstart(url, "fp/")) { request_type = compressed?"/tor/server/fp.z":"/tor/server/fp"; if (smartlist_len(conn->fingerprint_stack) == 1) cache_lifetime = ROUTERDESC_CACHE_LIFETIME; } else if (!strcmpstart(url, "authority")) { request_type = compressed?"/tor/server/authority.z": "/tor/server/authority"; cache_lifetime = ROUTERDESC_CACHE_LIFETIME; } else if (!strcmpstart(url, "all")) { request_type = compressed?"/tor/server/all.z":"/tor/server/all"; cache_lifetime = FULL_DIR_CACHE_LIFETIME; } else if (!strcmpstart(url, "d/")) { request_type = compressed?"/tor/server/d.z":"/tor/server/d"; if (smartlist_len(conn->fingerprint_stack) == 1) cache_lifetime = ROUTERDESC_BY_DIGEST_CACHE_LIFETIME; } else { request_type = "/tor/server/?"; } (void) request_type; /* usable for note_request. */ if (!strcmpstart(url, "d/")) conn->dir_spool_src = is_extra ? DIR_SPOOL_EXTRA_BY_DIGEST : DIR_SPOOL_SERVER_BY_DIGEST; else conn->dir_spool_src = is_extra ? DIR_SPOOL_EXTRA_BY_FP : DIR_SPOOL_SERVER_BY_FP; if (!dirserv_have_any_serverdesc(conn->fingerprint_stack, conn->dir_spool_src)) { res = -1; msg = "Not found"; } if (res < 0) write_http_status_line(conn, 404, msg); else { dlen = dirserv_estimate_data_size(conn->fingerprint_stack, 1, compressed); if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) { log_info(LD_DIRSERV, "Client asked for server descriptors, but we've been " "writing too many bytes lately. Sending 503 Dir busy."); write_http_status_line(conn, 503, "Directory busy, try again later"); conn->dir_spool_src = DIR_SPOOL_NONE; goto done; } write_http_response_header(conn, -1, compressed, cache_lifetime); if (compressed) conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); /* Prime the connection with some data. */ connection_dirserv_flushed_some(conn); } goto done; } if (!strcmpstart(url,"/tor/keys/")) { smartlist_t *certs = smartlist_new(); ssize_t len = -1; if (!strcmp(url, "/tor/keys/all")) { authority_cert_get_all(certs); } else if (!strcmp(url, "/tor/keys/authority")) { authority_cert_t *cert = get_my_v3_authority_cert(); if (cert) smartlist_add(certs, cert); } else if (!strcmpstart(url, "/tor/keys/fp/")) { smartlist_t *fps = smartlist_new(); dir_split_resource_into_fingerprints(url+strlen("/tor/keys/fp/"), fps, NULL, DSR_HEX|DSR_SORT_UNIQ); SMARTLIST_FOREACH(fps, char *, d, { authority_cert_t *c = authority_cert_get_newest_by_id(d); if (c) smartlist_add(certs, c); tor_free(d); }); smartlist_free(fps); } else if (!strcmpstart(url, "/tor/keys/sk/")) { smartlist_t *fps = smartlist_new(); dir_split_resource_into_fingerprints(url+strlen("/tor/keys/sk/"), fps, NULL, DSR_HEX|DSR_SORT_UNIQ); SMARTLIST_FOREACH(fps, char *, d, { authority_cert_t *c = authority_cert_get_by_sk_digest(d); if (c) smartlist_add(certs, c); tor_free(d); }); smartlist_free(fps); } else if (!strcmpstart(url, "/tor/keys/fp-sk/")) { smartlist_t *fp_sks = smartlist_new(); dir_split_resource_into_fingerprint_pairs(url+strlen("/tor/keys/fp-sk/"), fp_sks); SMARTLIST_FOREACH(fp_sks, fp_pair_t *, pair, { authority_cert_t *c = authority_cert_get_by_digests(pair->first, pair->second); if (c) smartlist_add(certs, c); tor_free(pair); }); smartlist_free(fp_sks); } else { write_http_status_line(conn, 400, "Bad request"); goto keys_done; } if (!smartlist_len(certs)) { write_http_status_line(conn, 404, "Not found"); goto keys_done; } SMARTLIST_FOREACH(certs, authority_cert_t *, c, if (c->cache_info.published_on < if_modified_since) SMARTLIST_DEL_CURRENT(certs, c)); if (!smartlist_len(certs)) { write_http_status_line(conn, 304, "Not modified"); goto keys_done; } len = 0; SMARTLIST_FOREACH(certs, authority_cert_t *, c, len += c->cache_info.signed_descriptor_len); if (global_write_bucket_low(TO_CONN(conn), compressed?len/2:len, 2)) { write_http_status_line(conn, 503, "Directory busy, try again later."); goto keys_done; } write_http_response_header(conn, compressed?-1:len, compressed, 60*60); if (compressed) { conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); SMARTLIST_FOREACH(certs, authority_cert_t *, c, connection_write_to_buf_zlib(c->cache_info.signed_descriptor_body, c->cache_info.signed_descriptor_len, conn, 0)); connection_write_to_buf_zlib("", 0, conn, 1); } else { SMARTLIST_FOREACH(certs, authority_cert_t *, c, connection_write_to_buf(c->cache_info.signed_descriptor_body, c->cache_info.signed_descriptor_len, TO_CONN(conn))); } keys_done: smartlist_free(certs); goto done; } if (options->HidServDirectoryV2 && connection_dir_is_encrypted(conn) && !strcmpstart(url,"/tor/rendezvous2/")) { /* Handle v2 rendezvous descriptor fetch request. */ const char *descp; const char *query = url + strlen("/tor/rendezvous2/"); if (strlen(query) == REND_DESC_ID_V2_LEN_BASE32) { log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'", safe_str(query)); switch (rend_cache_lookup_v2_desc_as_dir(query, &descp)) { case 1: /* valid */ write_http_response_header(conn, strlen(descp), 0, 0); connection_write_to_buf(descp, strlen(descp), TO_CONN(conn)); break; case 0: /* well-formed but not present */ write_http_status_line(conn, 404, "Not found"); break; case -1: /* not well-formed */ write_http_status_line(conn, 400, "Bad request"); break; } } else { /* not well-formed */ write_http_status_line(conn, 400, "Bad request"); } goto done; } if (options->HSAuthoritativeDir && !strcmpstart(url,"/tor/rendezvous/")) { /* rendezvous descriptor fetch */ const char *descp; size_t desc_len; const char *query = url+strlen("/tor/rendezvous/"); log_info(LD_REND, "Handling rendezvous descriptor get"); switch (rend_cache_lookup_desc(query, 0, &descp, &desc_len)) { case 1: /* valid */ write_http_response_header_impl(conn, desc_len, "application/octet-stream", NULL, NULL, 0); note_request("/tor/rendezvous?/", desc_len); /* need to send descp separately, because it may include NULs */ connection_write_to_buf(descp, desc_len, TO_CONN(conn)); break; case 0: /* well-formed but not present */ write_http_status_line(conn, 404, "Not found"); break; case -1: /* not well-formed */ write_http_status_line(conn, 400, "Bad request"); break; } goto done; } if (options->BridgeAuthoritativeDir && options->BridgePassword_AuthDigest_ && connection_dir_is_encrypted(conn) && !strcmp(url,"/tor/networkstatus-bridges")) { char *status; char digest[DIGEST256_LEN]; header = http_get_header(headers, "Authorization: Basic "); if (header) crypto_digest256(digest, header, strlen(header), DIGEST_SHA256); /* now make sure the password is there and right */ if (!header || tor_memneq(digest, options->BridgePassword_AuthDigest_, DIGEST256_LEN)) { write_http_status_line(conn, 404, "Not found"); tor_free(header); goto done; } tor_free(header); /* all happy now. send an answer. */ status = networkstatus_getinfo_by_purpose("bridge", time(NULL)); dlen = strlen(status); write_http_response_header(conn, dlen, 0, 0); connection_write_to_buf(status, dlen, TO_CONN(conn)); tor_free(status); goto done; } if (!strcmpstart(url,"/tor/bytes.txt")) { char *bytes = directory_dump_request_log(); size_t len = strlen(bytes); write_http_response_header(conn, len, 0, 0); connection_write_to_buf(bytes, len, TO_CONN(conn)); tor_free(bytes); goto done; } if (!strcmp(url,"/tor/robots.txt")) { /* /robots.txt will have been rewritten to /tor/robots.txt */ char robots[] = "User-agent: *\r\nDisallow: /\r\n"; size_t len = strlen(robots); write_http_response_header(conn, len, 0, ROBOTS_CACHE_LIFETIME); connection_write_to_buf(robots, len, TO_CONN(conn)); goto done; } if (!strcmp(url,"/tor/dbg-stability.txt")) { const char *stability; size_t len; if (options->BridgeAuthoritativeDir || ! authdir_mode_tests_reachability(options) || ! (stability = rep_hist_get_router_stability_doc(time(NULL)))) { write_http_status_line(conn, 404, "Not found."); goto done; } len = strlen(stability); write_http_response_header(conn, len, 0, 0); connection_write_to_buf(stability, len, TO_CONN(conn)); goto done; } #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) #define ADD_MALLINFO_LINE(x) do { \ smartlist_add_asprintf(lines, "%s %d\n", #x, mi.x); \ }while(0); if (!strcmp(url,"/tor/mallinfo.txt") && (tor_addr_eq_ipv4h(&conn->base_.addr, 0x7f000001ul))) { char *result; size_t len; struct mallinfo mi; smartlist_t *lines; memset(&mi, 0, sizeof(mi)); mi = mallinfo(); lines = smartlist_new(); ADD_MALLINFO_LINE(arena) ADD_MALLINFO_LINE(ordblks) ADD_MALLINFO_LINE(smblks) ADD_MALLINFO_LINE(hblks) ADD_MALLINFO_LINE(hblkhd) ADD_MALLINFO_LINE(usmblks) ADD_MALLINFO_LINE(fsmblks) ADD_MALLINFO_LINE(uordblks) ADD_MALLINFO_LINE(fordblks) ADD_MALLINFO_LINE(keepcost) result = smartlist_join_strings(lines, "", 0, NULL); SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); smartlist_free(lines); len = strlen(result); write_http_response_header(conn, len, 0, 0); connection_write_to_buf(result, len, TO_CONN(conn)); tor_free(result); goto done; } #endif /* we didn't recognize the url */ write_http_status_line(conn, 404, "Not found"); done: tor_free(url_mem); return 0; } /** Helper function: called when a dirserver gets a complete HTTP POST * request. Look for an uploaded server descriptor or rendezvous * service descriptor. On finding one, process it and write a * response into conn-\>outbuf. If the request is unrecognized, send a * 400. Always return 0. */ static int directory_handle_command_post(dir_connection_t *conn, const char *headers, const char *body, size_t body_len) { char *url = NULL; const or_options_t *options = get_options(); log_debug(LD_DIRSERV,"Received POST command."); conn->base_.state = DIR_CONN_STATE_SERVER_WRITING; if (parse_http_url(headers, &url) < 0) { write_http_status_line(conn, 400, "Bad request"); return 0; } log_debug(LD_DIRSERV,"rewritten url as '%s'.", url); /* Handle v2 rendezvous service publish request. */ if (options->HidServDirectoryV2 && connection_dir_is_encrypted(conn) && !strcmpstart(url,"/tor/rendezvous2/publish")) { switch (rend_cache_store_v2_desc_as_dir(body)) { case -2: log_info(LD_REND, "Rejected v2 rend descriptor (length %d) from %s " "since we're not currently a hidden service directory.", (int)body_len, conn->base_.address); write_http_status_line(conn, 503, "Currently not acting as v2 " "hidden service directory"); break; case -1: log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.", (int)body_len, conn->base_.address); write_http_status_line(conn, 400, "Invalid v2 service descriptor rejected"); break; default: write_http_status_line(conn, 200, "Service descriptor (v2) stored"); log_info(LD_REND, "Handled v2 rendezvous descriptor post: accepted"); } goto done; } if (!authdir_mode(options)) { /* we just provide cached directories; we don't want to * receive anything. */ write_http_status_line(conn, 400, "Nonauthoritative directory does not " "accept posted server descriptors"); goto done; } if (authdir_mode_handles_descs(options, -1) && !strcmp(url,"/tor/")) { /* server descriptor post */ const char *msg = "[None]"; uint8_t purpose = authdir_mode_bridge(options) ? ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL; was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose, conn->base_.address, &msg); tor_assert(msg); if (WRA_WAS_ADDED(r)) dirserv_get_directory(); /* rebuild and write to disk */ if (r == ROUTER_ADDED_NOTIFY_GENERATOR) { /* Accepted with a message. */ log_info(LD_DIRSERV, "Problematic router descriptor or extra-info from %s " "(\"%s\").", conn->base_.address, msg); write_http_status_line(conn, 400, msg); } else if (r == ROUTER_ADDED_SUCCESSFULLY) { write_http_status_line(conn, 200, msg); } else if (WRA_WAS_OUTDATED(r)) { write_http_response_header_impl(conn, -1, NULL, NULL, "X-Descriptor-Not-New: Yes\r\n", -1); } else { log_info(LD_DIRSERV, "Rejected router descriptor or extra-info from %s " "(\"%s\").", conn->base_.address, msg); write_http_status_line(conn, 400, msg); } goto done; } if (options->HSAuthoritativeDir && !strcmpstart(url,"/tor/rendezvous/publish")) { /* rendezvous descriptor post */ log_info(LD_REND, "Handling rendezvous descriptor post."); if (rend_cache_store(body, body_len, 1, NULL) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV, "Rejected rend descriptor (length %d) from %s.", (int)body_len, conn->base_.address); write_http_status_line(conn, 400, "Invalid v0 service descriptor rejected"); } else { write_http_status_line(conn, 200, "Service descriptor (v0) stored"); } goto done; } if (authdir_mode_v3(options) && !strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */ const char *msg = "OK"; int status; if (dirvote_add_vote(body, &msg, &status)) { write_http_status_line(conn, status, "Vote stored"); } else { tor_assert(msg); log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").", conn->base_.address, msg); write_http_status_line(conn, status, msg); } goto done; } if (authdir_mode_v3(options) && !strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */ const char *msg = NULL; if (dirvote_add_signatures(body, conn->base_.address, &msg)>=0) { write_http_status_line(conn, 200, msg?msg:"Signatures stored"); } else { log_warn(LD_DIR, "Unable to store signatures posted by %s: %s", conn->base_.address, msg?msg:"???"); write_http_status_line(conn, 400, msg?msg:"Unable to store signatures"); } goto done; } /* we didn't recognize the url */ write_http_status_line(conn, 404, "Not found"); done: tor_free(url); return 0; } /** Called when a dirserver receives data on a directory connection; * looks for an HTTP request. If the request is complete, remove it * from the inbuf, try to process it; otherwise, leave it on the * buffer. Return a 0 on success, or -1 on error. */ static int directory_handle_command(dir_connection_t *conn) { char *headers=NULL, *body=NULL; size_t body_len=0; int r; tor_assert(conn); tor_assert(conn->base_.type == CONN_TYPE_DIR); switch (connection_fetch_from_buf_http(TO_CONN(conn), &headers, MAX_HEADERS_SIZE, &body, &body_len, MAX_DIR_UL_SIZE, 0)) { case -1: /* overflow */ log_warn(LD_DIRSERV, "Request too large from address '%s' to DirPort. Closing.", safe_str(conn->base_.address)); return -1; case 0: log_debug(LD_DIRSERV,"command not all here yet."); return 0; /* case 1, fall through */ } http_set_address_origin(headers, TO_CONN(conn)); //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body); if (!strncasecmp(headers,"GET",3)) r = directory_handle_command_get(conn, headers, body, body_len); else if (!strncasecmp(headers,"POST",4)) r = directory_handle_command_post(conn, headers, body, body_len); else { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Got headers %s with unknown command. Closing.", escaped(headers)); r = -1; } tor_free(headers); tor_free(body); return r; } /** Write handler for directory connections; called when all data has * been flushed. Close the connection or wait for a response as * appropriate. */ int connection_dir_finished_flushing(dir_connection_t *conn) { tor_assert(conn); tor_assert(conn->base_.type == CONN_TYPE_DIR); /* Note that we have finished writing the directory response. For direct * connections this means we're done, for tunneled connections its only * an intermediate step. */ if (conn->dirreq_id) geoip_change_dirreq_state(conn->dirreq_id, DIRREQ_TUNNELED, DIRREQ_FLUSHING_DIR_CONN_FINISHED); else geoip_change_dirreq_state(TO_CONN(conn)->global_identifier, DIRREQ_DIRECT, DIRREQ_FLUSHING_DIR_CONN_FINISHED); switch (conn->base_.state) { case DIR_CONN_STATE_CONNECTING: case DIR_CONN_STATE_CLIENT_SENDING: log_debug(LD_DIR,"client finished sending command."); conn->base_.state = DIR_CONN_STATE_CLIENT_READING; return 0; case DIR_CONN_STATE_SERVER_WRITING: if (conn->dir_spool_src != DIR_SPOOL_NONE) { #ifdef USE_BUFFEREVENTS /* This can happen with paired bufferevents, since a paired connection * can flush immediately when you write to it, making the subsequent * check in connection_handle_write_cb() decide that the connection * is flushed. */ log_debug(LD_DIRSERV, "Emptied a dirserv buffer, but still spooling."); #else log_warn(LD_BUG, "Emptied a dirserv buffer, but it's still spooling!"); connection_mark_for_close(TO_CONN(conn)); #endif } else { log_debug(LD_DIRSERV, "Finished writing server response. Closing."); connection_mark_for_close(TO_CONN(conn)); } return 0; default: log_warn(LD_BUG,"called in unexpected state %d.", conn->base_.state); tor_fragile_assert(); return -1; } return 0; } /** Connected handler for directory connections: begin sending data to the * server */ int connection_dir_finished_connecting(dir_connection_t *conn) { tor_assert(conn); tor_assert(conn->base_.type == CONN_TYPE_DIR); tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING); log_debug(LD_HTTP,"Dir connection to router %s:%u established.", conn->base_.address,conn->base_.port); conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */ return 0; } /** Called when one or more networkstatus fetches have failed (with uppercase * fingerprints listed in failed). Mark those fingerprints as having * failed once, unless they failed with status code 503. */ static void dir_networkstatus_download_failed(smartlist_t *failed, int status_code) { if (status_code == 503) return; SMARTLIST_FOREACH_BEGIN(failed, const char *, fp) { char digest[DIGEST_LEN]; dir_server_t *dir; if (base16_decode(digest, DIGEST_LEN, fp, strlen(fp))<0) { log_warn(LD_BUG, "Called with bad fingerprint in list: %s", escaped(fp)); continue; } dir = router_get_fallback_dirserver_by_digest(digest); if (dir) download_status_failed(&dir->v2_ns_dl_status, status_code); } SMARTLIST_FOREACH_END(fp); } /** Schedule for when servers should download things in general. */ static const int server_dl_schedule[] = { 0, 0, 0, 60, 60, 60*2, 60*5, 60*15, INT_MAX }; /** Schedule for when clients should download things in general. */ static const int client_dl_schedule[] = { 0, 0, 60, 60*5, 60*10, INT_MAX }; /** Schedule for when servers should download consensuses. */ static const int server_consensus_dl_schedule[] = { 0, 0, 60, 60*5, 60*10, 60*30, 60*30, 60*30, 60*30, 60*30, 60*60, 60*60*2 }; /** Schedule for when clients should download consensuses. */ static const int client_consensus_dl_schedule[] = { 0, 0, 60, 60*5, 60*10, 60*30, 60*60, 60*60, 60*60, 60*60*3, 60*60*6, 60*60*12 }; /** Schedule for when clients should download bridge descriptors. */ static const int bridge_dl_schedule[] = { 60*60, 15*60, 15*60, 60*60 }; /** Decide which download schedule we want to use, and then return a * pointer to it along with a pointer to its length. Helper function for * download_status_increment_failure() and download_status_reset(). */ static void find_dl_schedule_and_len(download_status_t *dls, int server, const int **schedule, size_t *schedule_len) { switch (dls->schedule) { case DL_SCHED_GENERIC: if (server) { *schedule = server_dl_schedule; *schedule_len = sizeof(server_dl_schedule)/sizeof(int); } else { *schedule = client_dl_schedule; *schedule_len = sizeof(client_dl_schedule)/sizeof(int); } break; case DL_SCHED_CONSENSUS: if (server) { *schedule = server_consensus_dl_schedule; *schedule_len = sizeof(server_consensus_dl_schedule)/sizeof(int); } else { *schedule = client_consensus_dl_schedule; *schedule_len = sizeof(client_consensus_dl_schedule)/sizeof(int); } break; case DL_SCHED_BRIDGE: *schedule = bridge_dl_schedule; *schedule_len = sizeof(bridge_dl_schedule)/sizeof(int); break; default: tor_assert(0); } } /** Called when an attempt to download dls has failed with HTTP status * status_code. Increment the failure count (if the code indicates a * real failure) and set dls-\>next_attempt_at to an appropriate time * in the future. */ time_t download_status_increment_failure(download_status_t *dls, int status_code, const char *item, int server, time_t now) { const int *schedule; size_t schedule_len; int increment; tor_assert(dls); if (status_code != 503 || server) { if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1) ++dls->n_download_failures; } find_dl_schedule_and_len(dls, server, &schedule, &schedule_len); if (dls->n_download_failures < schedule_len) increment = schedule[dls->n_download_failures]; else if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD) increment = INT_MAX; else increment = schedule[schedule_len-1]; if (increment < INT_MAX) dls->next_attempt_at = now+increment; else dls->next_attempt_at = TIME_MAX; if (item) { if (increment == 0) log_debug(LD_DIR, "%s failed %d time(s); I'll try again immediately.", item, (int)dls->n_download_failures); else if (dls->next_attempt_at < TIME_MAX) log_debug(LD_DIR, "%s failed %d time(s); I'll try again in %d seconds.", item, (int)dls->n_download_failures, (int)(dls->next_attempt_at-now)); else log_debug(LD_DIR, "%s failed %d time(s); Giving up for a while.", item, (int)dls->n_download_failures); } return dls->next_attempt_at; } /** Reset dls so that it will be considered downloadable * immediately, and/or to show that we don't need it anymore. * * (We find the zeroth element of the download schedule, and set * next_attempt_at to be the appropriate offset from 'now'. In most * cases this means setting it to 'now', so the item will be immediately * downloadable; in the case of bridge descriptors, the zeroth element * is an hour from now.) */ void download_status_reset(download_status_t *dls) { const int *schedule; size_t schedule_len; find_dl_schedule_and_len(dls, get_options()->DirPort_set, &schedule, &schedule_len); dls->n_download_failures = 0; dls->next_attempt_at = time(NULL) + schedule[0]; } /** Return the number of failures on dls since the last success (if * any). */ int download_status_get_n_failures(const download_status_t *dls) { return dls->n_download_failures; } /** Called when one or more routerdesc (or extrainfo, if was_extrainfo) * fetches have failed (with uppercase fingerprints listed in failed, * either as descriptor digests or as identity digests based on * was_descriptor_digests). */ static void dir_routerdesc_download_failed(smartlist_t *failed, int status_code, int router_purpose, int was_extrainfo, int was_descriptor_digests) { char digest[DIGEST_LEN]; time_t now = time(NULL); int server = directory_fetches_from_authorities(get_options()); if (!was_descriptor_digests) { if (router_purpose == ROUTER_PURPOSE_BRIDGE) { tor_assert(!was_extrainfo); connection_dir_retry_bridges(failed); } return; /* FFFF should implement for other-than-router-purpose someday */ } SMARTLIST_FOREACH_BEGIN(failed, const char *, cp) { download_status_t *dls = NULL; if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp)) < 0) { log_warn(LD_BUG, "Malformed fingerprint in list: %s", escaped(cp)); continue; } if (was_extrainfo) { signed_descriptor_t *sd = router_get_by_extrainfo_digest(digest); if (sd) dls = &sd->ei_dl_status; } else { dls = router_get_dl_status_by_descriptor_digest(digest); } if (!dls || dls->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES) continue; download_status_increment_failure(dls, status_code, cp, server, now); } SMARTLIST_FOREACH_END(cp); /* No need to relaunch descriptor downloads here: we already do it * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */ } /** Called when a connection to download microdescriptors has failed in whole * or in part. failed is a list of every microdesc digest we didn't * get. status_code is the http status code we received. Reschedule the * microdesc downloads as appropriate. */ static void dir_microdesc_download_failed(smartlist_t *failed, int status_code) { networkstatus_t *consensus = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC); routerstatus_t *rs; download_status_t *dls; time_t now = time(NULL); int server = directory_fetches_from_authorities(get_options()); if (! consensus) return; SMARTLIST_FOREACH_BEGIN(failed, const char *, d) { rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d); if (!rs) continue; dls = &rs->dl_status; if (dls->n_download_failures >= MAX_MICRODESC_DOWNLOAD_FAILURES) continue; { char buf[BASE64_DIGEST256_LEN+1]; digest256_to_base64(buf, d); download_status_increment_failure(dls, status_code, buf, server, now); } } SMARTLIST_FOREACH_END(d); } /** Helper. Compare two fp_pair_t objects, and return negative, 0, or * positive as appropriate. */ static int compare_pairs_(const void **a, const void **b) { const fp_pair_t *fp1 = *a, *fp2 = *b; int r; if ((r = fast_memcmp(fp1->first, fp2->first, DIGEST_LEN))) return r; else return fast_memcmp(fp1->second, fp2->second, DIGEST_LEN); } /** Divide a string res of the form FP1-FP2+FP3-FP4...[.z], where each * FP is a hex-encoded fingerprint, into a sequence of distinct sorted * fp_pair_t. Skip malformed pairs. On success, return 0 and add those * fp_pair_t into pairs_out. On failure, return -1. */ int dir_split_resource_into_fingerprint_pairs(const char *res, smartlist_t *pairs_out) { smartlist_t *pairs_tmp = smartlist_new(); smartlist_t *pairs_result = smartlist_new(); smartlist_split_string(pairs_tmp, res, "+", 0, 0); if (smartlist_len(pairs_tmp)) { char *last = smartlist_get(pairs_tmp,smartlist_len(pairs_tmp)-1); size_t last_len = strlen(last); if (last_len > 2 && !strcmp(last+last_len-2, ".z")) { last[last_len-2] = '\0'; } } SMARTLIST_FOREACH_BEGIN(pairs_tmp, char *, cp) { if (strlen(cp) != HEX_DIGEST_LEN*2+1) { log_info(LD_DIR, "Skipping digest pair %s with non-standard length.", escaped(cp)); } else if (cp[HEX_DIGEST_LEN] != '-') { log_info(LD_DIR, "Skipping digest pair %s with missing dash.", escaped(cp)); } else { fp_pair_t pair; if (base16_decode(pair.first, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0 || base16_decode(pair.second, DIGEST_LEN, cp+HEX_DIGEST_LEN+1, HEX_DIGEST_LEN)<0) { log_info(LD_DIR, "Skipping non-decodable digest pair %s", escaped(cp)); } else { smartlist_add(pairs_result, tor_memdup(&pair, sizeof(pair))); } } tor_free(cp); } SMARTLIST_FOREACH_END(cp); smartlist_free(pairs_tmp); /* Uniq-and-sort */ smartlist_sort(pairs_result, compare_pairs_); smartlist_uniq(pairs_result, compare_pairs_, tor_free_); smartlist_add_all(pairs_out, pairs_result); smartlist_free(pairs_result); return 0; } /** Given a directory resource request, containing zero * or more strings separated by plus signs, followed optionally by ".z", store * the strings, in order, into fp_out. If compressed_out is * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. * * If (flags & DSR_HEX), then delete all elements that aren't hex digests, and * decode the rest. If (flags & DSR_BASE64), then use "-" rather than "+" as * a separator, delete all the elements that aren't base64-encoded digests, * and decode the rest. If (flags & DSR_DIGEST256), these digests should be * 256 bits long; else they should be 160. * * If (flags & DSR_SORT_UNIQ), then sort the list and remove all duplicates. */ int dir_split_resource_into_fingerprints(const char *resource, smartlist_t *fp_out, int *compressed_out, int flags) { const int decode_hex = flags & DSR_HEX; const int decode_base64 = flags & DSR_BASE64; const int digests_are_256 = flags & DSR_DIGEST256; const int sort_uniq = flags & DSR_SORT_UNIQ; const int digest_len = digests_are_256 ? DIGEST256_LEN : DIGEST_LEN; const int hex_digest_len = digests_are_256 ? HEX_DIGEST256_LEN : HEX_DIGEST_LEN; const int base64_digest_len = digests_are_256 ? BASE64_DIGEST256_LEN : BASE64_DIGEST_LEN; smartlist_t *fp_tmp = smartlist_new(); tor_assert(!(decode_hex && decode_base64)); tor_assert(fp_out); smartlist_split_string(fp_tmp, resource, decode_base64?"-":"+", 0, 0); if (compressed_out) *compressed_out = 0; if (smartlist_len(fp_tmp)) { char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1); size_t last_len = strlen(last); if (last_len > 2 && !strcmp(last+last_len-2, ".z")) { last[last_len-2] = '\0'; if (compressed_out) *compressed_out = 1; } } if (decode_hex || decode_base64) { const size_t encoded_len = decode_hex ? hex_digest_len : base64_digest_len; int i; char *cp, *d = NULL; for (i = 0; i < smartlist_len(fp_tmp); ++i) { cp = smartlist_get(fp_tmp, i); if (strlen(cp) != encoded_len) { log_info(LD_DIR, "Skipping digest %s with non-standard length.", escaped(cp)); smartlist_del_keeporder(fp_tmp, i--); goto again; } d = tor_malloc_zero(digest_len); if (decode_hex ? (base16_decode(d, digest_len, cp, hex_digest_len)<0) : (base64_decode(d, digest_len, cp, base64_digest_len)<0)) { log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp)); smartlist_del_keeporder(fp_tmp, i--); goto again; } smartlist_set(fp_tmp, i, d); d = NULL; again: tor_free(cp); tor_free(d); } } if (sort_uniq) { if (decode_hex || decode_base64) { if (digests_are_256) { smartlist_sort_digests256(fp_tmp); smartlist_uniq_digests256(fp_tmp); } else { smartlist_sort_digests(fp_tmp); smartlist_uniq_digests(fp_tmp); } } else { smartlist_sort_strings(fp_tmp); smartlist_uniq_strings(fp_tmp); } } smartlist_add_all(fp_out, fp_tmp); smartlist_free(fp_tmp); return 0; } tor-0.2.4.20/src/or/fp_pair.h0000644000175000017500000000330712166112777012477 00000000000000/* Copyright (c) 2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file fp_pair.h * \brief Header file for fp_pair.c. **/ #ifndef _TOR_FP_PAIR_H #define _TOR_FP_PAIR_H /* * Declare fp_pair_map_t functions and structs */ typedef struct fp_pair_map_entry_s fp_pair_map_entry_t; typedef struct fp_pair_map_s fp_pair_map_t; typedef fp_pair_map_entry_t *fp_pair_map_iter_t; fp_pair_map_t * fp_pair_map_new(void); void * fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val); void * fp_pair_map_set_by_digests(fp_pair_map_t *map, const char *first, const char *second, void *val); void * fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key); void * fp_pair_map_get_by_digests(const fp_pair_map_t *map, const char *first, const char *second); void * fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key); void fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*)); int fp_pair_map_isempty(const fp_pair_map_t *map); int fp_pair_map_size(const fp_pair_map_t *map); fp_pair_map_iter_t * fp_pair_map_iter_init(fp_pair_map_t *map); fp_pair_map_iter_t * fp_pair_map_iter_next(fp_pair_map_t *map, fp_pair_map_iter_t *iter); fp_pair_map_iter_t * fp_pair_map_iter_next_rmv(fp_pair_map_t *map, fp_pair_map_iter_t *iter); void fp_pair_map_iter_get(fp_pair_map_iter_t *iter, fp_pair_t *key_out, void **val_out); int fp_pair_map_iter_done(fp_pair_map_iter_t *iter); void fp_pair_map_assert_ok(const fp_pair_map_t *map); #undef DECLARE_MAP_FNS #endif tor-0.2.4.20/src/or/onion_tap.c0000644000175000017500000001600312166112777013035 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file onion_tap.c * \brief Functions to implement the original Tor circuit extension handshake * (a.k.a TAP). * * We didn't call it "TAP" ourselves -- Ian Goldberg named it in "On the * Security of the Tor Authentication Protocol". (Spoiler: it's secure, but * its security is kind of fragile and implementation dependent. Never modify * this implementation without reading and understanding that paper at least.) **/ #include "or.h" #include "config.h" #include "onion_tap.h" #include "rephist.h" /*----------------------------------------------------------------------*/ /** Given a router's 128 byte public key, * stores the following in onion_skin_out: * - [42 bytes] OAEP padding * - [16 bytes] Symmetric key for encrypting blob past RSA * - [70 bytes] g^x part 1 (inside the RSA) * - [58 bytes] g^x part 2 (symmetrically encrypted) * * Stores the DH private key into handshake_state_out for later completion * of the handshake. * * The meeting point/cookies and auth are zeroed out for now. */ int onion_skin_TAP_create(crypto_pk_t *dest_router_key, crypto_dh_t **handshake_state_out, char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */ { char challenge[DH_KEY_LEN]; crypto_dh_t *dh = NULL; int dhbytes, pkbytes; tor_assert(dest_router_key); tor_assert(handshake_state_out); tor_assert(onion_skin_out); *handshake_state_out = NULL; memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN); if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT))) goto err; dhbytes = crypto_dh_get_bytes(dh); pkbytes = (int) crypto_pk_keysize(dest_router_key); tor_assert(dhbytes == 128); tor_assert(pkbytes == 128); if (crypto_dh_get_public(dh, challenge, dhbytes)) goto err; note_crypto_pk_op(ENC_ONIONSKIN); /* set meeting point, meeting cookie, etc here. Leave zero for now. */ if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out, TAP_ONIONSKIN_CHALLENGE_LEN, challenge, DH_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1)<0) goto err; memwipe(challenge, 0, sizeof(challenge)); *handshake_state_out = dh; return 0; err: memwipe(challenge, 0, sizeof(challenge)); if (dh) crypto_dh_free(dh); return -1; } /** Given an encrypted DH public key as generated by onion_skin_create, * and the private key for this onion router, generate the reply (128-byte * DH plus the first 20 bytes of shared key material), and store the * next key_out_len bytes of key material in key_out. */ int onion_skin_TAP_server_handshake( /*TAP_ONIONSKIN_CHALLENGE_LEN*/ const char *onion_skin, crypto_pk_t *private_key, crypto_pk_t *prev_private_key, /*TAP_ONIONSKIN_REPLY_LEN*/ char *handshake_reply_out, char *key_out, size_t key_out_len) { char challenge[TAP_ONIONSKIN_CHALLENGE_LEN]; crypto_dh_t *dh = NULL; ssize_t len; char *key_material=NULL; size_t key_material_len=0; int i; crypto_pk_t *k; len = -1; for (i=0;i<2;++i) { k = i==0?private_key:prev_private_key; if (!k) break; note_crypto_pk_op(DEC_ONIONSKIN); len = crypto_pk_private_hybrid_decrypt(k, challenge, TAP_ONIONSKIN_CHALLENGE_LEN, onion_skin, TAP_ONIONSKIN_CHALLENGE_LEN, PK_PKCS1_OAEP_PADDING,0); if (len>0) break; } if (len<0) { log_info(LD_PROTOCOL, "Couldn't decrypt onionskin: client may be using old onion key"); goto err; } else if (len != DH_KEY_LEN) { log_warn(LD_PROTOCOL, "Unexpected onionskin length after decryption: %ld", (long)len); goto err; } dh = crypto_dh_new(DH_TYPE_CIRCUIT); if (!dh) { log_warn(LD_BUG, "Couldn't allocate DH key"); goto err; } if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) { log_info(LD_GENERAL, "crypto_dh_get_public failed."); goto err; } key_material_len = DIGEST_LEN+key_out_len; key_material = tor_malloc(key_material_len); len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge, DH_KEY_LEN, key_material, key_material_len); if (len < 0) { log_info(LD_GENERAL, "crypto_dh_compute_secret failed."); goto err; } /* send back H(K|0) as proof that we learned K. */ memcpy(handshake_reply_out+DH_KEY_LEN, key_material, DIGEST_LEN); /* use the rest of the key material for our shared keys, digests, etc */ memcpy(key_out, key_material+DIGEST_LEN, key_out_len); memwipe(challenge, 0, sizeof(challenge)); memwipe(key_material, 0, key_material_len); tor_free(key_material); crypto_dh_free(dh); return 0; err: memwipe(challenge, 0, sizeof(challenge)); if (key_material) { memwipe(key_material, 0, key_material_len); tor_free(key_material); } if (dh) crypto_dh_free(dh); return -1; } /** Finish the client side of the DH handshake. * Given the 128 byte DH reply + 20 byte hash as generated by * onion_skin_server_handshake and the handshake state generated by * onion_skin_create, verify H(K) with the first 20 bytes of shared * key material, then generate key_out_len more bytes of shared key * material and store them in key_out. * * After the invocation, call crypto_dh_free on handshake_state. */ int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */ char *key_out, size_t key_out_len) { ssize_t len; char *key_material=NULL; size_t key_material_len; tor_assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN); key_material_len = DIGEST_LEN + key_out_len; key_material = tor_malloc(key_material_len); len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state, handshake_reply, DH_KEY_LEN, key_material, key_material_len); if (len < 0) goto err; if (tor_memneq(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) { /* H(K) does *not* match. Something fishy. */ log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on onion handshake. " "Bug or attack."); goto err; } /* use the rest of the key material for our shared keys, digests, etc */ memcpy(key_out, key_material+DIGEST_LEN, key_out_len); memwipe(key_material, 0, key_material_len); tor_free(key_material); return 0; err: memwipe(key_material, 0, key_material_len); tor_free(key_material); return -1; } tor-0.2.4.20/src/or/dns.c0000644000175000017500000022451312255745673011650 00000000000000/* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file dns.c * \brief Implements a local cache for DNS results for Tor servers. * This is implemented as a wrapper around Adam Langley's eventdns.c code. * (We can't just use gethostbyname() and friends because we really need to * be nonblocking.) **/ #include "or.h" #include "circuitlist.h" #include "circuituse.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "control.h" #include "dns.h" #include "main.h" #include "policies.h" #include "relay.h" #include "router.h" #include "ht.h" #ifdef HAVE_EVENT2_DNS_H #include #include #else #include #include "eventdns.h" #ifndef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS #define HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS #endif #endif #ifndef HAVE_EVENT2_DNS_H struct evdns_base; struct evdns_request; #define evdns_base_new(x,y) tor_malloc(1) #define evdns_base_clear_nameservers_and_suspend(base) \ evdns_clear_nameservers_and_suspend() #define evdns_base_search_clear(base) evdns_search_clear() #define evdns_base_set_default_outgoing_bind_address(base, a, len) \ evdns_set_default_outgoing_bind_address((a),(len)) #define evdns_base_resolv_conf_parse(base, options, fname) \ evdns_resolv_conf_parse((options), (fname)) #define evdns_base_count_nameservers(base) \ evdns_count_nameservers() #define evdns_base_resume(base) \ evdns_resume() #define evdns_base_config_windows_nameservers(base) \ evdns_config_windows_nameservers() #define evdns_base_set_option_(base, opt, val) \ evdns_set_option((opt),(val),DNS_OPTIONS_ALL) /* Note: our internal eventdns.c, plus Libevent 1.4, used a 1 return to * signify failure to launch a resolve. Libevent 2.0 uses a -1 return to * signify a failure on a resolve, though if we're on Libevent 2.0, we should * have event2/dns.h and never hit these macros. Regardless, 0 is success. */ #define evdns_base_resolve_ipv4(base, addr, options, cb, ptr) \ ((evdns_resolve_ipv4((addr), (options), (cb), (ptr))!=0) \ ? NULL : ((void*)1)) #define evdns_base_resolve_ipv6(base, addr, options, cb, ptr) \ ((evdns_resolve_ipv6((addr), (options), (cb), (ptr))!=0) \ ? NULL : ((void*)1)) #define evdns_base_resolve_reverse(base, addr, options, cb, ptr) \ ((evdns_resolve_reverse((addr), (options), (cb), (ptr))!=0) \ ? NULL : ((void*)1)) #define evdns_base_resolve_reverse_ipv6(base, addr, options, cb, ptr) \ ((evdns_resolve_reverse_ipv6((addr), (options), (cb), (ptr))!=0) \ ? NULL : ((void*)1)) #elif defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER < 0x02000303 #define evdns_base_set_option_(base, opt, val) \ evdns_base_set_option((base), (opt),(val),DNS_OPTIONS_ALL) #else #define evdns_base_set_option_ evdns_base_set_option #endif /** Longest hostname we're willing to resolve. */ #define MAX_ADDRESSLEN 256 /** How long will we wait for an answer from the resolver before we decide * that the resolver is wedged? */ #define RESOLVE_MAX_TIMEOUT 300 /** Our evdns_base; this structure handles all our name lookups. */ static struct evdns_base *the_evdns_base = NULL; /** Have we currently configured nameservers with eventdns? */ static int nameservers_configured = 0; /** Did our most recent attempt to configure nameservers with eventdns fail? */ static int nameserver_config_failed = 0; /** What was the resolv_conf fname we last used when configuring the * nameservers? Used to check whether we need to reconfigure. */ static char *resolv_conf_fname = NULL; /** What was the mtime on the resolv.conf file we last used when configuring * the nameservers? Used to check whether we need to reconfigure. */ static time_t resolv_conf_mtime = 0; /** Linked list of connections waiting for a DNS answer. */ typedef struct pending_connection_t { edge_connection_t *conn; struct pending_connection_t *next; } pending_connection_t; /** Value of 'magic' field for cached_resolve_t. Used to try to catch bad * pointers and memory stomping. */ #define CACHED_RESOLVE_MAGIC 0x1234F00D /* Possible states for a cached resolve_t */ /** We are waiting for the resolver system to tell us an answer here. * When we get one, or when we time out, the state of this cached_resolve_t * will become "DONE" and we'll possibly add a CACHED * entry. This cached_resolve_t will be in the hash table so that we will * know not to launch more requests for this addr, but rather to add more * connections to the pending list for the addr. */ #define CACHE_STATE_PENDING 0 /** This used to be a pending cached_resolve_t, and we got an answer for it. * Now we're waiting for this cached_resolve_t to expire. This should * have no pending connections, and should not appear in the hash table. */ #define CACHE_STATE_DONE 1 /** We are caching an answer for this address. This should have no pending * connections, and should appear in the hash table. */ #define CACHE_STATE_CACHED 2 /** @name status values for a single DNS request. * * @{ */ /** The DNS request is in progress. */ #define RES_STATUS_INFLIGHT 1 /** The DNS request finished and gave an answer */ #define RES_STATUS_DONE_OK 2 /** The DNS request finished and gave an error */ #define RES_STATUS_DONE_ERR 3 /**@}*/ /** A DNS request: possibly completed, possibly pending; cached_resolve * structs are stored at the OR side in a hash table, and as a linked * list from oldest to newest. */ typedef struct cached_resolve_t { HT_ENTRY(cached_resolve_t) node; uint32_t magic; /**< Must be CACHED_RESOLVE_MAGIC */ char address[MAX_ADDRESSLEN]; /**< The hostname to be resolved. */ union { uint32_t addr_ipv4; /**< IPv4 addr for address, if successful. * (In host order.) */ int err_ipv4; /**< One of DNS_ERR_*, if IPv4 lookup failed. */ } result_ipv4; /**< Outcome of IPv4 lookup */ union { struct in6_addr addr_ipv6; /**< IPv6 addr for address, if * successful */ int err_ipv6; /**< One of DNS_ERR_*, if IPv6 lookup failed. */ } result_ipv6; /**< Outcome of IPv6 lookup, if any */ union { char *hostname; /** A hostname, if PTR lookup happened successfully*/ int err_hostname; /** One of DNS_ERR_*, if PTR lookup failed. */ } result_ptr; /** @name Status fields * * These take one of the RES_STATUS_* values, depending on the state * of the corresponding lookup. * * @{ */ unsigned int res_status_ipv4 : 2; unsigned int res_status_ipv6 : 2; unsigned int res_status_hostname : 2; /**@}*/ uint8_t state; /**< Is this cached entry pending/done/informative? */ time_t expire; /**< Remove items from cache after this time. */ uint32_t ttl_ipv4; /**< What TTL did the nameserver tell us? */ uint32_t ttl_ipv6; /**< What TTL did the nameserver tell us? */ uint32_t ttl_hostname; /**< What TTL did the nameserver tell us? */ /** Connections that want to know when we get an answer for this resolve. */ pending_connection_t *pending_connections; /** Position of this element in the heap*/ int minheap_idx; } cached_resolve_t; static void purge_expired_resolves(time_t now); static void dns_found_answer(const char *address, uint8_t query_type, int dns_answer, const tor_addr_t *addr, const char *hostname, uint32_t ttl); static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type, const cached_resolve_t *resolve); static int launch_resolve(cached_resolve_t *resolve); static void add_wildcarded_test_address(const char *address); static int configure_nameservers(int force); static int answer_is_wildcarded(const char *ip); static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, or_circuit_t *oncirc, char **resolved_to_hostname, int *made_connection_pending_out, cached_resolve_t **resolve_out); static int set_exitconn_info_from_resolve(edge_connection_t *exitconn, const cached_resolve_t *resolve, char **hostname_out); static int evdns_err_is_transient(int err); static void inform_pending_connections(cached_resolve_t *resolve); static void make_pending_resolve_cached(cached_resolve_t *cached); #ifdef DEBUG_DNS_CACHE static void assert_cache_ok_(void); #define assert_cache_ok() assert_cache_ok_() #else #define assert_cache_ok() STMT_NIL #endif static void assert_resolve_ok(cached_resolve_t *resolve); /** Hash table of cached_resolve objects. */ static HT_HEAD(cache_map, cached_resolve_t) cache_root; /** Global: how many IPv6 requests have we made in all? */ static uint64_t n_ipv6_requests_made = 0; /** Global: how many IPv6 requests have timed out? */ static uint64_t n_ipv6_timeouts = 0; /** Global: Do we think that IPv6 DNS is broken? */ static int dns_is_broken_for_ipv6 = 0; /** Function to compare hashed resolves on their addresses; used to * implement hash tables. */ static INLINE int cached_resolves_eq(cached_resolve_t *a, cached_resolve_t *b) { /* make this smarter one day? */ assert_resolve_ok(a); // Not b; b may be just a search. return !strncmp(a->address, b->address, MAX_ADDRESSLEN); } /** Hash function for cached_resolve objects */ static INLINE unsigned int cached_resolve_hash(cached_resolve_t *a) { return ht_string_hash(a->address); } HT_PROTOTYPE(cache_map, cached_resolve_t, node, cached_resolve_hash, cached_resolves_eq) HT_GENERATE(cache_map, cached_resolve_t, node, cached_resolve_hash, cached_resolves_eq, 0.6, malloc, realloc, free) /** Initialize the DNS cache. */ static void init_cache_map(void) { HT_INIT(cache_map, &cache_root); } /** Helper: called by eventdns when eventdns wants to log something. */ static void evdns_log_cb(int warn, const char *msg) { const char *cp; static int all_down = 0; int severity = warn ? LOG_WARN : LOG_INFO; if (!strcmpstart(msg, "Resolve requested for") && get_options()->SafeLogging) { log_info(LD_EXIT, "eventdns: Resolve requested."); return; } else if (!strcmpstart(msg, "Search: ")) { return; } if (!strcmpstart(msg, "Nameserver ") && (cp=strstr(msg, " has failed: "))) { char *ns = tor_strndup(msg+11, cp-(msg+11)); const char *err = strchr(cp, ':')+2; tor_assert(err); /* Don't warn about a single failed nameserver; we'll warn with 'all * nameservers have failed' if we're completely out of nameservers; * otherwise, the situation is tolerable. */ severity = LOG_INFO; control_event_server_status(LOG_NOTICE, "NAMESERVER_STATUS NS=%s STATUS=DOWN ERR=%s", ns, escaped(err)); tor_free(ns); } else if (!strcmpstart(msg, "Nameserver ") && (cp=strstr(msg, " is back up"))) { char *ns = tor_strndup(msg+11, cp-(msg+11)); severity = (all_down && warn) ? LOG_NOTICE : LOG_INFO; all_down = 0; control_event_server_status(LOG_NOTICE, "NAMESERVER_STATUS NS=%s STATUS=UP", ns); tor_free(ns); } else if (!strcmp(msg, "All nameservers have failed")) { control_event_server_status(LOG_WARN, "NAMESERVER_ALL_DOWN"); all_down = 1; } tor_log(severity, LD_EXIT, "eventdns: %s", msg); } /** Helper: passed to eventdns.c as a callback so it can generate random * numbers for transaction IDs and 0x20-hack coding. */ static void dns_randfn_(char *b, size_t n) { crypto_rand(b,n); } /** Initialize the DNS subsystem; called by the OR process. */ int dns_init(void) { init_cache_map(); evdns_set_random_bytes_fn(dns_randfn_); if (server_mode(get_options())) { int r = configure_nameservers(1); return r; } return 0; } /** Called when DNS-related options change (or may have changed). Returns -1 * on failure, 0 on success. */ int dns_reset(void) { const or_options_t *options = get_options(); if (! server_mode(options)) { if (!the_evdns_base) { if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) { log_err(LD_BUG, "Couldn't create an evdns_base"); return -1; } } evdns_base_clear_nameservers_and_suspend(the_evdns_base); evdns_base_search_clear(the_evdns_base); nameservers_configured = 0; tor_free(resolv_conf_fname); resolv_conf_mtime = 0; } else { if (configure_nameservers(0) < 0) { return -1; } } return 0; } /** Return true iff the most recent attempt to initialize the DNS subsystem * failed. */ int has_dns_init_failed(void) { return nameserver_config_failed; } /** Helper: Given a TTL from a DNS response, determine what TTL to give the * OP that asked us to resolve it. */ uint32_t dns_clip_ttl(uint32_t ttl) { if (ttl < MIN_DNS_TTL) return MIN_DNS_TTL; else if (ttl > MAX_DNS_TTL) return MAX_DNS_TTL; else return ttl; } /** Helper: Given a TTL from a DNS response, determine how long to hold it in * our cache. */ static uint32_t dns_get_expiry_ttl(uint32_t ttl) { if (ttl < MIN_DNS_TTL) return MIN_DNS_TTL; else if (ttl > MAX_DNS_ENTRY_AGE) return MAX_DNS_ENTRY_AGE; else return ttl; } /** Helper: free storage held by an entry in the DNS cache. */ static void free_cached_resolve_(cached_resolve_t *r) { if (!r) return; while (r->pending_connections) { pending_connection_t *victim = r->pending_connections; r->pending_connections = victim->next; tor_free(victim); } if (r->res_status_hostname == RES_STATUS_DONE_OK) tor_free(r->result_ptr.hostname); r->magic = 0xFF00FF00; tor_free(r); } /** Compare two cached_resolve_t pointers by expiry time, and return * less-than-zero, zero, or greater-than-zero as appropriate. Used for * the priority queue implementation. */ static int compare_cached_resolves_by_expiry_(const void *_a, const void *_b) { const cached_resolve_t *a = _a, *b = _b; if (a->expire < b->expire) return -1; else if (a->expire == b->expire) return 0; else return 1; } /** Priority queue of cached_resolve_t objects to let us know when they * will expire. */ static smartlist_t *cached_resolve_pqueue = NULL; static void cached_resolve_add_answer(cached_resolve_t *resolve, int query_type, int dns_result, const tor_addr_t *answer_addr, const char *answer_hostname, uint32_t ttl) { if (query_type == DNS_PTR) { if (resolve->res_status_hostname != RES_STATUS_INFLIGHT) return; if (dns_result == DNS_ERR_NONE && answer_hostname) { resolve->result_ptr.hostname = tor_strdup(answer_hostname); resolve->res_status_hostname = RES_STATUS_DONE_OK; } else { resolve->result_ptr.err_hostname = dns_result; resolve->res_status_hostname = RES_STATUS_DONE_ERR; } resolve->ttl_hostname = ttl; } else if (query_type == DNS_IPv4_A) { if (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT) return; if (dns_result == DNS_ERR_NONE && answer_addr && tor_addr_family(answer_addr) == AF_INET) { resolve->result_ipv4.addr_ipv4 = tor_addr_to_ipv4h(answer_addr); resolve->res_status_ipv4 = RES_STATUS_DONE_OK; } else { resolve->result_ipv4.err_ipv4 = dns_result; resolve->res_status_ipv4 = RES_STATUS_DONE_ERR; } } else if (query_type == DNS_IPv6_AAAA) { if (resolve->res_status_ipv6 != RES_STATUS_INFLIGHT) return; if (dns_result == DNS_ERR_NONE && answer_addr && tor_addr_family(answer_addr) == AF_INET6) { memcpy(&resolve->result_ipv6.addr_ipv6, tor_addr_to_in6(answer_addr), sizeof(struct in6_addr)); resolve->res_status_ipv6 = RES_STATUS_DONE_OK; } else { resolve->result_ipv6.err_ipv6 = dns_result; resolve->res_status_ipv6 = RES_STATUS_DONE_ERR; } } } /** Return true iff there are no in-flight requests for resolve. */ static int cached_resolve_have_all_answers(const cached_resolve_t *resolve) { return (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT && resolve->res_status_ipv6 != RES_STATUS_INFLIGHT && resolve->res_status_hostname != RES_STATUS_INFLIGHT); } /** Set an expiry time for a cached_resolve_t, and add it to the expiry * priority queue */ static void set_expiry(cached_resolve_t *resolve, time_t expires) { tor_assert(resolve && resolve->expire == 0); if (!cached_resolve_pqueue) cached_resolve_pqueue = smartlist_new(); resolve->expire = expires; smartlist_pqueue_add(cached_resolve_pqueue, compare_cached_resolves_by_expiry_, STRUCT_OFFSET(cached_resolve_t, minheap_idx), resolve); } /** Free all storage held in the DNS cache and related structures. */ void dns_free_all(void) { cached_resolve_t **ptr, **next, *item; assert_cache_ok(); if (cached_resolve_pqueue) { SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res, { if (res->state == CACHE_STATE_DONE) free_cached_resolve_(res); }); } for (ptr = HT_START(cache_map, &cache_root); ptr != NULL; ptr = next) { item = *ptr; next = HT_NEXT_RMV(cache_map, &cache_root, ptr); free_cached_resolve_(item); } HT_CLEAR(cache_map, &cache_root); smartlist_free(cached_resolve_pqueue); cached_resolve_pqueue = NULL; tor_free(resolv_conf_fname); } /** Remove every cached_resolve whose expire time is before or * equal to now from the cache. */ static void purge_expired_resolves(time_t now) { cached_resolve_t *resolve, *removed; pending_connection_t *pend; edge_connection_t *pendconn; assert_cache_ok(); if (!cached_resolve_pqueue) return; while (smartlist_len(cached_resolve_pqueue)) { resolve = smartlist_get(cached_resolve_pqueue, 0); if (resolve->expire > now) break; smartlist_pqueue_pop(cached_resolve_pqueue, compare_cached_resolves_by_expiry_, STRUCT_OFFSET(cached_resolve_t, minheap_idx)); if (resolve->state == CACHE_STATE_PENDING) { log_debug(LD_EXIT, "Expiring a dns resolve %s that's still pending. Forgot to " "cull it? DNS resolve didn't tell us about the timeout?", escaped_safe_str(resolve->address)); } else if (resolve->state == CACHE_STATE_CACHED) { log_debug(LD_EXIT, "Forgetting old cached resolve (address %s, expires %lu)", escaped_safe_str(resolve->address), (unsigned long)resolve->expire); tor_assert(!resolve->pending_connections); } else { tor_assert(resolve->state == CACHE_STATE_DONE); tor_assert(!resolve->pending_connections); } if (resolve->pending_connections) { log_debug(LD_EXIT, "Closing pending connections on timed-out DNS resolve!"); while (resolve->pending_connections) { pend = resolve->pending_connections; resolve->pending_connections = pend->next; /* Connections should only be pending if they have no socket. */ tor_assert(!SOCKET_OK(pend->conn->base_.s)); pendconn = pend->conn; if (!pendconn->base_.marked_for_close) { connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT); circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); connection_free(TO_CONN(pendconn)); } tor_free(pend); } } if (resolve->state == CACHE_STATE_CACHED || resolve->state == CACHE_STATE_PENDING) { removed = HT_REMOVE(cache_map, &cache_root, resolve); if (removed != resolve) { log_err(LD_BUG, "The expired resolve we purged didn't match any in" " the cache. Tried to purge %s (%p); instead got %s (%p).", resolve->address, (void*)resolve, removed ? removed->address : "NULL", (void*)removed); } tor_assert(removed == resolve); } else { /* This should be in state DONE. Make sure it's not in the cache. */ cached_resolve_t *tmp = HT_FIND(cache_map, &cache_root, resolve); tor_assert(tmp != resolve); } if (resolve->res_status_hostname == RES_STATUS_DONE_OK) tor_free(resolve->result_ptr.hostname); resolve->magic = 0xF0BBF0BB; tor_free(resolve); } assert_cache_ok(); } /* argument for send_resolved_cell only, meaning "let the answer type be ipv4 * or ipv6 depending on the connection's address". */ #define RESOLVED_TYPE_AUTO 0xff /** Send a response to the RESOLVE request of a connection. * answer_type must be one of * RESOLVED_TYPE_(AUTO|ERROR|ERROR_TRANSIENT|). * * If circ is provided, and we have a cached answer, send the * answer back along circ; otherwise, send the answer back along * conn's attached circuit. */ static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type, const cached_resolve_t *resolved) { char buf[RELAY_PAYLOAD_SIZE], *cp = buf; size_t buflen = 0; uint32_t ttl; buf[0] = answer_type; ttl = dns_clip_ttl(conn->address_ttl); switch (answer_type) { case RESOLVED_TYPE_AUTO: if (resolved && resolved->res_status_ipv4 == RES_STATUS_DONE_OK) { cp[0] = RESOLVED_TYPE_IPV4; cp[1] = 4; set_uint32(cp+2, htonl(resolved->result_ipv4.addr_ipv4)); set_uint32(cp+6, htonl(ttl)); cp += 10; } if (resolved && resolved->res_status_ipv6 == RES_STATUS_DONE_OK) { const uint8_t *bytes = resolved->result_ipv6.addr_ipv6.s6_addr; cp[0] = RESOLVED_TYPE_IPV6; cp[1] = 16; memcpy(cp+2, bytes, 16); set_uint32(cp+18, htonl(ttl)); cp += 22; } if (cp != buf) { buflen = cp - buf; break; } else { answer_type = RESOLVED_TYPE_ERROR; /* fall through. */ } case RESOLVED_TYPE_ERROR_TRANSIENT: case RESOLVED_TYPE_ERROR: { const char *errmsg = "Error resolving hostname"; size_t msglen = strlen(errmsg); buf[0] = answer_type; buf[1] = msglen; strlcpy(buf+2, errmsg, sizeof(buf)-2); set_uint32(buf+2+msglen, htonl(ttl)); buflen = 6+msglen; break; } default: tor_assert(0); return; } // log_notice(LD_EXIT, "Sending a regular RESOLVED reply: "); connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen); } /** Send a response to the RESOLVE request of a connection for an in-addr.arpa * address on connection conn which yielded the result hostname. * The answer type will be RESOLVED_HOSTNAME. * * If circ is provided, and we have a cached answer, send the * answer back along circ; otherwise, send the answer back along * conn's attached circuit. */ static void send_resolved_hostname_cell(edge_connection_t *conn, const char *hostname) { char buf[RELAY_PAYLOAD_SIZE]; size_t buflen; uint32_t ttl; size_t namelen = strlen(hostname); tor_assert(hostname); tor_assert(namelen < 256); ttl = dns_clip_ttl(conn->address_ttl); buf[0] = RESOLVED_TYPE_HOSTNAME; buf[1] = (uint8_t)namelen; memcpy(buf+2, hostname, namelen); set_uint32(buf+2+namelen, htonl(ttl)); buflen = 2+namelen+4; // log_notice(LD_EXIT, "Sending a reply RESOLVED reply: %s", hostname); connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen); // log_notice(LD_EXIT, "Sent"); } /** See if we have a cache entry for exitconn-\>address. If so, * if resolve valid, put it into exitconn-\>addr and return 1. * If resolve failed, free exitconn and return -1. * * (For EXIT_PURPOSE_RESOLVE connections, send back a RESOLVED error cell * on returning -1. For EXIT_PURPOSE_CONNECT connections, there's no * need to send back an END cell, since connection_exit_begin_conn will * do that for us.) * * If we have a cached answer, send the answer back along exitconn's * circuit. * * Else, if seen before and pending, add conn to the pending list, * and return 0. * * Else, if not seen before, add conn to pending list, hand to * dns farm, and return 0. * * Exitconn's on_circuit field must be set, but exitconn should not * yet be linked onto the n_streams/resolving_streams list of that circuit. * On success, link the connection to n_streams if it's an exit connection. * On "pending", link the connection to resolving streams. Otherwise, * clear its on_circuit field. */ int dns_resolve(edge_connection_t *exitconn) { or_circuit_t *oncirc = TO_OR_CIRCUIT(exitconn->on_circuit); int is_resolve, r; int made_connection_pending = 0; char *hostname = NULL; cached_resolve_t *resolve = NULL; is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE; r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname, &made_connection_pending, &resolve); switch (r) { case 1: /* We got an answer without a lookup -- either the answer was * cached, or it was obvious (like an IP address). */ if (is_resolve) { /* Send the answer back right now, and detach. */ if (hostname) send_resolved_hostname_cell(exitconn, hostname); else send_resolved_cell(exitconn, RESOLVED_TYPE_AUTO, resolve); exitconn->on_circuit = NULL; } else { /* Add to the n_streams list; the calling function will send back a * connected cell. */ exitconn->next_stream = oncirc->n_streams; oncirc->n_streams = exitconn; } break; case 0: /* The request is pending: add the connection into the linked list of * resolving_streams on this circuit. */ exitconn->base_.state = EXIT_CONN_STATE_RESOLVING; exitconn->next_stream = oncirc->resolving_streams; oncirc->resolving_streams = exitconn; break; case -2: case -1: /* The request failed before it could start: cancel this connection, * and stop everybody waiting for the same connection. */ if (is_resolve) { send_resolved_cell(exitconn, (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT, NULL); } exitconn->on_circuit = NULL; dns_cancel_pending_resolve(exitconn->base_.address); if (!made_connection_pending && !exitconn->base_.marked_for_close) { /* If we made the connection pending, then we freed it already in * dns_cancel_pending_resolve(). If we marked it for close, it'll * get freed from the main loop. Otherwise, can free it now. */ connection_free(TO_CONN(exitconn)); } break; default: tor_assert(0); } tor_free(hostname); return r; } /** Helper function for dns_resolve: same functionality, but does not handle: * - marking connections on error and clearing their on_circuit * - linking connections to n_streams/resolving_streams, * - sending resolved cells if we have an answer/error right away, * * Return -2 on a transient error. If it's a reverse resolve and it's * successful, sets *hostname_out to a newly allocated string * holding the cached reverse DNS value. * * Set *made_connection_pending_out to true if we have placed * exitconn on the list of pending connections for some resolve; set it * to false otherwise. * * Set *resolve_out to a cached resolve, if we found one. */ static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, or_circuit_t *oncirc, char **hostname_out, int *made_connection_pending_out, cached_resolve_t **resolve_out) { cached_resolve_t *resolve; cached_resolve_t search; pending_connection_t *pending_connection; int is_reverse = 0; tor_addr_t addr; time_t now = time(NULL); int r; assert_connection_ok(TO_CONN(exitconn), 0); tor_assert(!SOCKET_OK(exitconn->base_.s)); assert_cache_ok(); tor_assert(oncirc); *made_connection_pending_out = 0; /* first check if exitconn->base_.address is an IP. If so, we already * know the answer. */ if (tor_addr_parse(&addr, exitconn->base_.address) >= 0) { if (tor_addr_family(&addr) == AF_INET || tor_addr_family(&addr) == AF_INET6) { tor_addr_copy(&exitconn->base_.addr, &addr); exitconn->address_ttl = DEFAULT_DNS_TTL; return 1; } else { /* XXXX unspec? Bogus? */ return -1; } } /* If we're a non-exit, don't even do DNS lookups. */ if (router_my_exit_policy_is_reject_star()) return -1; if (address_is_invalid_destination(exitconn->base_.address, 0)) { tor_log(LOG_PROTOCOL_WARN, LD_EXIT, "Rejecting invalid destination address %s", escaped_safe_str(exitconn->base_.address)); return -1; } /* then take this opportunity to see if there are any expired * resolves in the hash table. */ purge_expired_resolves(now); /* lower-case exitconn->base_.address, so it's in canonical form */ tor_strlower(exitconn->base_.address); /* Check whether this is a reverse lookup. If it's malformed, or it's a * .in-addr.arpa address but this isn't a resolve request, kill the * connection. */ if ((r = tor_addr_parse_PTR_name(&addr, exitconn->base_.address, AF_UNSPEC, 0)) != 0) { if (r == 1) { is_reverse = 1; if (tor_addr_is_internal(&addr, 0)) /* internal address? */ return -1; } if (!is_reverse || !is_resolve) { if (!is_reverse) log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.", escaped_safe_str(exitconn->base_.address)); else if (!is_resolve) log_info(LD_EXIT, "Attempt to connect to a .in-addr.arpa address \"%s\"; " "sending error.", escaped_safe_str(exitconn->base_.address)); return -1; } //log_notice(LD_EXIT, "Looks like an address %s", //exitconn->base_.address); } exitconn->is_reverse_dns_lookup = is_reverse; /* now check the hash table to see if 'address' is already there. */ strlcpy(search.address, exitconn->base_.address, sizeof(search.address)); resolve = HT_FIND(cache_map, &cache_root, &search); if (resolve && resolve->expire > now) { /* already there */ switch (resolve->state) { case CACHE_STATE_PENDING: /* add us to the pending list */ pending_connection = tor_malloc_zero( sizeof(pending_connection_t)); pending_connection->conn = exitconn; pending_connection->next = resolve->pending_connections; resolve->pending_connections = pending_connection; *made_connection_pending_out = 1; log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") waiting " "for pending DNS resolve of %s", exitconn->base_.s, escaped_safe_str(exitconn->base_.address)); return 0; case CACHE_STATE_CACHED: log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") found " "cached answer for %s", exitconn->base_.s, escaped_safe_str(resolve->address)); *resolve_out = resolve; return set_exitconn_info_from_resolve(exitconn, resolve, hostname_out); case CACHE_STATE_DONE: log_err(LD_BUG, "Found a 'DONE' dns resolve still in the cache."); tor_fragile_assert(); } tor_assert(0); } tor_assert(!resolve); /* not there, need to add it */ resolve = tor_malloc_zero(sizeof(cached_resolve_t)); resolve->magic = CACHED_RESOLVE_MAGIC; resolve->state = CACHE_STATE_PENDING; resolve->minheap_idx = -1; strlcpy(resolve->address, exitconn->base_.address, sizeof(resolve->address)); /* add this connection to the pending list */ pending_connection = tor_malloc_zero(sizeof(pending_connection_t)); pending_connection->conn = exitconn; resolve->pending_connections = pending_connection; *made_connection_pending_out = 1; /* Add this resolve to the cache and priority queue. */ HT_INSERT(cache_map, &cache_root, resolve); set_expiry(resolve, now + RESOLVE_MAX_TIMEOUT); log_debug(LD_EXIT,"Launching %s.", escaped_safe_str(exitconn->base_.address)); assert_cache_ok(); return launch_resolve(resolve); } /** Given an exit connection exitconn, and a cached_resolve_t * resolve whose DNS lookups have all succeeded or failed, update the * appropriate fields (address_ttl and addr) of exitconn. * * If this is a reverse lookup, set *hostname_out to a newly allocated * copy of the name resulting hostname. * * Return -2 on a transient error, -1 on a permenent error, and 1 on * a successful lookup. */ static int set_exitconn_info_from_resolve(edge_connection_t *exitconn, const cached_resolve_t *resolve, char **hostname_out) { int ipv4_ok, ipv6_ok, answer_with_ipv4, r; uint32_t begincell_flags; const int is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE; tor_assert(exitconn); tor_assert(resolve); if (exitconn->is_reverse_dns_lookup) { exitconn->address_ttl = resolve->ttl_hostname; if (resolve->res_status_hostname == RES_STATUS_DONE_OK) { *hostname_out = tor_strdup(resolve->result_ptr.hostname); return 1; } else { return -1; } } /* If we're here then the connection wants one or either of ipv4, ipv6, and * we can give it one or both. */ if (is_resolve) { begincell_flags = BEGIN_FLAG_IPV6_OK; } else { begincell_flags = exitconn->begincell_flags; } ipv4_ok = (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) && ! (begincell_flags & BEGIN_FLAG_IPV4_NOT_OK); ipv6_ok = (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) && (begincell_flags & BEGIN_FLAG_IPV6_OK) && get_options()->IPv6Exit; /* Now decide which one to actually give. */ if (ipv4_ok && ipv6_ok && is_resolve) { answer_with_ipv4 = 1; } else if (ipv4_ok && ipv6_ok) { /* If we have both, see if our exit policy has an opinion. */ const uint16_t port = exitconn->base_.port; int ipv4_allowed, ipv6_allowed; tor_addr_t a4, a6; tor_addr_from_ipv4h(&a4, resolve->result_ipv4.addr_ipv4); tor_addr_from_in6(&a6, &resolve->result_ipv6.addr_ipv6); ipv4_allowed = !router_compare_to_my_exit_policy(&a4, port); ipv6_allowed = !router_compare_to_my_exit_policy(&a6, port); if (ipv4_allowed && !ipv6_allowed) { answer_with_ipv4 = 1; } else if (ipv6_allowed && !ipv4_allowed) { answer_with_ipv4 = 0; } else { /* Our exit policy would permit both. Answer with whichever the user * prefers */ answer_with_ipv4 = !(begincell_flags & BEGIN_FLAG_IPV6_PREFERRED); } } else { /* Otherwise if one is okay, send it back. */ if (ipv4_ok) { answer_with_ipv4 = 1; } else if (ipv6_ok) { answer_with_ipv4 = 0; } else { /* Neither one was okay. Choose based on user preference. */ answer_with_ipv4 = !(begincell_flags & BEGIN_FLAG_IPV6_PREFERRED); } } /* Finally, we write the answer back. */ r = 1; if (answer_with_ipv4) { if (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) { tor_addr_from_ipv4h(&exitconn->base_.addr, resolve->result_ipv4.addr_ipv4); } else { r = evdns_err_is_transient(resolve->result_ipv4.err_ipv4) ? -2 : -1; } exitconn->address_ttl = resolve->ttl_ipv4; } else { if (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) { tor_addr_from_in6(&exitconn->base_.addr, &resolve->result_ipv6.addr_ipv6); } else { r = evdns_err_is_transient(resolve->result_ipv6.err_ipv6) ? -2 : -1; } exitconn->address_ttl = resolve->ttl_ipv6; } return r; } /** Log an error and abort if conn is waiting for a DNS resolve. */ void assert_connection_edge_not_dns_pending(edge_connection_t *conn) { pending_connection_t *pend; cached_resolve_t search; #if 1 cached_resolve_t *resolve; strlcpy(search.address, conn->base_.address, sizeof(search.address)); resolve = HT_FIND(cache_map, &cache_root, &search); if (!resolve) return; for (pend = resolve->pending_connections; pend; pend = pend->next) { tor_assert(pend->conn != conn); } #else cached_resolve_t **resolve; HT_FOREACH(resolve, cache_map, &cache_root) { for (pend = (*resolve)->pending_connections; pend; pend = pend->next) { tor_assert(pend->conn != conn); } } #endif } /** Log an error and abort if any connection waiting for a DNS resolve is * corrupted. */ void assert_all_pending_dns_resolves_ok(void) { pending_connection_t *pend; cached_resolve_t **resolve; HT_FOREACH(resolve, cache_map, &cache_root) { for (pend = (*resolve)->pending_connections; pend; pend = pend->next) { assert_connection_ok(TO_CONN(pend->conn), 0); tor_assert(!SOCKET_OK(pend->conn->base_.s)); tor_assert(!connection_in_array(TO_CONN(pend->conn))); } } } /** Remove conn from the list of connections waiting for conn-\>address. */ void connection_dns_remove(edge_connection_t *conn) { pending_connection_t *pend, *victim; cached_resolve_t search; cached_resolve_t *resolve; tor_assert(conn->base_.type == CONN_TYPE_EXIT); tor_assert(conn->base_.state == EXIT_CONN_STATE_RESOLVING); strlcpy(search.address, conn->base_.address, sizeof(search.address)); resolve = HT_FIND(cache_map, &cache_root, &search); if (!resolve) { log_notice(LD_BUG, "Address %s is not pending. Dropping.", escaped_safe_str(conn->base_.address)); return; } tor_assert(resolve->pending_connections); assert_connection_ok(TO_CONN(conn),0); pend = resolve->pending_connections; if (pend->conn == conn) { resolve->pending_connections = pend->next; tor_free(pend); log_debug(LD_EXIT, "First connection (fd "TOR_SOCKET_T_FORMAT") no " "longer waiting for resolve of %s", conn->base_.s, escaped_safe_str(conn->base_.address)); return; } else { for ( ; pend->next; pend = pend->next) { if (pend->next->conn == conn) { victim = pend->next; pend->next = victim->next; tor_free(victim); log_debug(LD_EXIT, "Connection (fd "TOR_SOCKET_T_FORMAT") no longer waiting " "for resolve of %s", conn->base_.s, escaped_safe_str(conn->base_.address)); return; /* more are pending */ } } tor_assert(0); /* not reachable unless onlyconn not in pending list */ } } /** Mark all connections waiting for address for close. Then cancel * the resolve for address itself, and remove any cached results for * address from the cache. */ void dns_cancel_pending_resolve(const char *address) { pending_connection_t *pend; cached_resolve_t search; cached_resolve_t *resolve, *tmp; edge_connection_t *pendconn; circuit_t *circ; strlcpy(search.address, address, sizeof(search.address)); resolve = HT_FIND(cache_map, &cache_root, &search); if (!resolve) return; if (resolve->state != CACHE_STATE_PENDING) { /* We can get into this state if we never actually created the pending * resolve, due to finding an earlier cached error or something. Just * ignore it. */ if (resolve->pending_connections) { log_warn(LD_BUG, "Address %s is not pending but has pending connections!", escaped_safe_str(address)); tor_fragile_assert(); } return; } if (!resolve->pending_connections) { log_warn(LD_BUG, "Address %s is pending but has no pending connections!", escaped_safe_str(address)); tor_fragile_assert(); return; } tor_assert(resolve->pending_connections); /* mark all pending connections to fail */ log_debug(LD_EXIT, "Failing all connections waiting on DNS resolve of %s", escaped_safe_str(address)); while (resolve->pending_connections) { pend = resolve->pending_connections; pend->conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; pendconn = pend->conn; assert_connection_ok(TO_CONN(pendconn), 0); tor_assert(!SOCKET_OK(pendconn->base_.s)); if (!pendconn->base_.marked_for_close) { connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED); } circ = circuit_get_by_edge_conn(pendconn); if (circ) circuit_detach_stream(circ, pendconn); if (!pendconn->base_.marked_for_close) connection_free(TO_CONN(pendconn)); resolve->pending_connections = pend->next; tor_free(pend); } tmp = HT_REMOVE(cache_map, &cache_root, resolve); if (tmp != resolve) { log_err(LD_BUG, "The cancelled resolve we purged didn't match any in" " the cache. Tried to purge %s (%p); instead got %s (%p).", resolve->address, (void*)resolve, tmp ? tmp->address : "NULL", (void*)tmp); } tor_assert(tmp == resolve); resolve->state = CACHE_STATE_DONE; } /** Return true iff address is one of the addresses we use to verify * that well-known sites aren't being hijacked by our DNS servers. */ static INLINE int is_test_address(const char *address) { const or_options_t *options = get_options(); return options->ServerDNSTestAddresses && smartlist_contains_string_case(options->ServerDNSTestAddresses, address); } /** Called on the OR side when the eventdns library tells us the outcome of a * single DNS resolve: remember the answer, and tell all pending connections * about the result of the lookup if the lookup is now done. (address * is a NUL-terminated string containing the address to look up; * query_type is one of DNS_{IPv4_A,IPv6_AAAA,PTR}; dns_answer * is DNS_OK or one of DNS_ERR_*, addr is an IPv4 or IPv6 address if we * got one; hostname is a hostname fora PTR request if we got one, and * ttl is the time-to-live of this answer, in seconds.) */ static void dns_found_answer(const char *address, uint8_t query_type, int dns_answer, const tor_addr_t *addr, const char *hostname, uint32_t ttl) { cached_resolve_t search; cached_resolve_t *resolve; assert_cache_ok(); strlcpy(search.address, address, sizeof(search.address)); resolve = HT_FIND(cache_map, &cache_root, &search); if (!resolve) { int is_test_addr = is_test_address(address); if (!is_test_addr) log_info(LD_EXIT,"Resolved unasked address %s; ignoring.", escaped_safe_str(address)); return; } assert_resolve_ok(resolve); if (resolve->state != CACHE_STATE_PENDING) { /* XXXX Maybe update addr? or check addr for consistency? Or let * VALID replace FAILED? */ int is_test_addr = is_test_address(address); if (!is_test_addr) log_notice(LD_EXIT, "Resolved %s which was already resolved; ignoring", escaped_safe_str(address)); tor_assert(resolve->pending_connections == NULL); return; } cached_resolve_add_answer(resolve, query_type, dns_answer, addr, hostname, ttl); if (cached_resolve_have_all_answers(resolve)) { inform_pending_connections(resolve); make_pending_resolve_cached(resolve); } } /** Given a pending cached_resolve_t that we just finished resolving, * inform every connection that was waiting for the outcome of that * resolution. */ static void inform_pending_connections(cached_resolve_t *resolve) { pending_connection_t *pend; edge_connection_t *pendconn; int r; while (resolve->pending_connections) { char *hostname = NULL; pend = resolve->pending_connections; pendconn = pend->conn; /* don't pass complex things to the connection_mark_for_close macro */ assert_connection_ok(TO_CONN(pendconn),time(NULL)); if (pendconn->base_.marked_for_close) { /* prevent double-remove. */ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; resolve->pending_connections = pend->next; tor_free(pend); continue; } r = set_exitconn_info_from_resolve(pendconn, resolve, &hostname); if (r < 0) { /* prevent double-remove. */ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) { connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED); /* This detach must happen after we send the end cell. */ circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); } else { send_resolved_cell(pendconn, r == -1 ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT, NULL); /* This detach must happen after we send the resolved cell. */ circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); } connection_free(TO_CONN(pendconn)); } else { circuit_t *circ; if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) { /* prevent double-remove. */ pend->conn->base_.state = EXIT_CONN_STATE_CONNECTING; circ = circuit_get_by_edge_conn(pend->conn); tor_assert(circ); tor_assert(!CIRCUIT_IS_ORIGIN(circ)); /* unlink pend->conn from resolving_streams, */ circuit_detach_stream(circ, pend->conn); /* and link it to n_streams */ pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams; pend->conn->on_circuit = circ; TO_OR_CIRCUIT(circ)->n_streams = pend->conn; connection_exit_connect(pend->conn); } else { /* prevent double-remove. This isn't really an accurate state, * but it does the right thing. */ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; if (pendconn->is_reverse_dns_lookup) send_resolved_hostname_cell(pendconn, hostname); else send_resolved_cell(pendconn, RESOLVED_TYPE_AUTO, resolve); circ = circuit_get_by_edge_conn(pendconn); tor_assert(circ); circuit_detach_stream(circ, pendconn); connection_free(TO_CONN(pendconn)); } } resolve->pending_connections = pend->next; tor_free(pend); } } /** Remove a pending cached_resolve_t from the hashtable, and add a * corresponding cached cached_resolve_t. * * This function is only necessary because of the perversity of our * cache timeout code; see inline comment for ideas on eliminating it. **/ static void make_pending_resolve_cached(cached_resolve_t *resolve) { cached_resolve_t *removed; resolve->state = CACHE_STATE_DONE; removed = HT_REMOVE(cache_map, &cache_root, resolve); if (removed != resolve) { log_err(LD_BUG, "The pending resolve we found wasn't removable from" " the cache. Tried to purge %s (%p); instead got %s (%p).", resolve->address, (void*)resolve, removed ? removed->address : "NULL", (void*)removed); } assert_resolve_ok(resolve); assert_cache_ok(); /* The resolve will eventually just hit the time-out in the expiry queue and * expire. See fd0bafb0dedc7e2 for a brief explanation of how this got that * way. XXXXX we could do better!*/ { cached_resolve_t *new_resolve = tor_memdup(resolve, sizeof(cached_resolve_t)); uint32_t ttl = UINT32_MAX; new_resolve->expire = 0; /* So that set_expiry won't croak. */ if (resolve->res_status_hostname == RES_STATUS_DONE_OK) new_resolve->result_ptr.hostname = tor_strdup(resolve->result_ptr.hostname); new_resolve->state = CACHE_STATE_CACHED; assert_resolve_ok(new_resolve); HT_INSERT(cache_map, &cache_root, new_resolve); if ((resolve->res_status_ipv4 == RES_STATUS_DONE_OK || resolve->res_status_ipv4 == RES_STATUS_DONE_ERR) && resolve->ttl_ipv4 < ttl) ttl = resolve->ttl_ipv4; if ((resolve->res_status_ipv6 == RES_STATUS_DONE_OK || resolve->res_status_ipv6 == RES_STATUS_DONE_ERR) && resolve->ttl_ipv6 < ttl) ttl = resolve->ttl_ipv6; if ((resolve->res_status_hostname == RES_STATUS_DONE_OK || resolve->res_status_hostname == RES_STATUS_DONE_ERR) && resolve->ttl_hostname < ttl) ttl = resolve->ttl_hostname; set_expiry(new_resolve, time(NULL) + dns_get_expiry_ttl(ttl)); } assert_cache_ok(); } /** Eventdns helper: return true iff the eventdns result err is * a transient failure. */ static int evdns_err_is_transient(int err) { switch (err) { case DNS_ERR_SERVERFAILED: case DNS_ERR_TRUNCATED: case DNS_ERR_TIMEOUT: return 1; default: return 0; } } /** Configure eventdns nameservers if force is true, or if the configuration * has changed since the last time we called this function, or if we failed on * our last attempt. On Unix, this reads from /etc/resolv.conf or * options->ServerDNSResolvConfFile; on Windows, this reads from * options->ServerDNSResolvConfFile or the registry. Return 0 on success or * -1 on failure. */ static int configure_nameservers(int force) { const or_options_t *options; const char *conf_fname; struct stat st; int r; options = get_options(); conf_fname = options->ServerDNSResolvConfFile; #ifndef _WIN32 if (!conf_fname) conf_fname = "/etc/resolv.conf"; #endif if (!the_evdns_base) { if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) { log_err(LD_BUG, "Couldn't create an evdns_base"); return -1; } } #ifdef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS if (! tor_addr_is_null(&options->OutboundBindAddressIPv4_)) { int socklen; struct sockaddr_storage ss; socklen = tor_addr_to_sockaddr(&options->OutboundBindAddressIPv4_, 0, (struct sockaddr *)&ss, sizeof(ss)); if (socklen <= 0) { log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr." " Ignoring."); } else { evdns_base_set_default_outgoing_bind_address(the_evdns_base, (struct sockaddr *)&ss, socklen); } } #endif evdns_set_log_fn(evdns_log_cb); if (conf_fname) { if (stat(conf_fname, &st)) { log_warn(LD_EXIT, "Unable to stat resolver configuration in '%s': %s", conf_fname, strerror(errno)); goto err; } if (!force && resolv_conf_fname && !strcmp(conf_fname,resolv_conf_fname) && st.st_mtime == resolv_conf_mtime) { log_info(LD_EXIT, "No change to '%s'", conf_fname); return 0; } if (nameservers_configured) { evdns_base_search_clear(the_evdns_base); evdns_base_clear_nameservers_and_suspend(the_evdns_base); } log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname); if ((r = evdns_base_resolv_conf_parse(the_evdns_base, DNS_OPTIONS_ALL, conf_fname))) { log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers in '%s' (%d)", conf_fname, conf_fname, r); goto err; } if (evdns_base_count_nameservers(the_evdns_base) == 0) { log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.", conf_fname); goto err; } tor_free(resolv_conf_fname); resolv_conf_fname = tor_strdup(conf_fname); resolv_conf_mtime = st.st_mtime; if (nameservers_configured) evdns_base_resume(the_evdns_base); } #ifdef _WIN32 else { if (nameservers_configured) { evdns_base_search_clear(the_evdns_base); evdns_base_clear_nameservers_and_suspend(the_evdns_base); } if (evdns_base_config_windows_nameservers(the_evdns_base)) { log_warn(LD_EXIT,"Could not config nameservers."); goto err; } if (evdns_base_count_nameservers(the_evdns_base) == 0) { log_warn(LD_EXIT, "Unable to find any platform nameservers in " "your Windows configuration."); goto err; } if (nameservers_configured) evdns_base_resume(the_evdns_base); tor_free(resolv_conf_fname); resolv_conf_mtime = 0; } #endif #define SET(k,v) evdns_base_set_option_(the_evdns_base, (k), (v)) if (evdns_base_count_nameservers(the_evdns_base) == 1) { SET("max-timeouts:", "16"); SET("timeout:", "10"); } else { SET("max-timeouts:", "3"); SET("timeout:", "5"); } if (options->ServerDNSRandomizeCase) SET("randomize-case:", "1"); else SET("randomize-case:", "0"); #undef SET dns_servers_relaunch_checks(); nameservers_configured = 1; if (nameserver_config_failed) { nameserver_config_failed = 0; /* XXX the three calls to republish the descriptor might be producing * descriptors that are only cosmetically different, especially on * non-exit relays! -RD */ mark_my_descriptor_dirty("dns resolvers back"); } return 0; err: nameservers_configured = 0; if (! nameserver_config_failed) { nameserver_config_failed = 1; mark_my_descriptor_dirty("dns resolvers failed"); } return -1; } /** For eventdns: Called when we get an answer for a request we launched. * See eventdns.h for arguments; 'arg' holds the address we tried to resolve. */ static void evdns_callback(int result, char type, int count, int ttl, void *addresses, void *arg) { char *arg_ = arg; uint8_t orig_query_type = arg_[0]; char *string_address = arg_ + 1; tor_addr_t addr; const char *hostname = NULL; int was_wildcarded = 0; tor_addr_make_unspec(&addr); /* Keep track of whether IPv6 is working */ if (type == DNS_IPv6_AAAA) { if (result == DNS_ERR_TIMEOUT) { ++n_ipv6_timeouts; } if (n_ipv6_timeouts > 10 && n_ipv6_timeouts > n_ipv6_requests_made / 2) { if (! dns_is_broken_for_ipv6) { log_notice(LD_EXIT, "More than half of our IPv6 requests seem to " "have timed out. I'm going to assume I can't get AAAA " "responses."); dns_is_broken_for_ipv6 = 1; } } } if (result == DNS_ERR_NONE) { if (type == DNS_IPv4_A && count) { char answer_buf[INET_NTOA_BUF_LEN+1]; char *escaped_address; uint32_t *addrs = addresses; tor_addr_from_ipv4n(&addr, addrs[0]); tor_addr_to_str(answer_buf, &addr, sizeof(answer_buf), 0); escaped_address = esc_for_log(string_address); if (answer_is_wildcarded(answer_buf)) { log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked " "address %s; treating as a failure.", safe_str(escaped_address), escaped_safe_str(answer_buf)); was_wildcarded = 1; tor_addr_make_unspec(&addr); result = DNS_ERR_NOTEXIST; } else { log_debug(LD_EXIT, "eventdns said that %s resolves to %s", safe_str(escaped_address), escaped_safe_str(answer_buf)); } tor_free(escaped_address); } else if (type == DNS_IPv6_AAAA && count) { char answer_buf[TOR_ADDR_BUF_LEN]; char *escaped_address; struct in6_addr *addrs = addresses; tor_addr_from_in6(&addr, &addrs[0]); tor_inet_ntop(AF_INET6, &addrs[0], answer_buf, sizeof(answer_buf)); escaped_address = esc_for_log(string_address); if (answer_is_wildcarded(answer_buf)) { log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked " "address %s; treating as a failure.", safe_str(escaped_address), escaped_safe_str(answer_buf)); was_wildcarded = 1; tor_addr_make_unspec(&addr); result = DNS_ERR_NOTEXIST; } else { log_debug(LD_EXIT, "eventdns said that %s resolves to %s", safe_str(escaped_address), escaped_safe_str(answer_buf)); } tor_free(escaped_address); } else if (type == DNS_PTR && count) { char *escaped_address; hostname = ((char**)addresses)[0]; escaped_address = esc_for_log(string_address); log_debug(LD_EXIT, "eventdns said that %s resolves to %s", safe_str(escaped_address), escaped_safe_str(hostname)); tor_free(escaped_address); } else if (count) { log_warn(LD_EXIT, "eventdns returned only non-IPv4 answers for %s.", escaped_safe_str(string_address)); } else { log_warn(LD_BUG, "eventdns returned no addresses or error for %s!", escaped_safe_str(string_address)); } } if (was_wildcarded) { if (is_test_address(string_address)) { /* Ick. We're getting redirected on known-good addresses. Our DNS * server must really hate us. */ add_wildcarded_test_address(string_address); } } if (orig_query_type && type && orig_query_type != type) { log_warn(LD_BUG, "Weird; orig_query_type == %d but type == %d", (int)orig_query_type, (int)type); } if (result != DNS_ERR_SHUTDOWN) dns_found_answer(string_address, orig_query_type, result, &addr, hostname, ttl); tor_free(arg_); } /** Start a single DNS resolve for address (if query_type is * DNS_IPv4_A or DNS_IPv6_AAAA) ptr_address (if query_type is * DNS_PTR). Return 0 if we launched the request, -1 otherwise. */ static int launch_one_resolve(const char *address, uint8_t query_type, const tor_addr_t *ptr_address) { const int options = get_options()->ServerDNSSearchDomains ? 0 : DNS_QUERY_NO_SEARCH; const size_t addr_len = strlen(address); struct evdns_request *req = 0; char *addr = tor_malloc(addr_len + 2); addr[0] = (char) query_type; memcpy(addr+1, address, addr_len + 1); switch (query_type) { case DNS_IPv4_A: req = evdns_base_resolve_ipv4(the_evdns_base, address, options, evdns_callback, addr); break; case DNS_IPv6_AAAA: req = evdns_base_resolve_ipv6(the_evdns_base, address, options, evdns_callback, addr); ++n_ipv6_requests_made; break; case DNS_PTR: if (tor_addr_family(ptr_address) == AF_INET) req = evdns_base_resolve_reverse(the_evdns_base, tor_addr_to_in(ptr_address), DNS_QUERY_NO_SEARCH, evdns_callback, addr); else if (tor_addr_family(ptr_address) == AF_INET6) req = evdns_base_resolve_reverse_ipv6(the_evdns_base, tor_addr_to_in6(ptr_address), DNS_QUERY_NO_SEARCH, evdns_callback, addr); else log_warn(LD_BUG, "Called with PTR query and unexpected address family"); break; default: log_warn(LD_BUG, "Called with unexpectd query type %d", (int)query_type); break; } if (req) { return 0; } else { tor_free(addr); return -1; } } /** For eventdns: start resolving as necessary to find the target for * exitconn. Returns -1 on error, -2 on transient error, * 0 on "resolve launched." */ static int launch_resolve(cached_resolve_t *resolve) { tor_addr_t a; int r; if (get_options()->DisableNetwork) return -1; /* What? Nameservers not configured? Sounds like a bug. */ if (!nameservers_configured) { log_warn(LD_EXIT, "(Harmless.) Nameservers not configured, but resolve " "launched. Configuring."); if (configure_nameservers(1) < 0) { return -1; } } r = tor_addr_parse_PTR_name( &a, resolve->address, AF_UNSPEC, 0); tor_assert(the_evdns_base); if (r == 0) { log_info(LD_EXIT, "Launching eventdns request for %s", escaped_safe_str(resolve->address)); resolve->res_status_ipv4 = RES_STATUS_INFLIGHT; if (get_options()->IPv6Exit) resolve->res_status_ipv6 = RES_STATUS_INFLIGHT; if (launch_one_resolve(resolve->address, DNS_IPv4_A, NULL) < 0) { resolve->res_status_ipv4 = 0; r = -1; } if (r==0 && get_options()->IPv6Exit) { /* We ask for an IPv6 address for *everything*. */ if (launch_one_resolve(resolve->address, DNS_IPv6_AAAA, NULL) < 0) { resolve->res_status_ipv6 = 0; r = -1; } } } else if (r == 1) { r = 0; log_info(LD_EXIT, "Launching eventdns reverse request for %s", escaped_safe_str(resolve->address)); resolve->res_status_hostname = RES_STATUS_INFLIGHT; if (launch_one_resolve(resolve->address, DNS_PTR, &a) < 0) { resolve->res_status_hostname = 0; r = -1; } } else if (r == -1) { log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here."); } if (r < 0) { log_fn(LOG_PROTOCOL_WARN, LD_EXIT, "eventdns rejected address %s.", escaped_safe_str(resolve->address)); } return r; } /** How many requests for bogus addresses have we launched so far? */ static int n_wildcard_requests = 0; /** Map from dotted-quad IP address in response to an int holding how many * times we've seen it for a randomly generated (hopefully bogus) address. It * would be easier to use definitely-invalid addresses (as specified by * RFC2606), but see comment in dns_launch_wildcard_checks(). */ static strmap_t *dns_wildcard_response_count = NULL; /** If present, a list of dotted-quad IP addresses that we are pretty sure our * nameserver wants to return in response to requests for nonexistent domains. */ static smartlist_t *dns_wildcard_list = NULL; /** True iff we've logged about a single address getting wildcarded. * Subsequent warnings will be less severe. */ static int dns_wildcard_one_notice_given = 0; /** True iff we've warned that our DNS server is wildcarding too many failures. */ static int dns_wildcard_notice_given = 0; /** List of supposedly good addresses that are getting wildcarded to the * same addresses as nonexistent addresses. */ static smartlist_t *dns_wildcarded_test_address_list = NULL; /** True iff we've warned about a test address getting wildcarded */ static int dns_wildcarded_test_address_notice_given = 0; /** True iff all addresses seem to be getting wildcarded. */ static int dns_is_completely_invalid = 0; /** Called when we see id (a dotted quad or IPv6 address) in response * to a request for a hopefully bogus address. */ static void wildcard_increment_answer(const char *id) { int *ip; if (!dns_wildcard_response_count) dns_wildcard_response_count = strmap_new(); ip = strmap_get(dns_wildcard_response_count, id); // may be null (0) if (!ip) { ip = tor_malloc_zero(sizeof(int)); strmap_set(dns_wildcard_response_count, id, ip); } ++*ip; if (*ip > 5 && n_wildcard_requests > 10) { if (!dns_wildcard_list) dns_wildcard_list = smartlist_new(); if (!smartlist_contains_string(dns_wildcard_list, id)) { tor_log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, "Your DNS provider has given \"%s\" as an answer for %d different " "invalid addresses. Apparently they are hijacking DNS failures. " "I'll try to correct for this by treating future occurrences of " "\"%s\" as 'not found'.", id, *ip, id); smartlist_add(dns_wildcard_list, tor_strdup(id)); } if (!dns_wildcard_notice_given) control_event_server_status(LOG_NOTICE, "DNS_HIJACKED"); dns_wildcard_notice_given = 1; } } /** Note that a single test address (one believed to be good) seems to be * getting redirected to the same IP as failures are. */ static void add_wildcarded_test_address(const char *address) { int n, n_test_addrs; if (!dns_wildcarded_test_address_list) dns_wildcarded_test_address_list = smartlist_new(); if (smartlist_contains_string_case(dns_wildcarded_test_address_list, address)) return; n_test_addrs = get_options()->ServerDNSTestAddresses ? smartlist_len(get_options()->ServerDNSTestAddresses) : 0; smartlist_add(dns_wildcarded_test_address_list, tor_strdup(address)); n = smartlist_len(dns_wildcarded_test_address_list); if (n > n_test_addrs/2) { tor_log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, "Your DNS provider tried to redirect \"%s\" to a junk " "address. It has done this with %d test addresses so far. I'm " "going to stop being an exit node for now, since our DNS seems so " "broken.", address, n); if (!dns_is_completely_invalid) { dns_is_completely_invalid = 1; mark_my_descriptor_dirty("dns hijacking confirmed"); } if (!dns_wildcarded_test_address_notice_given) control_event_server_status(LOG_WARN, "DNS_USELESS"); dns_wildcarded_test_address_notice_given = 1; } } /** Callback function when we get an answer (possibly failing) for a request * for a (hopefully) nonexistent domain. */ static void evdns_wildcard_check_callback(int result, char type, int count, int ttl, void *addresses, void *arg) { (void)ttl; ++n_wildcard_requests; if (result == DNS_ERR_NONE && count) { char *string_address = arg; int i; if (type == DNS_IPv4_A) { const uint32_t *addrs = addresses; for (i = 0; i < count; ++i) { char answer_buf[INET_NTOA_BUF_LEN+1]; struct in_addr in; in.s_addr = addrs[i]; tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf)); wildcard_increment_answer(answer_buf); } } else if (type == DNS_IPv6_AAAA) { const struct in6_addr *addrs = addresses; for (i = 0; i < count; ++i) { char answer_buf[TOR_ADDR_BUF_LEN+1]; tor_inet_ntop(AF_INET6, &addrs[i], answer_buf, sizeof(answer_buf)); wildcard_increment_answer(answer_buf); } } tor_log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, "Your DNS provider gave an answer for \"%s\", which " "is not supposed to exist. Apparently they are hijacking " "DNS failures. Trying to correct for this. We've noticed %d " "possibly bad address%s so far.", string_address, strmap_size(dns_wildcard_response_count), (strmap_size(dns_wildcard_response_count) == 1) ? "" : "es"); dns_wildcard_one_notice_given = 1; } tor_free(arg); } /** Launch a single request for a nonexistent hostname consisting of between * min_len and max_len random (plausible) characters followed by * suffix */ static void launch_wildcard_check(int min_len, int max_len, int is_ipv6, const char *suffix) { char *addr; struct evdns_request *req; addr = crypto_random_hostname(min_len, max_len, "", suffix); log_info(LD_EXIT, "Testing whether our DNS server is hijacking nonexistent " "domains with request for bogus hostname \"%s\"", addr); tor_assert(the_evdns_base); if (is_ipv6) req = evdns_base_resolve_ipv6( the_evdns_base, /* This "addr" tells us which address to resolve */ addr, DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback, /* This "addr" is an argument to the callback*/ addr); else req = evdns_base_resolve_ipv4( the_evdns_base, /* This "addr" tells us which address to resolve */ addr, DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback, /* This "addr" is an argument to the callback*/ addr); if (!req) { /* There is no evdns request in progress; stop addr from getting leaked */ tor_free(addr); } } /** Launch attempts to resolve a bunch of known-good addresses (configured in * ServerDNSTestAddresses). [Callback for a libevent timer] */ static void launch_test_addresses(evutil_socket_t fd, short event, void *args) { const or_options_t *options = get_options(); (void)fd; (void)event; (void)args; if (options->DisableNetwork) return; log_info(LD_EXIT, "Launching checks to see whether our nameservers like to " "hijack *everything*."); /* This situation is worse than the failure-hijacking situation. When this * happens, we're no good for DNS requests at all, and we shouldn't really * be an exit server.*/ if (options->ServerDNSTestAddresses) { tor_assert(the_evdns_base); SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses, const char *, address) { if (launch_one_resolve(address, DNS_IPv4_A, NULL) < 0) { log_info(LD_EXIT, "eventdns rejected test address %s", escaped_safe_str(address)); } if (launch_one_resolve(address, DNS_IPv6_AAAA, NULL) < 0) { log_info(LD_EXIT, "eventdns rejected test address %s", escaped_safe_str(address)); } } SMARTLIST_FOREACH_END(address); } } #define N_WILDCARD_CHECKS 2 /** Launch DNS requests for a few nonexistent hostnames and a few well-known * hostnames, and see if we can catch our nameserver trying to hijack them and * map them to a stupid "I couldn't find ggoogle.com but maybe you'd like to * buy these lovely encyclopedias" page. */ static void dns_launch_wildcard_checks(void) { int i, ipv6; log_info(LD_EXIT, "Launching checks to see whether our nameservers like " "to hijack DNS failures."); for (ipv6 = 0; ipv6 <= 1; ++ipv6) { for (i = 0; i < N_WILDCARD_CHECKS; ++i) { /* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly * attempt to 'comply' with rfc2606, refrain from giving A records for * these. This is the standards-compliance equivalent of making sure * that your crackhouse's elevator inspection certificate is up to date. */ launch_wildcard_check(2, 16, ipv6, ".invalid"); launch_wildcard_check(2, 16, ipv6, ".test"); /* These will break specs if there are ever any number of * 8+-character top-level domains. */ launch_wildcard_check(8, 16, ipv6, ""); /* Try some random .com/org/net domains. This will work fine so long as * not too many resolve to the same place. */ launch_wildcard_check(8, 16, ipv6, ".com"); launch_wildcard_check(8, 16, ipv6, ".org"); launch_wildcard_check(8, 16, ipv6, ".net"); } } } /** If appropriate, start testing whether our DNS servers tend to lie to * us. */ void dns_launch_correctness_checks(void) { static struct event *launch_event = NULL; struct timeval timeout; if (!get_options()->ServerDNSDetectHijacking) return; dns_launch_wildcard_checks(); /* Wait a while before launching requests for test addresses, so we can * get the results from checking for wildcarding. */ if (! launch_event) launch_event = tor_evtimer_new(tor_libevent_get_base(), launch_test_addresses, NULL); timeout.tv_sec = 30; timeout.tv_usec = 0; if (evtimer_add(launch_event, &timeout)<0) { log_warn(LD_BUG, "Couldn't add timer for checking for dns hijacking"); } } /** Return true iff our DNS servers lie to us too much to be trusted. */ int dns_seems_to_be_broken(void) { return dns_is_completely_invalid; } /** Return true iff we think that IPv6 hostname lookup is broken */ int dns_seems_to_be_broken_for_ipv6(void) { return dns_is_broken_for_ipv6; } /** Forget what we've previously learned about our DNS servers' correctness. */ void dns_reset_correctness_checks(void) { strmap_free(dns_wildcard_response_count, tor_free_); dns_wildcard_response_count = NULL; n_wildcard_requests = 0; n_ipv6_requests_made = n_ipv6_timeouts = 0; if (dns_wildcard_list) { SMARTLIST_FOREACH(dns_wildcard_list, char *, cp, tor_free(cp)); smartlist_clear(dns_wildcard_list); } if (dns_wildcarded_test_address_list) { SMARTLIST_FOREACH(dns_wildcarded_test_address_list, char *, cp, tor_free(cp)); smartlist_clear(dns_wildcarded_test_address_list); } dns_wildcard_one_notice_given = dns_wildcard_notice_given = dns_wildcarded_test_address_notice_given = dns_is_completely_invalid = dns_is_broken_for_ipv6 = 0; } /** Return true iff we have noticed that the dotted-quad ip has been * returned in response to requests for nonexistent hostnames. */ static int answer_is_wildcarded(const char *ip) { return dns_wildcard_list && smartlist_contains_string(dns_wildcard_list, ip); } /** Exit with an assertion if resolve is corrupt. */ static void assert_resolve_ok(cached_resolve_t *resolve) { tor_assert(resolve); tor_assert(resolve->magic == CACHED_RESOLVE_MAGIC); tor_assert(strlen(resolve->address) < MAX_ADDRESSLEN); tor_assert(tor_strisnonupper(resolve->address)); if (resolve->state != CACHE_STATE_PENDING) { tor_assert(!resolve->pending_connections); } if (resolve->state == CACHE_STATE_PENDING || resolve->state == CACHE_STATE_DONE) { #if 0 tor_assert(!resolve->ttl); if (resolve->is_reverse) tor_assert(!resolve->hostname); else tor_assert(!resolve->result_ipv4.addr_ipv4); #endif /*XXXXX ADD MORE */ } } /** Return the number of DNS cache entries as an int */ static int dns_cache_entry_count(void) { return HT_SIZE(&cache_root); } /** Log memory information about our internal DNS cache at level 'severity'. */ void dump_dns_mem_usage(int severity) { /* This should never be larger than INT_MAX. */ int hash_count = dns_cache_entry_count(); size_t hash_mem = sizeof(struct cached_resolve_t) * hash_count; hash_mem += HT_MEM_USAGE(&cache_root); /* Print out the count and estimated size of our &cache_root. It undercounts hostnames in cached reverse resolves. */ tor_log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count); tor_log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.", (unsigned)hash_mem); } #ifdef DEBUG_DNS_CACHE /** Exit with an assertion if the DNS cache is corrupt. */ static void assert_cache_ok_(void) { cached_resolve_t **resolve; int bad_rep = _cache_map_HT_REP_IS_BAD(&cache_root); if (bad_rep) { log_err(LD_BUG, "Bad rep type %d on dns cache hash table", bad_rep); tor_assert(!bad_rep); } HT_FOREACH(resolve, cache_map, &cache_root) { assert_resolve_ok(*resolve); tor_assert((*resolve)->state != CACHE_STATE_DONE); } if (!cached_resolve_pqueue) return; smartlist_pqueue_assert_ok(cached_resolve_pqueue, compare_cached_resolves_by_expiry_, STRUCT_OFFSET(cached_resolve_t, minheap_idx)); SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res, { if (res->state == CACHE_STATE_DONE) { cached_resolve_t *found = HT_FIND(cache_map, &cache_root, res); tor_assert(!found || found != res); } else { cached_resolve_t *found = HT_FIND(cache_map, &cache_root, res); tor_assert(found); } }); } #endif tor-0.2.4.20/src/or/rephist.c0000644000175000017500000030542312255745673012542 00000000000000/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file rephist.c * \brief Basic history and "reputation" functionality to remember * which servers have worked in the past, how much bandwidth we've * been using, which ports we tend to want, and so on; further, * exit port statistics, cell statistics, and connection statistics. **/ #include "or.h" #include "circuitlist.h" #include "circuituse.h" #include "config.h" #include "networkstatus.h" #include "nodelist.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "ht.h" static void bw_arrays_init(void); static void predicted_ports_init(void); /** Total number of bytes currently allocated in fields used by rephist.c. */ uint64_t rephist_total_alloc=0; /** Number of or_history_t objects currently allocated. */ uint32_t rephist_total_num=0; /** If the total weighted run count of all runs for a router ever falls * below this amount, the router can be treated as having 0 MTBF. */ #define STABILITY_EPSILON 0.0001 /** Value by which to discount all old intervals for MTBF purposes. This * is compounded every STABILITY_INTERVAL. */ #define STABILITY_ALPHA 0.95 /** Interval at which to discount all old intervals for MTBF purposes. */ #define STABILITY_INTERVAL (12*60*60) /* (This combination of ALPHA, INTERVAL, and EPSILON makes it so that an * interval that just ended counts twice as much as one that ended a week ago, * 20X as much as one that ended a month ago, and routers that have had no * uptime data for about half a year will get forgotten.) */ /** History of an OR-\>OR link. */ typedef struct link_history_t { /** When did we start tracking this list? */ time_t since; /** When did we most recently note a change to this link */ time_t changed; /** How many times did extending from OR1 to OR2 succeed? */ unsigned long n_extend_ok; /** How many times did extending from OR1 to OR2 fail? */ unsigned long n_extend_fail; } link_history_t; /** History of an OR. */ typedef struct or_history_t { /** When did we start tracking this OR? */ time_t since; /** When did we most recently note a change to this OR? */ time_t changed; /** How many times did we successfully connect? */ unsigned long n_conn_ok; /** How many times did we try to connect and fail?*/ unsigned long n_conn_fail; /** How many seconds have we been connected to this OR before * 'up_since'? */ unsigned long uptime; /** How many seconds have we been unable to connect to this OR before * 'down_since'? */ unsigned long downtime; /** If nonzero, we have been connected since this time. */ time_t up_since; /** If nonzero, we have been unable to connect since this time. */ time_t down_since; /** The address at which we most recently connected to this OR * successfully. */ tor_addr_t last_reached_addr; /** The port at which we most recently connected to this OR successfully */ uint16_t last_reached_port; /* === For MTBF tracking: */ /** Weighted sum total of all times that this router has been online. */ unsigned long weighted_run_length; /** If the router is now online (according to stability-checking rules), * when did it come online? */ time_t start_of_run; /** Sum of weights for runs in weighted_run_length. */ double total_run_weights; /* === For fractional uptime tracking: */ time_t start_of_downtime; unsigned long weighted_uptime; unsigned long total_weighted_time; /** Map from hex OR2 identity digest to a link_history_t for the link * from this OR to OR2. */ digestmap_t *link_history_map; } or_history_t; /** When did we last multiply all routers' weighted_run_length and * total_run_weights by STABILITY_ALPHA? */ static time_t stability_last_downrated = 0; /** */ static time_t started_tracking_stability = 0; /** Map from hex OR identity digest to or_history_t. */ static digestmap_t *history_map = NULL; /** Return the or_history_t for the OR with identity digest id, * creating it if necessary. */ static or_history_t * get_or_history(const char* id) { or_history_t *hist; if (tor_digest_is_zero(id)) return NULL; hist = digestmap_get(history_map, id); if (!hist) { hist = tor_malloc_zero(sizeof(or_history_t)); rephist_total_alloc += sizeof(or_history_t); rephist_total_num++; hist->link_history_map = digestmap_new(); hist->since = hist->changed = time(NULL); tor_addr_make_unspec(&hist->last_reached_addr); digestmap_set(history_map, id, hist); } return hist; } /** Return the link_history_t for the link from the first named OR to * the second, creating it if necessary. (ORs are identified by * identity digest.) */ static link_history_t * get_link_history(const char *from_id, const char *to_id) { or_history_t *orhist; link_history_t *lhist; orhist = get_or_history(from_id); if (!orhist) return NULL; if (tor_digest_is_zero(to_id)) return NULL; lhist = (link_history_t*) digestmap_get(orhist->link_history_map, to_id); if (!lhist) { lhist = tor_malloc_zero(sizeof(link_history_t)); rephist_total_alloc += sizeof(link_history_t); lhist->since = lhist->changed = time(NULL); digestmap_set(orhist->link_history_map, to_id, lhist); } return lhist; } /** Helper: free storage held by a single link history entry. */ static void free_link_history_(void *val) { rephist_total_alloc -= sizeof(link_history_t); tor_free(val); } /** Helper: free storage held by a single OR history entry. */ static void free_or_history(void *_hist) { or_history_t *hist = _hist; digestmap_free(hist->link_history_map, free_link_history_); rephist_total_alloc -= sizeof(or_history_t); rephist_total_num--; tor_free(hist); } /** Update an or_history_t object hist so that its uptime/downtime * count is up-to-date as of when. */ static void update_or_history(or_history_t *hist, time_t when) { tor_assert(hist); if (hist->up_since) { tor_assert(!hist->down_since); hist->uptime += (when - hist->up_since); hist->up_since = when; } else if (hist->down_since) { hist->downtime += (when - hist->down_since); hist->down_since = when; } } /** Initialize the static data structures for tracking history. */ void rep_hist_init(void) { history_map = digestmap_new(); bw_arrays_init(); predicted_ports_init(); } /** Helper: note that we are no longer connected to the router with history * hist. If failed, the connection failed; otherwise, it was * closed correctly. */ static void mark_or_down(or_history_t *hist, time_t when, int failed) { if (hist->up_since) { hist->uptime += (when - hist->up_since); hist->up_since = 0; } if (failed && !hist->down_since) { hist->down_since = when; } } /** Helper: note that we are connected to the router with history * hist. */ static void mark_or_up(or_history_t *hist, time_t when) { if (hist->down_since) { hist->downtime += (when - hist->down_since); hist->down_since = 0; } if (!hist->up_since) { hist->up_since = when; } } /** Remember that an attempt to connect to the OR with identity digest * id failed at when. */ void rep_hist_note_connect_failed(const char* id, time_t when) { or_history_t *hist; hist = get_or_history(id); if (!hist) return; ++hist->n_conn_fail; mark_or_down(hist, when, 1); hist->changed = when; } /** Remember that an attempt to connect to the OR with identity digest * id succeeded at when. */ void rep_hist_note_connect_succeeded(const char* id, time_t when) { or_history_t *hist; hist = get_or_history(id); if (!hist) return; ++hist->n_conn_ok; mark_or_up(hist, when); hist->changed = when; } /** Remember that we intentionally closed our connection to the OR * with identity digest id at when. */ void rep_hist_note_disconnect(const char* id, time_t when) { or_history_t *hist; hist = get_or_history(id); if (!hist) return; mark_or_down(hist, when, 0); hist->changed = when; } /** Remember that our connection to the OR with identity digest * id had an error and stopped working at when. */ void rep_hist_note_connection_died(const char* id, time_t when) { or_history_t *hist; if (!id) { /* If conn has no identity, it didn't complete its handshake, or something * went wrong. Ignore it. */ return; } hist = get_or_history(id); if (!hist) return; mark_or_down(hist, when, 1); hist->changed = when; } /** We have just decided that this router with identity digest id is * reachable, meaning we will give it a "Running" flag for the next while. */ void rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr, const uint16_t at_port, time_t when) { or_history_t *hist = get_or_history(id); int was_in_run = 1; char tbuf[ISO_TIME_LEN+1]; int addr_changed, port_changed; tor_assert(hist); tor_assert((!at_addr && !at_port) || (at_addr && at_port)); addr_changed = at_addr && !tor_addr_is_null(&hist->last_reached_addr) && tor_addr_compare(at_addr, &hist->last_reached_addr, CMP_EXACT) != 0; port_changed = at_port && hist->last_reached_port && at_port != hist->last_reached_port; if (!started_tracking_stability) started_tracking_stability = time(NULL); if (!hist->start_of_run) { hist->start_of_run = when; was_in_run = 0; } if (hist->start_of_downtime) { long down_length; format_local_iso_time(tbuf, hist->start_of_downtime); log_info(LD_HIST, "Router %s is now Running; it had been down since %s.", hex_str(id, DIGEST_LEN), tbuf); if (was_in_run) log_info(LD_HIST, " (Paradoxically, it was already Running too.)"); down_length = when - hist->start_of_downtime; hist->total_weighted_time += down_length; hist->start_of_downtime = 0; } else if (addr_changed || port_changed) { /* If we're reachable, but the address changed, treat this as some * downtime. */ int penalty = get_options()->TestingTorNetwork ? 240 : 3600; networkstatus_t *ns; if ((ns = networkstatus_get_latest_consensus())) { int fresh_interval = (int)(ns->fresh_until - ns->valid_after); int live_interval = (int)(ns->valid_until - ns->valid_after); /* on average, a descriptor addr change takes .5 intervals to make it * into a consensus, and half a liveness period to make it to * clients. */ penalty = (int)(fresh_interval + live_interval) / 2; } format_local_iso_time(tbuf, hist->start_of_run); log_info(LD_HIST,"Router %s still seems Running, but its address appears " "to have changed since the last time it was reachable. I'm " "going to treat it as having been down for %d seconds", hex_str(id, DIGEST_LEN), penalty); rep_hist_note_router_unreachable(id, when-penalty); rep_hist_note_router_reachable(id, NULL, 0, when); } else { format_local_iso_time(tbuf, hist->start_of_run); if (was_in_run) log_debug(LD_HIST, "Router %s is still Running; it has been Running " "since %s", hex_str(id, DIGEST_LEN), tbuf); else log_info(LD_HIST,"Router %s is now Running; it was previously untracked", hex_str(id, DIGEST_LEN)); } if (at_addr) tor_addr_copy(&hist->last_reached_addr, at_addr); if (at_port) hist->last_reached_port = at_port; } /** We have just decided that this router is unreachable, meaning * we are taking away its "Running" flag. */ void rep_hist_note_router_unreachable(const char *id, time_t when) { or_history_t *hist = get_or_history(id); char tbuf[ISO_TIME_LEN+1]; int was_running = 0; if (!started_tracking_stability) started_tracking_stability = time(NULL); tor_assert(hist); if (hist->start_of_run) { /*XXXX We could treat failed connections differently from failed * connect attempts. */ long run_length = when - hist->start_of_run; format_local_iso_time(tbuf, hist->start_of_run); hist->total_run_weights += 1.0; hist->start_of_run = 0; if (run_length < 0) { unsigned long penalty = -run_length; #define SUBTRACT_CLAMPED(var, penalty) \ do { (var) = (var) < (penalty) ? 0 : (var) - (penalty); } while (0) SUBTRACT_CLAMPED(hist->weighted_run_length, penalty); SUBTRACT_CLAMPED(hist->weighted_uptime, penalty); } else { hist->weighted_run_length += run_length; hist->weighted_uptime += run_length; hist->total_weighted_time += run_length; } was_running = 1; log_info(LD_HIST, "Router %s is now non-Running: it had previously been " "Running since %s. Its total weighted uptime is %lu/%lu.", hex_str(id, DIGEST_LEN), tbuf, hist->weighted_uptime, hist->total_weighted_time); } if (!hist->start_of_downtime) { hist->start_of_downtime = when; if (!was_running) log_info(LD_HIST, "Router %s is now non-Running; it was previously " "untracked.", hex_str(id, DIGEST_LEN)); } else { if (!was_running) { format_local_iso_time(tbuf, hist->start_of_downtime); log_info(LD_HIST, "Router %s is still non-Running; it has been " "non-Running since %s.", hex_str(id, DIGEST_LEN), tbuf); } } } /** Mark a router with ID id as non-Running, and retroactively declare * that it has never been running: give it no stability and no WFU. */ void rep_hist_make_router_pessimal(const char *id, time_t when) { or_history_t *hist = get_or_history(id); tor_assert(hist); rep_hist_note_router_unreachable(id, when); mark_or_down(hist, when, 1); hist->weighted_run_length = 0; hist->weighted_uptime = 0; } /** Helper: Discount all old MTBF data, if it is time to do so. Return * the time at which we should next discount MTBF data. */ time_t rep_hist_downrate_old_runs(time_t now) { digestmap_iter_t *orhist_it; const char *digest1; or_history_t *hist; void *hist_p; double alpha = 1.0; if (!history_map) history_map = digestmap_new(); if (!stability_last_downrated) stability_last_downrated = now; if (stability_last_downrated + STABILITY_INTERVAL > now) return stability_last_downrated + STABILITY_INTERVAL; /* Okay, we should downrate the data. By how much? */ while (stability_last_downrated + STABILITY_INTERVAL < now) { stability_last_downrated += STABILITY_INTERVAL; alpha *= STABILITY_ALPHA; } log_info(LD_HIST, "Discounting all old stability info by a factor of %f", alpha); /* Multiply every w_r_l, t_r_w pair by alpha. */ for (orhist_it = digestmap_iter_init(history_map); !digestmap_iter_done(orhist_it); orhist_it = digestmap_iter_next(history_map,orhist_it)) { digestmap_iter_get(orhist_it, &digest1, &hist_p); hist = hist_p; hist->weighted_run_length = (unsigned long)(hist->weighted_run_length * alpha); hist->total_run_weights *= alpha; hist->weighted_uptime = (unsigned long)(hist->weighted_uptime * alpha); hist->total_weighted_time = (unsigned long) (hist->total_weighted_time * alpha); } return stability_last_downrated + STABILITY_INTERVAL; } /** Helper: Return the weighted MTBF of the router with history hist. */ static double get_stability(or_history_t *hist, time_t when) { long total = hist->weighted_run_length; double total_weights = hist->total_run_weights; if (hist->start_of_run) { /* We're currently in a run. Let total and total_weights hold the values * they would hold if the current run were to end now. */ total += (when-hist->start_of_run); total_weights += 1.0; } if (total_weights < STABILITY_EPSILON) { /* Round down to zero, and avoid divide-by-zero. */ return 0.0; } return total / total_weights; } /** Return the total amount of time we've been observing, with each run of * time downrated by the appropriate factor. */ static long get_total_weighted_time(or_history_t *hist, time_t when) { long total = hist->total_weighted_time; if (hist->start_of_run) { total += (when - hist->start_of_run); } else if (hist->start_of_downtime) { total += (when - hist->start_of_downtime); } return total; } /** Helper: Return the weighted percent-of-time-online of the router with * history hist. */ static double get_weighted_fractional_uptime(or_history_t *hist, time_t when) { long total = hist->total_weighted_time; long up = hist->weighted_uptime; if (hist->start_of_run) { long run_length = (when - hist->start_of_run); up += run_length; total += run_length; } else if (hist->start_of_downtime) { total += (when - hist->start_of_downtime); } if (!total) { /* Avoid calling anybody's uptime infinity (which should be impossible if * the code is working), or NaN (which can happen for any router we haven't * observed up or down yet). */ return 0.0; } return ((double) up) / total; } /** Return how long the router whose identity digest is id has * been reachable. Return 0 if the router is unknown or currently deemed * unreachable. */ long rep_hist_get_uptime(const char *id, time_t when) { or_history_t *hist = get_or_history(id); if (!hist) return 0; if (!hist->start_of_run || when < hist->start_of_run) return 0; return when - hist->start_of_run; } /** Return an estimated MTBF for the router whose identity digest is * id. Return 0 if the router is unknown. */ double rep_hist_get_stability(const char *id, time_t when) { or_history_t *hist = get_or_history(id); if (!hist) return 0.0; return get_stability(hist, when); } /** Return an estimated percent-of-time-online for the router whose identity * digest is id. Return 0 if the router is unknown. */ double rep_hist_get_weighted_fractional_uptime(const char *id, time_t when) { or_history_t *hist = get_or_history(id); if (!hist) return 0.0; return get_weighted_fractional_uptime(hist, when); } /** Return a number representing how long we've known about the router whose * digest is id. Return 0 if the router is unknown. * * Be careful: this measure increases monotonically as we know the router for * longer and longer, but it doesn't increase linearly. */ long rep_hist_get_weighted_time_known(const char *id, time_t when) { or_history_t *hist = get_or_history(id); if (!hist) return 0; return get_total_weighted_time(hist, when); } /** Return true if we've been measuring MTBFs for long enough to * pronounce on Stability. */ int rep_hist_have_measured_enough_stability(void) { /* XXXX023 This doesn't do so well when we change our opinion * as to whether we're tracking router stability. */ return started_tracking_stability < time(NULL) - 4*60*60; } /** Remember that we successfully extended from the OR with identity * digest from_id to the OR with identity digest * to_name. */ void rep_hist_note_extend_succeeded(const char *from_id, const char *to_id) { link_history_t *hist; /* log_fn(LOG_WARN, "EXTEND SUCCEEDED: %s->%s",from_name,to_name); */ hist = get_link_history(from_id, to_id); if (!hist) return; ++hist->n_extend_ok; hist->changed = time(NULL); } /** Remember that we tried to extend from the OR with identity digest * from_id to the OR with identity digest to_name, but * failed. */ void rep_hist_note_extend_failed(const char *from_id, const char *to_id) { link_history_t *hist; /* log_fn(LOG_WARN, "EXTEND FAILED: %s->%s",from_name,to_name); */ hist = get_link_history(from_id, to_id); if (!hist) return; ++hist->n_extend_fail; hist->changed = time(NULL); } /** Log all the reliability data we have remembered, with the chosen * severity. */ void rep_hist_dump_stats(time_t now, int severity) { digestmap_iter_t *lhist_it; digestmap_iter_t *orhist_it; const char *name1, *name2, *digest1, *digest2; char hexdigest1[HEX_DIGEST_LEN+1]; char hexdigest2[HEX_DIGEST_LEN+1]; or_history_t *or_history; link_history_t *link_history; void *or_history_p, *link_history_p; double uptime; char buffer[2048]; size_t len; int ret; unsigned long upt, downt; const node_t *node; rep_history_clean(now - get_options()->RephistTrackTime); tor_log(severity, LD_HIST, "--------------- Dumping history information:"); for (orhist_it = digestmap_iter_init(history_map); !digestmap_iter_done(orhist_it); orhist_it = digestmap_iter_next(history_map,orhist_it)) { double s; long stability; digestmap_iter_get(orhist_it, &digest1, &or_history_p); or_history = (or_history_t*) or_history_p; if ((node = node_get_by_id(digest1)) && node_get_nickname(node)) name1 = node_get_nickname(node); else name1 = "(unknown)"; base16_encode(hexdigest1, sizeof(hexdigest1), digest1, DIGEST_LEN); update_or_history(or_history, now); upt = or_history->uptime; downt = or_history->downtime; s = get_stability(or_history, now); stability = (long)s; if (upt+downt) { uptime = ((double)upt) / (upt+downt); } else { uptime=1.0; } tor_log(severity, LD_HIST, "OR %s [%s]: %ld/%ld good connections; uptime %ld/%ld sec (%.2f%%); " "wmtbf %lu:%02lu:%02lu", name1, hexdigest1, or_history->n_conn_ok, or_history->n_conn_fail+or_history->n_conn_ok, upt, upt+downt, uptime*100.0, stability/3600, (stability/60)%60, stability%60); if (!digestmap_isempty(or_history->link_history_map)) { strlcpy(buffer, " Extend attempts: ", sizeof(buffer)); len = strlen(buffer); for (lhist_it = digestmap_iter_init(or_history->link_history_map); !digestmap_iter_done(lhist_it); lhist_it = digestmap_iter_next(or_history->link_history_map, lhist_it)) { digestmap_iter_get(lhist_it, &digest2, &link_history_p); if ((node = node_get_by_id(digest2)) && node_get_nickname(node)) name2 = node_get_nickname(node); else name2 = "(unknown)"; link_history = (link_history_t*) link_history_p; base16_encode(hexdigest2, sizeof(hexdigest2), digest2, DIGEST_LEN); ret = tor_snprintf(buffer+len, 2048-len, "%s [%s](%ld/%ld); ", name2, hexdigest2, link_history->n_extend_ok, link_history->n_extend_ok+link_history->n_extend_fail); if (ret<0) break; else len += ret; } tor_log(severity, LD_HIST, "%s", buffer); } } } /** Remove history info for routers/links that haven't changed since * before. */ void rep_history_clean(time_t before) { int authority = authdir_mode(get_options()); or_history_t *or_history; link_history_t *link_history; void *or_history_p, *link_history_p; digestmap_iter_t *orhist_it, *lhist_it; const char *d1, *d2; orhist_it = digestmap_iter_init(history_map); while (!digestmap_iter_done(orhist_it)) { int remove; digestmap_iter_get(orhist_it, &d1, &or_history_p); or_history = or_history_p; remove = authority ? (or_history->total_run_weights < STABILITY_EPSILON && !or_history->start_of_run) : (or_history->changed < before); if (remove) { orhist_it = digestmap_iter_next_rmv(history_map, orhist_it); free_or_history(or_history); continue; } for (lhist_it = digestmap_iter_init(or_history->link_history_map); !digestmap_iter_done(lhist_it); ) { digestmap_iter_get(lhist_it, &d2, &link_history_p); link_history = link_history_p; if (link_history->changed < before) { lhist_it = digestmap_iter_next_rmv(or_history->link_history_map, lhist_it); rephist_total_alloc -= sizeof(link_history_t); tor_free(link_history); continue; } lhist_it = digestmap_iter_next(or_history->link_history_map,lhist_it); } orhist_it = digestmap_iter_next(history_map, orhist_it); } } /** Write MTBF data to disk. Return 0 on success, negative on failure. * * If missing_means_down, then if we're about to write an entry * that is still considered up but isn't in our routerlist, consider it * to be down. */ int rep_hist_record_mtbf_data(time_t now, int missing_means_down) { char time_buf[ISO_TIME_LEN+1]; digestmap_iter_t *orhist_it; const char *digest; void *or_history_p; or_history_t *hist; open_file_t *open_file = NULL; FILE *f; { char *filename = get_datadir_fname("router-stability"); f = start_writing_to_stdio_file(filename, OPEN_FLAGS_REPLACE|O_TEXT, 0600, &open_file); tor_free(filename); if (!f) return -1; } /* File format is: * FormatLine *KeywordLine Data * * FormatLine = "format 1" NL * KeywordLine = Keyword SP Arguments NL * Data = "data" NL *RouterMTBFLine "." NL * RouterMTBFLine = Fingerprint SP WeightedRunLen SP * TotalRunWeights [SP S=StartRunTime] NL */ #define PUT(s) STMT_BEGIN if (fputs((s),f)<0) goto err; STMT_END #define PRINTF(args) STMT_BEGIN if (fprintf args <0) goto err; STMT_END PUT("format 2\n"); format_iso_time(time_buf, time(NULL)); PRINTF((f, "stored-at %s\n", time_buf)); if (started_tracking_stability) { format_iso_time(time_buf, started_tracking_stability); PRINTF((f, "tracked-since %s\n", time_buf)); } if (stability_last_downrated) { format_iso_time(time_buf, stability_last_downrated); PRINTF((f, "last-downrated %s\n", time_buf)); } PUT("data\n"); /* XXX Nick: now bridge auths record this for all routers too. * Should we make them record it only for bridge routers? -RD * Not for 0.2.0. -NM */ for (orhist_it = digestmap_iter_init(history_map); !digestmap_iter_done(orhist_it); orhist_it = digestmap_iter_next(history_map,orhist_it)) { char dbuf[HEX_DIGEST_LEN+1]; const char *t = NULL; digestmap_iter_get(orhist_it, &digest, &or_history_p); hist = (or_history_t*) or_history_p; base16_encode(dbuf, sizeof(dbuf), digest, DIGEST_LEN); if (missing_means_down && hist->start_of_run && !router_get_by_id_digest(digest)) { /* We think this relay is running, but it's not listed in our * routerlist. Somehow it fell out without telling us it went * down. Complain and also correct it. */ log_info(LD_HIST, "Relay '%s' is listed as up in rephist, but it's not in " "our routerlist. Correcting.", dbuf); rep_hist_note_router_unreachable(digest, now); } PRINTF((f, "R %s\n", dbuf)); if (hist->start_of_run > 0) { format_iso_time(time_buf, hist->start_of_run); t = time_buf; } PRINTF((f, "+MTBF %lu %.5f%s%s\n", hist->weighted_run_length, hist->total_run_weights, t ? " S=" : "", t ? t : "")); t = NULL; if (hist->start_of_downtime > 0) { format_iso_time(time_buf, hist->start_of_downtime); t = time_buf; } PRINTF((f, "+WFU %lu %lu%s%s\n", hist->weighted_uptime, hist->total_weighted_time, t ? " S=" : "", t ? t : "")); } PUT(".\n"); #undef PUT #undef PRINTF return finish_writing_to_file(open_file); err: abort_writing_to_file(open_file); return -1; } /** Format the current tracked status of the router in hist at time * now for analysis; return it in a newly allocated string. */ static char * rep_hist_format_router_status(or_history_t *hist, time_t now) { char sor_buf[ISO_TIME_LEN+1]; char sod_buf[ISO_TIME_LEN+1]; double wfu; double mtbf; int up = 0, down = 0; char *cp = NULL; if (hist->start_of_run) { format_iso_time(sor_buf, hist->start_of_run); up = 1; } if (hist->start_of_downtime) { format_iso_time(sod_buf, hist->start_of_downtime); down = 1; } wfu = get_weighted_fractional_uptime(hist, now); mtbf = get_stability(hist, now); tor_asprintf(&cp, "%s%s%s" "%s%s%s" "wfu %0.3f\n" " weighted-time %lu\n" " weighted-uptime %lu\n" "mtbf %0.1f\n" " weighted-run-length %lu\n" " total-run-weights %f\n", up?"uptime-started ":"", up?sor_buf:"", up?" UTC\n":"", down?"downtime-started ":"", down?sod_buf:"", down?" UTC\n":"", wfu, hist->total_weighted_time, hist->weighted_uptime, mtbf, hist->weighted_run_length, hist->total_run_weights ); return cp; } /** The last stability analysis document that we created, or NULL if we never * have created one. */ static char *last_stability_doc = NULL; /** The last time we created a stability analysis document, or 0 if we never * have created one. */ static time_t built_last_stability_doc_at = 0; /** Shortest allowable time between building two stability documents. */ #define MAX_STABILITY_DOC_BUILD_RATE (3*60) /** Return a pointer to a NUL-terminated document describing our view of the * stability of the routers we've been tracking. Return NULL on failure. */ const char * rep_hist_get_router_stability_doc(time_t now) { char *result; smartlist_t *chunks; if (built_last_stability_doc_at + MAX_STABILITY_DOC_BUILD_RATE > now) return last_stability_doc; if (!history_map) return NULL; tor_free(last_stability_doc); chunks = smartlist_new(); if (rep_hist_have_measured_enough_stability()) { smartlist_add(chunks, tor_strdup("we-have-enough-measurements\n")); } else { smartlist_add(chunks, tor_strdup("we-do-not-have-enough-measurements\n")); } DIGESTMAP_FOREACH(history_map, id, or_history_t *, hist) { const node_t *node; char dbuf[BASE64_DIGEST_LEN+1]; char *info; digest_to_base64(dbuf, id); node = node_get_by_id(id); if (node) { char ip[INET_NTOA_BUF_LEN+1]; char tbuf[ISO_TIME_LEN+1]; time_t published = node_get_published_on(node); node_get_address_string(node,ip,sizeof(ip)); if (published > 0) format_iso_time(tbuf, published); else strlcpy(tbuf, "???", sizeof(tbuf)); smartlist_add_asprintf(chunks, "router %s %s %s\n" "published %s\n" "relevant-flags %s%s%s\n" "declared-uptime %ld\n", dbuf, node_get_nickname(node), ip, tbuf, node->is_running ? "Running " : "", node->is_valid ? "Valid " : "", node->ri && node->ri->is_hibernating ? "Hibernating " : "", node_get_declared_uptime(node)); } else { smartlist_add_asprintf(chunks, "router %s {no descriptor}\n", dbuf); } info = rep_hist_format_router_status(hist, now); if (info) smartlist_add(chunks, info); } DIGESTMAP_FOREACH_END; result = smartlist_join_strings(chunks, "", 0, NULL); SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); smartlist_free(chunks); last_stability_doc = result; built_last_stability_doc_at = time(NULL); return result; } /** Helper: return the first j >= i such that !strcmpstart(sl[j], prefix) and * such that no line sl[k] with i <= k < j starts with "R ". Return -1 if no * such line exists. */ static int find_next_with(smartlist_t *sl, int i, const char *prefix) { for ( ; i < smartlist_len(sl); ++i) { const char *line = smartlist_get(sl, i); if (!strcmpstart(line, prefix)) return i; if (!strcmpstart(line, "R ")) return -1; } return -1; } /** How many bad times has parse_possibly_bad_iso_time() parsed? */ static int n_bogus_times = 0; /** Parse the ISO-formatted time in s into *time_out, but * round any pre-1970 date to Jan 1, 1970. */ static int parse_possibly_bad_iso_time(const char *s, time_t *time_out) { int year; char b[5]; strlcpy(b, s, sizeof(b)); b[4] = '\0'; year = (int)tor_parse_long(b, 10, 0, INT_MAX, NULL, NULL); if (year < 1970) { *time_out = 0; ++n_bogus_times; return 0; } else return parse_iso_time(s, time_out); } /** We've read a time t from a file stored at stored_at, which * says we started measuring at started_measuring. Return a new number * that's about as much before now as t was before * stored_at. */ static INLINE time_t correct_time(time_t t, time_t now, time_t stored_at, time_t started_measuring) { if (t < started_measuring - 24*60*60*365) return 0; else if (t < started_measuring) return started_measuring; else if (t > stored_at) return 0; else { long run_length = stored_at - t; t = now - run_length; if (t < started_measuring) t = started_measuring; return t; } } /** Load MTBF data from disk. Returns 0 on success or recoverable error, -1 * on failure. */ int rep_hist_load_mtbf_data(time_t now) { /* XXXX won't handle being called while history is already populated. */ smartlist_t *lines; const char *line = NULL; int r=0, i; time_t last_downrated = 0, stored_at = 0, tracked_since = 0; time_t latest_possible_start = now; long format = -1; { char *filename = get_datadir_fname("router-stability"); char *d = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); tor_free(filename); if (!d) return -1; lines = smartlist_new(); smartlist_split_string(lines, d, "\n", SPLIT_SKIP_SPACE, 0); tor_free(d); } { const char *firstline; if (smartlist_len(lines)>4) { firstline = smartlist_get(lines, 0); if (!strcmpstart(firstline, "format ")) format = tor_parse_long(firstline+strlen("format "), 10, -1, LONG_MAX, NULL, NULL); } } if (format != 1 && format != 2) { log_warn(LD_HIST, "Unrecognized format in mtbf history file. Skipping."); goto err; } for (i = 1; i < smartlist_len(lines); ++i) { line = smartlist_get(lines, i); if (!strcmp(line, "data")) break; if (!strcmpstart(line, "last-downrated ")) { if (parse_iso_time(line+strlen("last-downrated "), &last_downrated)<0) log_warn(LD_HIST,"Couldn't parse downrate time in mtbf " "history file."); } if (!strcmpstart(line, "stored-at ")) { if (parse_iso_time(line+strlen("stored-at "), &stored_at)<0) log_warn(LD_HIST,"Couldn't parse stored time in mtbf " "history file."); } if (!strcmpstart(line, "tracked-since ")) { if (parse_iso_time(line+strlen("tracked-since "), &tracked_since)<0) log_warn(LD_HIST,"Couldn't parse started-tracking time in mtbf " "history file."); } } if (last_downrated > now) last_downrated = now; if (tracked_since > now) tracked_since = now; if (!stored_at) { log_warn(LD_HIST, "No stored time recorded."); goto err; } if (line && !strcmp(line, "data")) ++i; n_bogus_times = 0; for (; i < smartlist_len(lines); ++i) { char digest[DIGEST_LEN]; char hexbuf[HEX_DIGEST_LEN+1]; char mtbf_timebuf[ISO_TIME_LEN+1]; char wfu_timebuf[ISO_TIME_LEN+1]; time_t start_of_run = 0; time_t start_of_downtime = 0; int have_mtbf = 0, have_wfu = 0; long wrl = 0; double trw = 0; long wt_uptime = 0, total_wt_time = 0; int n; or_history_t *hist; line = smartlist_get(lines, i); if (!strcmp(line, ".")) break; mtbf_timebuf[0] = '\0'; wfu_timebuf[0] = '\0'; if (format == 1) { n = tor_sscanf(line, "%40s %ld %lf S=%10s %8s", hexbuf, &wrl, &trw, mtbf_timebuf, mtbf_timebuf+11); if (n != 3 && n != 5) { log_warn(LD_HIST, "Couldn't scan line %s", escaped(line)); continue; } have_mtbf = 1; } else { // format == 2. int mtbf_idx, wfu_idx; if (strcmpstart(line, "R ") || strlen(line) < 2+HEX_DIGEST_LEN) continue; strlcpy(hexbuf, line+2, sizeof(hexbuf)); mtbf_idx = find_next_with(lines, i+1, "+MTBF "); wfu_idx = find_next_with(lines, i+1, "+WFU "); if (mtbf_idx >= 0) { const char *mtbfline = smartlist_get(lines, mtbf_idx); n = tor_sscanf(mtbfline, "+MTBF %lu %lf S=%10s %8s", &wrl, &trw, mtbf_timebuf, mtbf_timebuf+11); if (n == 2 || n == 4) { have_mtbf = 1; } else { log_warn(LD_HIST, "Couldn't scan +MTBF line %s", escaped(mtbfline)); } } if (wfu_idx >= 0) { const char *wfuline = smartlist_get(lines, wfu_idx); n = tor_sscanf(wfuline, "+WFU %lu %lu S=%10s %8s", &wt_uptime, &total_wt_time, wfu_timebuf, wfu_timebuf+11); if (n == 2 || n == 4) { have_wfu = 1; } else { log_warn(LD_HIST, "Couldn't scan +WFU line %s", escaped(wfuline)); } } if (wfu_idx > i) i = wfu_idx; if (mtbf_idx > i) i = mtbf_idx; } if (base16_decode(digest, DIGEST_LEN, hexbuf, HEX_DIGEST_LEN) < 0) { log_warn(LD_HIST, "Couldn't hex string %s", escaped(hexbuf)); continue; } hist = get_or_history(digest); if (!hist) continue; if (have_mtbf) { if (mtbf_timebuf[0]) { mtbf_timebuf[10] = ' '; if (parse_possibly_bad_iso_time(mtbf_timebuf, &start_of_run)<0) log_warn(LD_HIST, "Couldn't parse time %s", escaped(mtbf_timebuf)); } hist->start_of_run = correct_time(start_of_run, now, stored_at, tracked_since); if (hist->start_of_run < latest_possible_start + wrl) latest_possible_start = hist->start_of_run - wrl; hist->weighted_run_length = wrl; hist->total_run_weights = trw; } if (have_wfu) { if (wfu_timebuf[0]) { wfu_timebuf[10] = ' '; if (parse_possibly_bad_iso_time(wfu_timebuf, &start_of_downtime)<0) log_warn(LD_HIST, "Couldn't parse time %s", escaped(wfu_timebuf)); } } hist->start_of_downtime = correct_time(start_of_downtime, now, stored_at, tracked_since); hist->weighted_uptime = wt_uptime; hist->total_weighted_time = total_wt_time; } if (strcmp(line, ".")) log_warn(LD_HIST, "Truncated MTBF file."); if (tracked_since < 86400*365) /* Recover from insanely early value. */ tracked_since = latest_possible_start; stability_last_downrated = last_downrated; started_tracking_stability = tracked_since; goto done; err: r = -1; done: SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); smartlist_free(lines); return r; } /** For how many seconds do we keep track of individual per-second bandwidth * totals? */ #define NUM_SECS_ROLLING_MEASURE 10 /** How large are the intervals for which we track and report bandwidth use? */ /* XXXX Watch out! Before Tor 0.2.2.21-alpha, using any other value here would * generate an unparseable state file. */ #define NUM_SECS_BW_SUM_INTERVAL (15*60) /** How far in the past do we remember and publish bandwidth use? */ #define NUM_SECS_BW_SUM_IS_VALID (24*60*60) /** How many bandwidth usage intervals do we remember? (derived) */ #define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL) /** Structure to track bandwidth use, and remember the maxima for a given * time period. */ typedef struct bw_array_t { /** Observation array: Total number of bytes transferred in each of the last * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */ uint64_t obs[NUM_SECS_ROLLING_MEASURE]; int cur_obs_idx; /**< Current position in obs. */ time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */ uint64_t total_obs; /**< Total for all members of obs except * obs[cur_obs_idx] */ uint64_t max_total; /**< Largest value that total_obs has taken on in the * current period. */ uint64_t total_in_period; /**< Total bytes transferred in the current * period. */ /** When does the next period begin? */ time_t next_period; /** Where in 'maxima' should the maximum bandwidth usage for the current * period be stored? */ int next_max_idx; /** How many values in maxima/totals have been set ever? */ int num_maxes_set; /** Circular array of the maximum * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last * NUM_TOTALS periods */ uint64_t maxima[NUM_TOTALS]; /** Circular array of the total bandwidth usage for the last NUM_TOTALS * periods */ uint64_t totals[NUM_TOTALS]; } bw_array_t; /** Shift the current period of b forward by one. */ static void commit_max(bw_array_t *b) { /* Store total from current period. */ b->totals[b->next_max_idx] = b->total_in_period; /* Store maximum from current period. */ b->maxima[b->next_max_idx++] = b->max_total; /* Advance next_period and next_max_idx */ b->next_period += NUM_SECS_BW_SUM_INTERVAL; if (b->next_max_idx == NUM_TOTALS) b->next_max_idx = 0; if (b->num_maxes_set < NUM_TOTALS) ++b->num_maxes_set; /* Reset max_total. */ b->max_total = 0; /* Reset total_in_period. */ b->total_in_period = 0; } /** Shift the current observation time of b forward by one second. */ static INLINE void advance_obs(bw_array_t *b) { int nextidx; uint64_t total; /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE * seconds; adjust max_total as needed.*/ total = b->total_obs + b->obs[b->cur_obs_idx]; if (total > b->max_total) b->max_total = total; nextidx = b->cur_obs_idx+1; if (nextidx == NUM_SECS_ROLLING_MEASURE) nextidx = 0; b->total_obs = total - b->obs[nextidx]; b->obs[nextidx]=0; b->cur_obs_idx = nextidx; if (++b->cur_obs_time >= b->next_period) commit_max(b); } /** Add n bytes to the number of bytes in b for second * when. */ static INLINE void add_obs(bw_array_t *b, time_t when, uint64_t n) { if (when < b->cur_obs_time) return; /* Don't record data in the past. */ /* If we're currently adding observations for an earlier second than * 'when', advance b->cur_obs_time and b->cur_obs_idx by an * appropriate number of seconds, and do all the other housekeeping. */ while (when > b->cur_obs_time) { /* Doing this one second at a time is potentially inefficient, if we start with a state file that is very old. Fortunately, it doesn't seem to show up in profiles, so we can just ignore it for now. */ advance_obs(b); } b->obs[b->cur_obs_idx] += n; b->total_in_period += n; } /** Allocate, initialize, and return a new bw_array. */ static bw_array_t * bw_array_new(void) { bw_array_t *b; time_t start; b = tor_malloc_zero(sizeof(bw_array_t)); rephist_total_alloc += sizeof(bw_array_t); start = time(NULL); b->cur_obs_time = start; b->next_period = start + NUM_SECS_BW_SUM_INTERVAL; return b; } /** Recent history of bandwidth observations for read operations. */ static bw_array_t *read_array = NULL; /** Recent history of bandwidth observations for write operations. */ static bw_array_t *write_array = NULL; /** Recent history of bandwidth observations for read operations for the directory protocol. */ static bw_array_t *dir_read_array = NULL; /** Recent history of bandwidth observations for write operations for the directory protocol. */ static bw_array_t *dir_write_array = NULL; /** Set up [dir-]read_array and [dir-]write_array, freeing them if they * already exist. */ static void bw_arrays_init(void) { tor_free(read_array); tor_free(write_array); tor_free(dir_read_array); tor_free(dir_write_array); read_array = bw_array_new(); write_array = bw_array_new(); dir_read_array = bw_array_new(); dir_write_array = bw_array_new(); } /** Remember that we read num_bytes bytes in second when. * * Add num_bytes to the current running total for when. * * when can go back to time, but it's safe to ignore calls * earlier than the latest when you've heard of. */ void rep_hist_note_bytes_written(size_t num_bytes, time_t when) { /* Maybe a circular array for recent seconds, and step to a new point * every time a new second shows up. Or simpler is to just to have * a normal array and push down each item every second; it's short. */ /* When a new second has rolled over, compute the sum of the bytes we've * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it * somewhere. See rep_hist_bandwidth_assess() below. */ add_obs(write_array, when, num_bytes); } /** Remember that we wrote num_bytes bytes in second when. * (like rep_hist_note_bytes_written() above) */ void rep_hist_note_bytes_read(size_t num_bytes, time_t when) { /* if we're smart, we can make this func and the one above share code */ add_obs(read_array, when, num_bytes); } /** Remember that we wrote num_bytes directory bytes in second * when. (like rep_hist_note_bytes_written() above) */ void rep_hist_note_dir_bytes_written(size_t num_bytes, time_t when) { add_obs(dir_write_array, when, num_bytes); } /** Remember that we read num_bytes directory bytes in second * when. (like rep_hist_note_bytes_written() above) */ void rep_hist_note_dir_bytes_read(size_t num_bytes, time_t when) { add_obs(dir_read_array, when, num_bytes); } /** Helper: Return the largest value in b->maxima. (This is equal to the * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last * NUM_SECS_BW_SUM_IS_VALID seconds.) */ static uint64_t find_largest_max(bw_array_t *b) { int i; uint64_t max; max=0; for (i=0; imaxima[i]>max) max = b->maxima[i]; } return max; } /** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly) * seconds. Find one sum for reading and one for writing. They don't have * to be at the same time. * * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE. */ int rep_hist_bandwidth_assess(void) { uint64_t w,r; r = find_largest_max(read_array); w = find_largest_max(write_array); if (r>w) return (int)(U64_TO_DBL(w)/NUM_SECS_ROLLING_MEASURE); else return (int)(U64_TO_DBL(r)/NUM_SECS_ROLLING_MEASURE); } /** Print the bandwidth history of b (either [dir-]read_array or * [dir-]write_array) into the buffer pointed to by buf. The format is * simply comma separated numbers, from oldest to newest. * * It returns the number of bytes written. */ static size_t rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b) { char *cp = buf; int i, n; const or_options_t *options = get_options(); uint64_t cutoff; if (b->num_maxes_set <= b->next_max_idx) { /* We haven't been through the circular array yet; time starts at i=0.*/ i = 0; } else { /* We've been around the array at least once. The next i to be overwritten is the oldest. */ i = b->next_max_idx; } if (options->RelayBandwidthRate) { /* We don't want to report that we used more bandwidth than the max we're * willing to relay; otherwise everybody will know how much traffic * we used ourself. */ cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL; } else { cutoff = UINT64_MAX; } for (n=0; nnum_maxes_set; ++n,++i) { uint64_t total; if (i >= NUM_TOTALS) i -= NUM_TOTALS; tor_assert(i < NUM_TOTALS); /* Round the bandwidth used down to the nearest 1k. */ total = b->totals[i] & ~0x3ff; if (total > cutoff) total = cutoff; if (n==(b->num_maxes_set-1)) tor_snprintf(cp, len-(cp-buf), U64_FORMAT, U64_PRINTF_ARG(total)); else tor_snprintf(cp, len-(cp-buf), U64_FORMAT",", U64_PRINTF_ARG(total)); cp += strlen(cp); } return cp-buf; } /** Allocate and return lines for representing this server's bandwidth * history in its descriptor. We publish these lines in our extra-info * descriptor. */ char * rep_hist_get_bandwidth_lines(void) { char *buf, *cp; char t[ISO_TIME_LEN+1]; int r; bw_array_t *b = NULL; const char *desc = NULL; size_t len; /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */ /* The n,n,n part above. Largest representation of a uint64_t is 20 chars * long, plus the comma. */ #define MAX_HIST_VALUE_LEN (21*NUM_TOTALS) len = (67+MAX_HIST_VALUE_LEN)*4; buf = tor_malloc_zero(len); cp = buf; for (r=0;r<4;++r) { char tmp[MAX_HIST_VALUE_LEN]; size_t slen; switch (r) { case 0: b = write_array; desc = "write-history"; break; case 1: b = read_array; desc = "read-history"; break; case 2: b = dir_write_array; desc = "dirreq-write-history"; break; case 3: b = dir_read_array; desc = "dirreq-read-history"; break; } tor_assert(b); slen = rep_hist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b); /* If we don't have anything to write, skip to the next entry. */ if (slen == 0) continue; format_iso_time(t, b->next_period-NUM_SECS_BW_SUM_INTERVAL); tor_snprintf(cp, len-(cp-buf), "%s %s (%d s) ", desc, t, NUM_SECS_BW_SUM_INTERVAL); cp += strlen(cp); strlcat(cp, tmp, len-(cp-buf)); cp += slen; strlcat(cp, "\n", len-(cp-buf)); ++cp; } return buf; } /** Write a single bw_array_t into the Values, Ends, Interval, and Maximum * entries of an or_state_t. Done before writing out a new state file. */ static void rep_hist_update_bwhist_state_section(or_state_t *state, const bw_array_t *b, smartlist_t **s_values, smartlist_t **s_maxima, time_t *s_begins, int *s_interval) { int i,j; uint64_t maxval; if (*s_values) { SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val)); smartlist_free(*s_values); } if (*s_maxima) { SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val)); smartlist_free(*s_maxima); } if (! server_mode(get_options())) { /* Clients don't need to store bandwidth history persistently; * force these values to the defaults. */ /* FFFF we should pull the default out of config.c's state table, * so we don't have two defaults. */ if (*s_begins != 0 || *s_interval != 900) { time_t now = time(NULL); time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600; or_state_mark_dirty(state, save_at); } *s_begins = 0; *s_interval = 900; *s_values = smartlist_new(); *s_maxima = smartlist_new(); return; } *s_begins = b->next_period; *s_interval = NUM_SECS_BW_SUM_INTERVAL; *s_values = smartlist_new(); *s_maxima = smartlist_new(); /* Set i to first position in circular array */ i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx; for (j=0; j < b->num_maxes_set; ++j,++i) { if (i >= NUM_TOTALS) i = 0; smartlist_add_asprintf(*s_values, U64_FORMAT, U64_PRINTF_ARG(b->totals[i] & ~0x3ff)); maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE; smartlist_add_asprintf(*s_maxima, U64_FORMAT, U64_PRINTF_ARG(maxval & ~0x3ff)); } smartlist_add_asprintf(*s_values, U64_FORMAT, U64_PRINTF_ARG(b->total_in_period & ~0x3ff)); maxval = b->max_total / NUM_SECS_ROLLING_MEASURE; smartlist_add_asprintf(*s_maxima, U64_FORMAT, U64_PRINTF_ARG(maxval & ~0x3ff)); } /** Update state with the newest bandwidth history. Done before * writing out a new state file. */ void rep_hist_update_state(or_state_t *state) { #define UPDATE(arrname,st) \ rep_hist_update_bwhist_state_section(state,\ (arrname),\ &state->BWHistory ## st ## Values, \ &state->BWHistory ## st ## Maxima, \ &state->BWHistory ## st ## Ends, \ &state->BWHistory ## st ## Interval) UPDATE(write_array, Write); UPDATE(read_array, Read); UPDATE(dir_write_array, DirWrite); UPDATE(dir_read_array, DirRead); if (server_mode(get_options())) { or_state_mark_dirty(state, time(NULL)+(2*3600)); } #undef UPDATE } /** Load a single bw_array_t from its Values, Ends, Maxima, and Interval * entries in an or_state_t. Done while reading the state file. */ static int rep_hist_load_bwhist_state_section(bw_array_t *b, const smartlist_t *s_values, const smartlist_t *s_maxima, const time_t s_begins, const int s_interval) { time_t now = time(NULL); int retval = 0; time_t start; uint64_t v, mv; int i,ok,ok_m; int have_maxima = s_maxima && s_values && (smartlist_len(s_values) == smartlist_len(s_maxima)); if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) { start = s_begins - s_interval*(smartlist_len(s_values)); if (start > now) return 0; b->cur_obs_time = start; b->next_period = start + NUM_SECS_BW_SUM_INTERVAL; SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) { const char *maxstr = NULL; v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL); if (have_maxima) { maxstr = smartlist_get(s_maxima, cp_sl_idx); mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL); mv *= NUM_SECS_ROLLING_MEASURE; } else { /* No maxima known; guess average rate to be conservative. */ mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE; } if (!ok) { retval = -1; log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp); } if (maxstr && !ok_m) { retval = -1; log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'", maxstr); } if (start < now) { time_t cur_start = start; time_t actual_interval_len = s_interval; uint64_t cur_val = 0; /* Calculate the average per second. This is the best we can do * because our state file doesn't have per-second resolution. */ if (start + s_interval > now) actual_interval_len = now - start; cur_val = v / actual_interval_len; /* This is potentially inefficient, but since we don't do it very * often it should be ok. */ while (cur_start < start + actual_interval_len) { add_obs(b, cur_start, cur_val); ++cur_start; } b->max_total = mv; /* This will result in some fairly choppy history if s_interval * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */ start += actual_interval_len; } } SMARTLIST_FOREACH_END(cp); } /* Clean up maxima and observed */ for (i=0; iobs[i] = 0; } b->total_obs = 0; return retval; } /** Set bandwidth history from the state file we just loaded. */ int rep_hist_load_state(or_state_t *state, char **err) { int all_ok = 1; /* Assert they already have been malloced */ tor_assert(read_array && write_array); tor_assert(dir_read_array && dir_write_array); #define LOAD(arrname,st) \ if (rep_hist_load_bwhist_state_section( \ (arrname), \ state->BWHistory ## st ## Values, \ state->BWHistory ## st ## Maxima, \ state->BWHistory ## st ## Ends, \ state->BWHistory ## st ## Interval)<0) \ all_ok = 0 LOAD(write_array, Write); LOAD(read_array, Read); LOAD(dir_write_array, DirWrite); LOAD(dir_read_array, DirRead); #undef LOAD if (!all_ok) { *err = tor_strdup("Parsing of bandwidth history values failed"); /* and create fresh arrays */ bw_arrays_init(); return -1; } return 0; } /*********************************************************************/ /** A single predicted port: used to remember which ports we've made * connections to, so that we can try to keep making circuits that can handle * those ports. */ typedef struct predicted_port_t { /** The port we connected to */ uint16_t port; /** The time at which we last used it */ time_t time; } predicted_port_t; /** A list of port numbers that have been used recently. */ static smartlist_t *predicted_ports_list=NULL; /** We just got an application request for a connection with * port port. Remember it for the future, so we can keep * some circuits open that will exit to this port. */ static void add_predicted_port(time_t now, uint16_t port) { predicted_port_t *pp = tor_malloc(sizeof(predicted_port_t)); pp->port = port; pp->time = now; rephist_total_alloc += sizeof(*pp); smartlist_add(predicted_ports_list, pp); } /** Initialize whatever memory and structs are needed for predicting * which ports will be used. Also seed it with port 80, so we'll build * circuits on start-up. */ static void predicted_ports_init(void) { predicted_ports_list = smartlist_new(); add_predicted_port(time(NULL), 80); /* add one to kickstart us */ } /** Free whatever memory is needed for predicting which ports will * be used. */ static void predicted_ports_free(void) { rephist_total_alloc -= smartlist_len(predicted_ports_list)*sizeof(predicted_port_t); SMARTLIST_FOREACH(predicted_ports_list, predicted_port_t *, pp, tor_free(pp)); smartlist_free(predicted_ports_list); } /** Remember that port has been asked for as of time now. * This is used for predicting what sorts of streams we'll make in the * future and making exit circuits to anticipate that. */ void rep_hist_note_used_port(time_t now, uint16_t port) { tor_assert(predicted_ports_list); if (!port) /* record nothing */ return; SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) { if (pp->port == port) { pp->time = now; return; } } SMARTLIST_FOREACH_END(pp); /* it's not there yet; we need to add it */ add_predicted_port(now, port); } /** For this long after we've seen a request for a given port, assume that * we'll want to make connections to the same port in the future. */ #define PREDICTED_CIRCS_RELEVANCE_TIME (60*60) /** Return a newly allocated pointer to a list of uint16_t * for ports that * are likely to be asked for in the near future. */ smartlist_t * rep_hist_get_predicted_ports(time_t now) { smartlist_t *out = smartlist_new(); tor_assert(predicted_ports_list); /* clean out obsolete entries */ SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) { if (pp->time + PREDICTED_CIRCS_RELEVANCE_TIME < now) { log_debug(LD_CIRC, "Expiring predicted port %d", pp->port); rephist_total_alloc -= sizeof(predicted_port_t); tor_free(pp); SMARTLIST_DEL_CURRENT(predicted_ports_list, pp); } else { smartlist_add(out, tor_memdup(&pp->port, sizeof(uint16_t))); } } SMARTLIST_FOREACH_END(pp); return out; } /** * Take a list of uint16_t *, and remove every port in the list from the * current list of predicted ports. */ void rep_hist_remove_predicted_ports(const smartlist_t *rmv_ports) { /* Let's do this on O(N), not O(N^2). */ bitarray_t *remove_ports = bitarray_init_zero(UINT16_MAX); SMARTLIST_FOREACH(rmv_ports, const uint16_t *, p, bitarray_set(remove_ports, *p)); SMARTLIST_FOREACH_BEGIN(predicted_ports_list, predicted_port_t *, pp) { if (bitarray_is_set(remove_ports, pp->port)) { tor_free(pp); SMARTLIST_DEL_CURRENT(predicted_ports_list, pp); } } SMARTLIST_FOREACH_END(pp); bitarray_free(remove_ports); } /** The user asked us to do a resolve. Rather than keeping track of * timings and such of resolves, we fake it for now by treating * it the same way as a connection to port 80. This way we will continue * to have circuits lying around if the user only uses Tor for resolves. */ void rep_hist_note_used_resolve(time_t now) { rep_hist_note_used_port(now, 80); } /** The last time at which we needed an internal circ. */ static time_t predicted_internal_time = 0; /** The last time we needed an internal circ with good uptime. */ static time_t predicted_internal_uptime_time = 0; /** The last time we needed an internal circ with good capacity. */ static time_t predicted_internal_capacity_time = 0; /** Remember that we used an internal circ at time now. */ void rep_hist_note_used_internal(time_t now, int need_uptime, int need_capacity) { predicted_internal_time = now; if (need_uptime) predicted_internal_uptime_time = now; if (need_capacity) predicted_internal_capacity_time = now; } /** Return 1 if we've used an internal circ recently; else return 0. */ int rep_hist_get_predicted_internal(time_t now, int *need_uptime, int *need_capacity) { if (!predicted_internal_time) { /* initialize it */ predicted_internal_time = now; predicted_internal_uptime_time = now; predicted_internal_capacity_time = now; } if (predicted_internal_time + PREDICTED_CIRCS_RELEVANCE_TIME < now) return 0; /* too long ago */ if (predicted_internal_uptime_time + PREDICTED_CIRCS_RELEVANCE_TIME >= now) *need_uptime = 1; // Always predict that we need capacity. *need_capacity = 1; return 1; } /** Any ports used lately? These are pre-seeded if we just started * up or if we're running a hidden service. */ int any_predicted_circuits(time_t now) { return smartlist_len(predicted_ports_list) || predicted_internal_time + PREDICTED_CIRCS_RELEVANCE_TIME >= now; } /** Return 1 if we have no need for circuits currently, else return 0. */ int rep_hist_circbuilding_dormant(time_t now) { if (any_predicted_circuits(now)) return 0; /* see if we'll still need to build testing circuits */ if (server_mode(get_options()) && (!check_whether_orport_reachable() || !circuit_enough_testing_circs())) return 0; if (!check_whether_dirport_reachable()) return 0; return 1; } /** Structure to track how many times we've done each public key operation. */ static struct { /** How many directory objects have we signed? */ unsigned long n_signed_dir_objs; /** How many routerdescs have we signed? */ unsigned long n_signed_routerdescs; /** How many directory objects have we verified? */ unsigned long n_verified_dir_objs; /** How many routerdescs have we verified */ unsigned long n_verified_routerdescs; /** How many onionskins have we encrypted to build circuits? */ unsigned long n_onionskins_encrypted; /** How many onionskins have we decrypted to do circuit build requests? */ unsigned long n_onionskins_decrypted; /** How many times have we done the TLS handshake as a client? */ unsigned long n_tls_client_handshakes; /** How many times have we done the TLS handshake as a server? */ unsigned long n_tls_server_handshakes; /** How many PK operations have we done as a hidden service client? */ unsigned long n_rend_client_ops; /** How many PK operations have we done as a hidden service midpoint? */ unsigned long n_rend_mid_ops; /** How many PK operations have we done as a hidden service provider? */ unsigned long n_rend_server_ops; } pk_op_counts = {0,0,0,0,0,0,0,0,0,0,0}; /** Increment the count of the number of times we've done operation. */ void note_crypto_pk_op(pk_op_t operation) { switch (operation) { case SIGN_DIR: pk_op_counts.n_signed_dir_objs++; break; case SIGN_RTR: pk_op_counts.n_signed_routerdescs++; break; case VERIFY_DIR: pk_op_counts.n_verified_dir_objs++; break; case VERIFY_RTR: pk_op_counts.n_verified_routerdescs++; break; case ENC_ONIONSKIN: pk_op_counts.n_onionskins_encrypted++; break; case DEC_ONIONSKIN: pk_op_counts.n_onionskins_decrypted++; break; case TLS_HANDSHAKE_C: pk_op_counts.n_tls_client_handshakes++; break; case TLS_HANDSHAKE_S: pk_op_counts.n_tls_server_handshakes++; break; case REND_CLIENT: pk_op_counts.n_rend_client_ops++; break; case REND_MID: pk_op_counts.n_rend_mid_ops++; break; case REND_SERVER: pk_op_counts.n_rend_server_ops++; break; default: log_warn(LD_BUG, "Unknown pk operation %d", operation); } } /** Log the number of times we've done each public/private-key operation. */ void dump_pk_ops(int severity) { tor_log(severity, LD_HIST, "PK operations: %lu directory objects signed, " "%lu directory objects verified, " "%lu routerdescs signed, " "%lu routerdescs verified, " "%lu onionskins encrypted, " "%lu onionskins decrypted, " "%lu client-side TLS handshakes, " "%lu server-side TLS handshakes, " "%lu rendezvous client operations, " "%lu rendezvous middle operations, " "%lu rendezvous server operations.", pk_op_counts.n_signed_dir_objs, pk_op_counts.n_verified_dir_objs, pk_op_counts.n_signed_routerdescs, pk_op_counts.n_verified_routerdescs, pk_op_counts.n_onionskins_encrypted, pk_op_counts.n_onionskins_decrypted, pk_op_counts.n_tls_client_handshakes, pk_op_counts.n_tls_server_handshakes, pk_op_counts.n_rend_client_ops, pk_op_counts.n_rend_mid_ops, pk_op_counts.n_rend_server_ops); } /*** Exit port statistics ***/ /* Some constants */ /** To what multiple should byte numbers be rounded up? */ #define EXIT_STATS_ROUND_UP_BYTES 1024 /** To what multiple should stream counts be rounded up? */ #define EXIT_STATS_ROUND_UP_STREAMS 4 /** Number of TCP ports */ #define EXIT_STATS_NUM_PORTS 65536 /** Top n ports that will be included in exit stats. */ #define EXIT_STATS_TOP_N_PORTS 10 /* The following data structures are arrays and no fancy smartlists or maps, * so that all write operations can be done in constant time. This comes at * the price of some memory (1.25 MB) and linear complexity when writing * stats for measuring relays. */ /** Number of bytes read in current period by exit port */ static uint64_t *exit_bytes_read = NULL; /** Number of bytes written in current period by exit port */ static uint64_t *exit_bytes_written = NULL; /** Number of streams opened in current period by exit port */ static uint32_t *exit_streams = NULL; /** Start time of exit stats or 0 if we're not collecting exit stats. */ static time_t start_of_exit_stats_interval; /** Initialize exit port stats. */ void rep_hist_exit_stats_init(time_t now) { start_of_exit_stats_interval = now; exit_bytes_read = tor_malloc_zero(EXIT_STATS_NUM_PORTS * sizeof(uint64_t)); exit_bytes_written = tor_malloc_zero(EXIT_STATS_NUM_PORTS * sizeof(uint64_t)); exit_streams = tor_malloc_zero(EXIT_STATS_NUM_PORTS * sizeof(uint32_t)); } /** Reset counters for exit port statistics. */ void rep_hist_reset_exit_stats(time_t now) { start_of_exit_stats_interval = now; memset(exit_bytes_read, 0, EXIT_STATS_NUM_PORTS * sizeof(uint64_t)); memset(exit_bytes_written, 0, EXIT_STATS_NUM_PORTS * sizeof(uint64_t)); memset(exit_streams, 0, EXIT_STATS_NUM_PORTS * sizeof(uint32_t)); } /** Stop collecting exit port stats in a way that we can re-start doing * so in rep_hist_exit_stats_init(). */ void rep_hist_exit_stats_term(void) { start_of_exit_stats_interval = 0; tor_free(exit_bytes_read); tor_free(exit_bytes_written); tor_free(exit_streams); } /** Helper for qsort: compare two ints. Does not handle overflow properly, * but works fine for sorting an array of port numbers, which is what we use * it for. */ static int compare_int_(const void *x, const void *y) { return (*(int*)x - *(int*)y); } /** Return a newly allocated string containing the exit port statistics * until now, or NULL if we're not collecting exit stats. Caller * must ensure start_of_exit_stats_interval is in the past. */ char * rep_hist_format_exit_stats(time_t now) { int i, j, top_elements = 0, cur_min_idx = 0, cur_port; uint64_t top_bytes[EXIT_STATS_TOP_N_PORTS]; int top_ports[EXIT_STATS_TOP_N_PORTS]; uint64_t cur_bytes = 0, other_read = 0, other_written = 0, total_read = 0, total_written = 0; uint32_t total_streams = 0, other_streams = 0; smartlist_t *written_strings, *read_strings, *streams_strings; char *written_string, *read_string, *streams_string; char t[ISO_TIME_LEN+1]; char *result; if (!start_of_exit_stats_interval) return NULL; /* Not initialized. */ tor_assert(now >= start_of_exit_stats_interval); /* Go through all ports to find the n ports that saw most written and * read bytes. * * Invariant: at the end of the loop for iteration i, * total_read is the sum of all exit_bytes_read[0..i] * total_written is the sum of all exit_bytes_written[0..i] * total_stream is the sum of all exit_streams[0..i] * * top_elements = MAX(EXIT_STATS_TOP_N_PORTS, * #{j | 0 <= j <= i && volume(i) > 0}) * * For all 0 <= j < top_elements, * top_bytes[j] > 0 * 0 <= top_ports[j] <= 65535 * top_bytes[j] = volume(top_ports[j]) * * There is no j in 0..i and k in 0..top_elements such that: * volume(j) > top_bytes[k] AND j is not in top_ports[0..top_elements] * * There is no j!=cur_min_idx in 0..top_elements such that: * top_bytes[j] < top_bytes[cur_min_idx] * * where volume(x) == exit_bytes_read[x]+exit_bytes_written[x] * * Worst case: O(EXIT_STATS_NUM_PORTS * EXIT_STATS_TOP_N_PORTS) */ for (i = 1; i < EXIT_STATS_NUM_PORTS; i++) { total_read += exit_bytes_read[i]; total_written += exit_bytes_written[i]; total_streams += exit_streams[i]; cur_bytes = exit_bytes_read[i] + exit_bytes_written[i]; if (cur_bytes == 0) { continue; } if (top_elements < EXIT_STATS_TOP_N_PORTS) { top_bytes[top_elements] = cur_bytes; top_ports[top_elements++] = i; } else if (cur_bytes > top_bytes[cur_min_idx]) { top_bytes[cur_min_idx] = cur_bytes; top_ports[cur_min_idx] = i; } else { continue; } cur_min_idx = 0; for (j = 1; j < top_elements; j++) { if (top_bytes[j] < top_bytes[cur_min_idx]) { cur_min_idx = j; } } } /* Add observations of top ports to smartlists. */ written_strings = smartlist_new(); read_strings = smartlist_new(); streams_strings = smartlist_new(); other_read = total_read; other_written = total_written; other_streams = total_streams; /* Sort the ports; this puts them out of sync with top_bytes, but we * won't be using top_bytes again anyway */ qsort(top_ports, top_elements, sizeof(int), compare_int_); for (j = 0; j < top_elements; j++) { cur_port = top_ports[j]; if (exit_bytes_written[cur_port] > 0) { uint64_t num = round_uint64_to_next_multiple_of( exit_bytes_written[cur_port], EXIT_STATS_ROUND_UP_BYTES); num /= 1024; smartlist_add_asprintf(written_strings, "%d="U64_FORMAT, cur_port, U64_PRINTF_ARG(num)); other_written -= exit_bytes_written[cur_port]; } if (exit_bytes_read[cur_port] > 0) { uint64_t num = round_uint64_to_next_multiple_of( exit_bytes_read[cur_port], EXIT_STATS_ROUND_UP_BYTES); num /= 1024; smartlist_add_asprintf(read_strings, "%d="U64_FORMAT, cur_port, U64_PRINTF_ARG(num)); other_read -= exit_bytes_read[cur_port]; } if (exit_streams[cur_port] > 0) { uint32_t num = round_uint32_to_next_multiple_of( exit_streams[cur_port], EXIT_STATS_ROUND_UP_STREAMS); smartlist_add_asprintf(streams_strings, "%d=%u", cur_port, num); other_streams -= exit_streams[cur_port]; } } /* Add observations of other ports in a single element. */ other_written = round_uint64_to_next_multiple_of(other_written, EXIT_STATS_ROUND_UP_BYTES); other_written /= 1024; smartlist_add_asprintf(written_strings, "other="U64_FORMAT, U64_PRINTF_ARG(other_written)); other_read = round_uint64_to_next_multiple_of(other_read, EXIT_STATS_ROUND_UP_BYTES); other_read /= 1024; smartlist_add_asprintf(read_strings, "other="U64_FORMAT, U64_PRINTF_ARG(other_read)); other_streams = round_uint32_to_next_multiple_of(other_streams, EXIT_STATS_ROUND_UP_STREAMS); smartlist_add_asprintf(streams_strings, "other=%u", other_streams); /* Join all observations in single strings. */ written_string = smartlist_join_strings(written_strings, ",", 0, NULL); read_string = smartlist_join_strings(read_strings, ",", 0, NULL); streams_string = smartlist_join_strings(streams_strings, ",", 0, NULL); SMARTLIST_FOREACH(written_strings, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(read_strings, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(streams_strings, char *, cp, tor_free(cp)); smartlist_free(written_strings); smartlist_free(read_strings); smartlist_free(streams_strings); /* Put everything together. */ format_iso_time(t, now); tor_asprintf(&result, "exit-stats-end %s (%d s)\n" "exit-kibibytes-written %s\n" "exit-kibibytes-read %s\n" "exit-streams-opened %s\n", t, (unsigned) (now - start_of_exit_stats_interval), written_string, read_string, streams_string); tor_free(written_string); tor_free(read_string); tor_free(streams_string); return result; } /** If 24 hours have passed since the beginning of the current exit port * stats period, write exit stats to $DATADIR/stats/exit-stats (possibly * overwriting an existing file) and reset counters. Return when we would * next want to write exit stats or 0 if we never want to write. */ time_t rep_hist_exit_stats_write(time_t now) { char *statsdir = NULL, *filename = NULL, *str = NULL; if (!start_of_exit_stats_interval) return 0; /* Not initialized. */ if (start_of_exit_stats_interval + WRITE_STATS_INTERVAL > now) goto done; /* Not ready to write. */ log_info(LD_HIST, "Writing exit port statistics to disk."); /* Generate history string. */ str = rep_hist_format_exit_stats(now); /* Reset counters. */ rep_hist_reset_exit_stats(now); /* Try to write to disk. */ statsdir = get_datadir_fname("stats"); if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { log_warn(LD_HIST, "Unable to create stats/ directory!"); goto done; } filename = get_datadir_fname2("stats", "exit-stats"); if (write_str_to_file(filename, str, 0) < 0) log_warn(LD_HIST, "Unable to write exit port statistics to disk!"); done: tor_free(str); tor_free(statsdir); tor_free(filename); return start_of_exit_stats_interval + WRITE_STATS_INTERVAL; } /** Note that we wrote num_written bytes and read num_read * bytes to/from an exit connection to port. */ void rep_hist_note_exit_bytes(uint16_t port, size_t num_written, size_t num_read) { if (!start_of_exit_stats_interval) return; /* Not initialized. */ exit_bytes_written[port] += num_written; exit_bytes_read[port] += num_read; log_debug(LD_HIST, "Written %lu bytes and read %lu bytes to/from an " "exit connection to port %d.", (unsigned long)num_written, (unsigned long)num_read, port); } /** Note that we opened an exit stream to port. */ void rep_hist_note_exit_stream_opened(uint16_t port) { if (!start_of_exit_stats_interval) return; /* Not initialized. */ exit_streams[port]++; log_debug(LD_HIST, "Opened exit stream to port %d", port); } /*** cell statistics ***/ /** Start of the current buffer stats interval or 0 if we're not * collecting buffer statistics. */ static time_t start_of_buffer_stats_interval; /** Initialize buffer stats. */ void rep_hist_buffer_stats_init(time_t now) { start_of_buffer_stats_interval = now; } /** Statistics from a single circuit. Collected when the circuit closes, or * when we flush statistics to disk. */ typedef struct circ_buffer_stats_t { /** Average number of cells in the circuit's queue */ double mean_num_cells_in_queue; /** Average time a cell waits in the queue. */ double mean_time_cells_in_queue; /** Total number of cells sent over this circuit */ uint32_t processed_cells; } circ_buffer_stats_t; /** List of circ_buffer_stats_t. */ static smartlist_t *circuits_for_buffer_stats = NULL; /** Remember cell statistics mean_num_cells_in_queue, * mean_time_cells_in_queue, and processed_cells of a * circuit. */ void rep_hist_add_buffer_stats(double mean_num_cells_in_queue, double mean_time_cells_in_queue, uint32_t processed_cells) { circ_buffer_stats_t *stat; if (!start_of_buffer_stats_interval) return; /* Not initialized. */ stat = tor_malloc_zero(sizeof(circ_buffer_stats_t)); stat->mean_num_cells_in_queue = mean_num_cells_in_queue; stat->mean_time_cells_in_queue = mean_time_cells_in_queue; stat->processed_cells = processed_cells; if (!circuits_for_buffer_stats) circuits_for_buffer_stats = smartlist_new(); smartlist_add(circuits_for_buffer_stats, stat); } /** Remember cell statistics for circuit circ at time * end_of_interval and reset cell counters in case the circuit * remains open in the next measurement interval. */ void rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval) { time_t start_of_interval; int interval_length; or_circuit_t *orcirc; double mean_num_cells_in_queue, mean_time_cells_in_queue; uint32_t processed_cells; if (CIRCUIT_IS_ORIGIN(circ)) return; orcirc = TO_OR_CIRCUIT(circ); if (!orcirc->processed_cells) return; start_of_interval = (circ->timestamp_created.tv_sec > start_of_buffer_stats_interval) ? circ->timestamp_created.tv_sec : start_of_buffer_stats_interval; interval_length = (int) (end_of_interval - start_of_interval); if (interval_length <= 0) return; processed_cells = orcirc->processed_cells; /* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */ mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time / (double) interval_length / 1000.0 / 2.0; mean_time_cells_in_queue = (double) orcirc->total_cell_waiting_time / (double) orcirc->processed_cells; orcirc->total_cell_waiting_time = 0; orcirc->processed_cells = 0; rep_hist_add_buffer_stats(mean_num_cells_in_queue, mean_time_cells_in_queue, processed_cells); } /** Sorting helper: return -1, 1, or 0 based on comparison of two * circ_buffer_stats_t */ static int buffer_stats_compare_entries_(const void **_a, const void **_b) { const circ_buffer_stats_t *a = *_a, *b = *_b; if (a->processed_cells < b->processed_cells) return 1; else if (a->processed_cells > b->processed_cells) return -1; else return 0; } /** Stop collecting cell stats in a way that we can re-start doing so in * rep_hist_buffer_stats_init(). */ void rep_hist_buffer_stats_term(void) { rep_hist_reset_buffer_stats(0); } /** Clear history of circuit statistics and set the measurement interval * start to now. */ void rep_hist_reset_buffer_stats(time_t now) { if (!circuits_for_buffer_stats) circuits_for_buffer_stats = smartlist_new(); SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *, stat, tor_free(stat)); smartlist_clear(circuits_for_buffer_stats); start_of_buffer_stats_interval = now; } /** Return a newly allocated string containing the buffer statistics until * now, or NULL if we're not collecting buffer stats. Caller must * ensure start_of_buffer_stats_interval is in the past. */ char * rep_hist_format_buffer_stats(time_t now) { #define SHARES 10 uint64_t processed_cells[SHARES]; uint32_t circs_in_share[SHARES]; int number_of_circuits, i; double queued_cells[SHARES], time_in_queue[SHARES]; smartlist_t *processed_cells_strings, *queued_cells_strings, *time_in_queue_strings; char *processed_cells_string, *queued_cells_string, *time_in_queue_string; char t[ISO_TIME_LEN+1]; char *result; if (!start_of_buffer_stats_interval) return NULL; /* Not initialized. */ tor_assert(now >= start_of_buffer_stats_interval); /* Calculate deciles if we saw at least one circuit. */ memset(processed_cells, 0, SHARES * sizeof(uint64_t)); memset(circs_in_share, 0, SHARES * sizeof(uint32_t)); memset(queued_cells, 0, SHARES * sizeof(double)); memset(time_in_queue, 0, SHARES * sizeof(double)); if (!circuits_for_buffer_stats) circuits_for_buffer_stats = smartlist_new(); number_of_circuits = smartlist_len(circuits_for_buffer_stats); if (number_of_circuits > 0) { smartlist_sort(circuits_for_buffer_stats, buffer_stats_compare_entries_); i = 0; SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats, circ_buffer_stats_t *, stat) { int share = i++ * SHARES / number_of_circuits; processed_cells[share] += stat->processed_cells; queued_cells[share] += stat->mean_num_cells_in_queue; time_in_queue[share] += stat->mean_time_cells_in_queue; circs_in_share[share]++; } SMARTLIST_FOREACH_END(stat); } /* Write deciles to strings. */ processed_cells_strings = smartlist_new(); queued_cells_strings = smartlist_new(); time_in_queue_strings = smartlist_new(); for (i = 0; i < SHARES; i++) { smartlist_add_asprintf(processed_cells_strings, U64_FORMAT, !circs_in_share[i] ? 0 : U64_PRINTF_ARG(processed_cells[i] / circs_in_share[i])); } for (i = 0; i < SHARES; i++) { smartlist_add_asprintf(queued_cells_strings, "%.2f", circs_in_share[i] == 0 ? 0.0 : queued_cells[i] / (double) circs_in_share[i]); } for (i = 0; i < SHARES; i++) { smartlist_add_asprintf(time_in_queue_strings, "%.0f", circs_in_share[i] == 0 ? 0.0 : time_in_queue[i] / (double) circs_in_share[i]); } /* Join all observations in single strings. */ processed_cells_string = smartlist_join_strings(processed_cells_strings, ",", 0, NULL); queued_cells_string = smartlist_join_strings(queued_cells_strings, ",", 0, NULL); time_in_queue_string = smartlist_join_strings(time_in_queue_strings, ",", 0, NULL); SMARTLIST_FOREACH(processed_cells_strings, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(queued_cells_strings, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(time_in_queue_strings, char *, cp, tor_free(cp)); smartlist_free(processed_cells_strings); smartlist_free(queued_cells_strings); smartlist_free(time_in_queue_strings); /* Put everything together. */ format_iso_time(t, now); tor_asprintf(&result, "cell-stats-end %s (%d s)\n" "cell-processed-cells %s\n" "cell-queued-cells %s\n" "cell-time-in-queue %s\n" "cell-circuits-per-decile %d\n", t, (unsigned) (now - start_of_buffer_stats_interval), processed_cells_string, queued_cells_string, time_in_queue_string, (number_of_circuits + SHARES - 1) / SHARES); tor_free(processed_cells_string); tor_free(queued_cells_string); tor_free(time_in_queue_string); return result; #undef SHARES } /** If 24 hours have passed since the beginning of the current buffer * stats period, write buffer stats to $DATADIR/stats/buffer-stats * (possibly overwriting an existing file) and reset counters. Return * when we would next want to write buffer stats or 0 if we never want to * write. */ time_t rep_hist_buffer_stats_write(time_t now) { circuit_t *circ; char *statsdir = NULL, *filename = NULL, *str = NULL; if (!start_of_buffer_stats_interval) return 0; /* Not initialized. */ if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now) goto done; /* Not ready to write */ /* Add open circuits to the history. */ for (circ = circuit_get_global_list_(); circ; circ = circ->next) { rep_hist_buffer_stats_add_circ(circ, now); } /* Generate history string. */ str = rep_hist_format_buffer_stats(now); /* Reset both buffer history and counters of open circuits. */ rep_hist_reset_buffer_stats(now); /* Try to write to disk. */ statsdir = get_datadir_fname("stats"); if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { log_warn(LD_HIST, "Unable to create stats/ directory!"); goto done; } filename = get_datadir_fname2("stats", "buffer-stats"); if (write_str_to_file(filename, str, 0) < 0) log_warn(LD_HIST, "Unable to write buffer stats to disk!"); done: tor_free(str); tor_free(filename); tor_free(statsdir); return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL; } /*** Descriptor serving statistics ***/ /** Digestmap to track which descriptors were downloaded this stats * collection interval. It maps descriptor digest to pointers to 1, * effectively turning this into a list. */ static digestmap_t *served_descs = NULL; /** Number of how many descriptors were downloaded in total during this * interval. */ static unsigned long total_descriptor_downloads; /** Start time of served descs stats or 0 if we're not collecting those. */ static time_t start_of_served_descs_stats_interval; /** Initialize descriptor stats. */ void rep_hist_desc_stats_init(time_t now) { if (served_descs) { log_warn(LD_BUG, "Called rep_hist_desc_stats_init() when desc stats were " "already initialized. This is probably harmless."); return; // Already initialized } served_descs = digestmap_new(); total_descriptor_downloads = 0; start_of_served_descs_stats_interval = now; } /** Reset served descs stats to empty, starting a new interval now. */ static void rep_hist_reset_desc_stats(time_t now) { rep_hist_desc_stats_term(); rep_hist_desc_stats_init(now); } /** Stop collecting served descs stats, so that rep_hist_desc_stats_init() is * safe to be called again. */ void rep_hist_desc_stats_term(void) { digestmap_free(served_descs, NULL); served_descs = NULL; start_of_served_descs_stats_interval = 0; total_descriptor_downloads = 0; } /** Helper for rep_hist_desc_stats_write(). Return a newly allocated string * containing the served desc statistics until now, or NULL if we're not * collecting served desc stats. Caller must ensure that now is not before * start_of_served_descs_stats_interval. */ static char * rep_hist_format_desc_stats(time_t now) { char t[ISO_TIME_LEN+1]; char *result; digestmap_iter_t *iter; const char *key; void *val; unsigned size; int *vals, max = 0, q3 = 0, md = 0, q1 = 0, min = 0; int n = 0; if (!start_of_served_descs_stats_interval) return NULL; size = digestmap_size(served_descs); if (size > 0) { vals = tor_malloc(size * sizeof(int)); for (iter = digestmap_iter_init(served_descs); !digestmap_iter_done(iter); iter = digestmap_iter_next(served_descs, iter)) { uintptr_t count; digestmap_iter_get(iter, &key, &val); count = (uintptr_t)val; vals[n++] = (int)count; (void)key; } max = find_nth_int(vals, size, size-1); q3 = find_nth_int(vals, size, (3*size-1)/4); md = find_nth_int(vals, size, (size-1)/2); q1 = find_nth_int(vals, size, (size-1)/4); min = find_nth_int(vals, size, 0); tor_free(vals); } format_iso_time(t, now); tor_asprintf(&result, "served-descs-stats-end %s (%d s) total=%lu unique=%u " "max=%d q3=%d md=%d q1=%d min=%d\n", t, (unsigned) (now - start_of_served_descs_stats_interval), total_descriptor_downloads, size, max, q3, md, q1, min); return result; } /** If WRITE_STATS_INTERVAL seconds have passed since the beginning of * the current served desc stats interval, write the stats to * $DATADIR/stats/served-desc-stats (possibly appending to an existing file) * and reset the state for the next interval. Return when we would next want * to write served desc stats or 0 if we won't want to write. */ time_t rep_hist_desc_stats_write(time_t now) { char *statsdir = NULL, *filename = NULL, *str = NULL; if (!start_of_served_descs_stats_interval) return 0; /* We're not collecting stats. */ if (start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL > now) return start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL; str = rep_hist_format_desc_stats(now); tor_assert(str != NULL); statsdir = get_datadir_fname("stats"); if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { log_warn(LD_HIST, "Unable to create stats/ directory!"); goto done; } filename = get_datadir_fname2("stats", "served-desc-stats"); if (append_bytes_to_file(filename, str, strlen(str), 0) < 0) log_warn(LD_HIST, "Unable to write served descs statistics to disk!"); rep_hist_reset_desc_stats(now); done: tor_free(statsdir); tor_free(filename); tor_free(str); return start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL; } /* DOCDOC rep_hist_note_desc_served */ void rep_hist_note_desc_served(const char * desc) { void *val; uintptr_t count; if (!served_descs) return; // We're not collecting stats val = digestmap_get(served_descs, desc); count = (uintptr_t)val; if (count != INT_MAX) ++count; digestmap_set(served_descs, desc, (void*)count); total_descriptor_downloads++; } /*** Connection statistics ***/ /** Start of the current connection stats interval or 0 if we're not * collecting connection statistics. */ static time_t start_of_conn_stats_interval; /** Initialize connection stats. */ void rep_hist_conn_stats_init(time_t now) { start_of_conn_stats_interval = now; } /* Count connections that we read and wrote less than these many bytes * from/to as below threshold. */ #define BIDI_THRESHOLD 20480 /* Count connections that we read or wrote at least this factor as many * bytes from/to than we wrote or read to/from as mostly reading or * writing. */ #define BIDI_FACTOR 10 /* Interval length in seconds for considering read and written bytes for * connection stats. */ #define BIDI_INTERVAL 10 /** Start of next BIDI_INTERVAL second interval. */ static time_t bidi_next_interval = 0; /** Number of connections that we read and wrote less than BIDI_THRESHOLD * bytes from/to in BIDI_INTERVAL seconds. */ static uint32_t below_threshold = 0; /** Number of connections that we read at least BIDI_FACTOR times more * bytes from than we wrote to in BIDI_INTERVAL seconds. */ static uint32_t mostly_read = 0; /** Number of connections that we wrote at least BIDI_FACTOR times more * bytes to than we read from in BIDI_INTERVAL seconds. */ static uint32_t mostly_written = 0; /** Number of connections that we read and wrote at least BIDI_THRESHOLD * bytes from/to, but not BIDI_FACTOR times more in either direction in * BIDI_INTERVAL seconds. */ static uint32_t both_read_and_written = 0; /** Entry in a map from connection ID to the number of read and written * bytes on this connection in a BIDI_INTERVAL second interval. */ typedef struct bidi_map_entry_t { HT_ENTRY(bidi_map_entry_t) node; uint64_t conn_id; /**< Connection ID */ size_t read; /**< Number of read bytes */ size_t written; /**< Number of written bytes */ } bidi_map_entry_t; /** Map of OR connections together with the number of read and written * bytes in the current BIDI_INTERVAL second interval. */ static HT_HEAD(bidimap, bidi_map_entry_t) bidi_map = HT_INITIALIZER(); static int bidi_map_ent_eq(const bidi_map_entry_t *a, const bidi_map_entry_t *b) { return a->conn_id == b->conn_id; } /* DOCDOC bidi_map_ent_hash */ static unsigned bidi_map_ent_hash(const bidi_map_entry_t *entry) { return (unsigned) entry->conn_id; } HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash, bidi_map_ent_eq); HT_GENERATE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash, bidi_map_ent_eq, 0.6, malloc, realloc, free); /* DOCDOC bidi_map_free */ static void bidi_map_free(void) { bidi_map_entry_t **ptr, **next, *ent; for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) { ent = *ptr; next = HT_NEXT_RMV(bidimap, &bidi_map, ptr); tor_free(ent); } HT_CLEAR(bidimap, &bidi_map); } /** Reset counters for conn statistics. */ void rep_hist_reset_conn_stats(time_t now) { start_of_conn_stats_interval = now; below_threshold = 0; mostly_read = 0; mostly_written = 0; both_read_and_written = 0; bidi_map_free(); } /** Stop collecting connection stats in a way that we can re-start doing * so in rep_hist_conn_stats_init(). */ void rep_hist_conn_stats_term(void) { rep_hist_reset_conn_stats(0); } /** We read num_read bytes and wrote num_written from/to OR * connection conn_id in second when. If this is the first * observation in a new interval, sum up the last observations. Add bytes * for this connection. */ void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read, size_t num_written, time_t when) { if (!start_of_conn_stats_interval) return; /* Initialize */ if (bidi_next_interval == 0) bidi_next_interval = when + BIDI_INTERVAL; /* Sum up last period's statistics */ if (when >= bidi_next_interval) { bidi_map_entry_t **ptr, **next, *ent; for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) { ent = *ptr; if (ent->read + ent->written < BIDI_THRESHOLD) below_threshold++; else if (ent->read >= ent->written * BIDI_FACTOR) mostly_read++; else if (ent->written >= ent->read * BIDI_FACTOR) mostly_written++; else both_read_and_written++; next = HT_NEXT_RMV(bidimap, &bidi_map, ptr); tor_free(ent); } while (when >= bidi_next_interval) bidi_next_interval += BIDI_INTERVAL; log_info(LD_GENERAL, "%d below threshold, %d mostly read, " "%d mostly written, %d both read and written.", below_threshold, mostly_read, mostly_written, both_read_and_written); } /* Add this connection's bytes. */ if (num_read > 0 || num_written > 0) { bidi_map_entry_t *entry, lookup; lookup.conn_id = conn_id; entry = HT_FIND(bidimap, &bidi_map, &lookup); if (entry) { entry->written += num_written; entry->read += num_read; } else { entry = tor_malloc_zero(sizeof(bidi_map_entry_t)); entry->conn_id = conn_id; entry->written = num_written; entry->read = num_read; HT_INSERT(bidimap, &bidi_map, entry); } } } /** Return a newly allocated string containing the connection statistics * until now, or NULL if we're not collecting conn stats. Caller must * ensure start_of_conn_stats_interval is in the past. */ char * rep_hist_format_conn_stats(time_t now) { char *result, written[ISO_TIME_LEN+1]; if (!start_of_conn_stats_interval) return NULL; /* Not initialized. */ tor_assert(now >= start_of_conn_stats_interval); format_iso_time(written, now); tor_asprintf(&result, "conn-bi-direct %s (%d s) %d,%d,%d,%d\n", written, (unsigned) (now - start_of_conn_stats_interval), below_threshold, mostly_read, mostly_written, both_read_and_written); return result; } /** If 24 hours have passed since the beginning of the current conn stats * period, write conn stats to $DATADIR/stats/conn-stats (possibly * overwriting an existing file) and reset counters. Return when we would * next want to write conn stats or 0 if we never want to write. */ time_t rep_hist_conn_stats_write(time_t now) { char *statsdir = NULL, *filename = NULL, *str = NULL; if (!start_of_conn_stats_interval) return 0; /* Not initialized. */ if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now) goto done; /* Not ready to write */ /* Generate history string. */ str = rep_hist_format_conn_stats(now); /* Reset counters. */ rep_hist_reset_conn_stats(now); /* Try to write to disk. */ statsdir = get_datadir_fname("stats"); if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { log_warn(LD_HIST, "Unable to create stats/ directory!"); goto done; } filename = get_datadir_fname2("stats", "conn-stats"); if (write_str_to_file(filename, str, 0) < 0) log_warn(LD_HIST, "Unable to write conn stats to disk!"); done: tor_free(str); tor_free(filename); tor_free(statsdir); return start_of_conn_stats_interval + WRITE_STATS_INTERVAL; } /** Internal statistics to track how many requests of each type of * handshake we've received, and how many we've completed. Useful for * seeing trends in cpu load. * @{ */ static int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; static int onion_handshakes_completed[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; /**@}*/ /** A new onionskin (using the type handshake) has arrived. */ void rep_hist_note_circuit_handshake_requested(uint16_t type) { if (type <= MAX_ONION_HANDSHAKE_TYPE) onion_handshakes_requested[type]++; } /** We've sent an onionskin (using the type handshake) to a * cpuworker. */ void rep_hist_note_circuit_handshake_completed(uint16_t type) { if (type <= MAX_ONION_HANDSHAKE_TYPE) onion_handshakes_completed[type]++; } /** Log our onionskin statistics since the last time we were called. */ void rep_hist_log_circuit_handshake_stats(time_t now) { (void)now; /* XXX024 maybe quiet this log message before 0.2.4 goes stable for real */ log_notice(LD_HIST, "Circuit handshake stats since last time: " "%d/%d TAP, %d/%d NTor.", onion_handshakes_completed[ONION_HANDSHAKE_TYPE_TAP], onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP], onion_handshakes_completed[ONION_HANDSHAKE_TYPE_NTOR], onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR]); memset(onion_handshakes_completed, 0, sizeof(onion_handshakes_completed)); memset(onion_handshakes_requested, 0, sizeof(onion_handshakes_requested)); } /** Free all storage held by the OR/link history caches, by the * bandwidth history arrays, by the port history, or by statistics . */ void rep_hist_free_all(void) { digestmap_free(history_map, free_or_history); tor_free(read_array); tor_free(write_array); tor_free(dir_read_array); tor_free(dir_write_array); tor_free(last_stability_doc); tor_free(exit_bytes_read); tor_free(exit_bytes_written); tor_free(exit_streams); built_last_stability_doc_at = 0; predicted_ports_free(); bidi_map_free(); if (circuits_for_buffer_stats) { SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *, s, tor_free(s)); smartlist_free(circuits_for_buffer_stats); circuits_for_buffer_stats = NULL; } rep_hist_desc_stats_term(); total_descriptor_downloads = 0; } tor-0.2.4.20/src/or/routerparse.h0000644000175000017500000001127012255512001013407 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file routerparse.h * \brief Header file for routerparse.c. **/ #ifndef TOR_ROUTERPARSE_H #define TOR_ROUTERPARSE_H int router_get_router_hash(const char *s, size_t s_len, char *digest); int router_get_dir_hash(const char *s, char *digest); int router_get_runningrouters_hash(const char *s, char *digest); int router_get_networkstatus_v2_hash(const char *s, char *digest); int router_get_networkstatus_v3_hashes(const char *s, digests_t *digests); int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest); #define DIROBJ_MAX_SIG_LEN 256 char *router_get_dirobj_signature(const char *digest, size_t digest_len, crypto_pk_t *private_key); int router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, size_t digest_len, crypto_pk_t *private_key); int router_parse_list_from_string(const char **s, const char *eos, smartlist_t *dest, saved_location_t saved_location, int is_extrainfo, int allow_annotations, const char *prepend_annotations); routerinfo_t *router_parse_entry_from_string(const char *s, const char *end, int cache_copy, int allow_annotations, const char *prepend_annotations); extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end, int cache_copy, struct digest_ri_map_t *routermap); addr_policy_t *router_parse_addr_policy_item_from_string(const char *s, int assume_action); version_status_t tor_version_is_obsolete(const char *myversion, const char *versionlist); int tor_version_supports_microdescriptors(const char *platform); int tor_version_as_new_as(const char *platform, const char *cutoff); int tor_version_parse(const char *s, tor_version_t *out); int tor_version_compare(tor_version_t *a, tor_version_t *b); int tor_version_same_series(tor_version_t *a, tor_version_t *b); void sort_version_list(smartlist_t *lst, int remove_duplicates); void assert_addr_policy_ok(smartlist_t *t); void dump_distinct_digest_count(int severity); int compare_routerstatus_entries(const void **_a, const void **_b); int compare_vote_routerstatus_entries(const void **_a, const void **_b); networkstatus_v2_t *networkstatus_v2_parse_from_string(const char *s); int networkstatus_verify_bw_weights(networkstatus_t *ns, int); networkstatus_t *networkstatus_parse_vote_from_string(const char *s, const char **eos_out, networkstatus_type_t ns_type); ns_detached_signatures_t *networkstatus_parse_detached_signatures( const char *s, const char *eos); smartlist_t *microdescs_parse_from_string(const char *s, const char *eos, int allow_annotations, saved_location_t where); authority_cert_t *authority_cert_parse_from_string(const char *s, const char **end_of_string); int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, char *desc_id_out, char **intro_points_encrypted_out, size_t *intro_points_encrypted_size_out, size_t *encoded_size_out, const char **next_out, const char *desc); int rend_decrypt_introduction_points(char **ipos_decrypted, size_t *ipos_decrypted_size, const char *descriptor_cookie, const char *ipos_encrypted, size_t ipos_encrypted_size); int rend_parse_introduction_points(rend_service_descriptor_t *parsed, const char *intro_points_encoded, size_t intro_points_encoded_size); int rend_parse_client_keys(strmap_t *parsed_clients, const char *str); #endif tor-0.2.4.20/src/or/statefile.c0000644000175000017500000004535312255745673013047 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "or.h" #include "circuitstats.h" #include "config.h" #include "confparse.h" #include "entrynodes.h" #include "hibernate.h" #include "rephist.h" #include "router.h" #include "statefile.h" /** A list of state-file "abbreviations," for compatibility. */ static config_abbrev_t state_abbrevs_[] = { { "AccountingBytesReadInterval", "AccountingBytesReadInInterval", 0, 0 }, { "HelperNode", "EntryGuard", 0, 0 }, { "HelperNodeDownSince", "EntryGuardDownSince", 0, 0 }, { "HelperNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 }, { "EntryNode", "EntryGuard", 0, 0 }, { "EntryNodeDownSince", "EntryGuardDownSince", 0, 0 }, { "EntryNodeUnlistedSince", "EntryGuardUnlistedSince", 0, 0 }, { NULL, NULL, 0, 0}, }; /*XXXX these next two are duplicates or near-duplicates from config.c */ #define VAR(name,conftype,member,initvalue) \ { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_state_t, member), \ initvalue } /** As VAR, but the option name and member name are the same. */ #define V(member,conftype,initvalue) \ VAR(#member, conftype, member, initvalue) /** Array of "state" variables saved to the ~/.tor/state file. */ static config_var_t state_vars_[] = { /* Remember to document these in state-contents.txt ! */ V(AccountingBytesReadInInterval, MEMUNIT, NULL), V(AccountingBytesWrittenInInterval, MEMUNIT, NULL), V(AccountingExpectedUsage, MEMUNIT, NULL), V(AccountingIntervalStart, ISOTIME, NULL), V(AccountingSecondsActive, INTERVAL, NULL), V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL), V(AccountingSoftLimitHitAt, ISOTIME, NULL), V(AccountingBytesAtSoftLimit, MEMUNIT, NULL), VAR("EntryGuard", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardUnlistedSince", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardPathBias", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardPathUseBias", LINELIST_S, EntryGuards, NULL), V(EntryGuards, LINELIST_V, NULL), VAR("TransportProxy", LINELIST_S, TransportProxies, NULL), V(TransportProxies, LINELIST_V, NULL), V(BWHistoryReadEnds, ISOTIME, NULL), V(BWHistoryReadInterval, UINT, "900"), V(BWHistoryReadValues, CSV, ""), V(BWHistoryReadMaxima, CSV, ""), V(BWHistoryWriteEnds, ISOTIME, NULL), V(BWHistoryWriteInterval, UINT, "900"), V(BWHistoryWriteValues, CSV, ""), V(BWHistoryWriteMaxima, CSV, ""), V(BWHistoryDirReadEnds, ISOTIME, NULL), V(BWHistoryDirReadInterval, UINT, "900"), V(BWHistoryDirReadValues, CSV, ""), V(BWHistoryDirReadMaxima, CSV, ""), V(BWHistoryDirWriteEnds, ISOTIME, NULL), V(BWHistoryDirWriteInterval, UINT, "900"), V(BWHistoryDirWriteValues, CSV, ""), V(BWHistoryDirWriteMaxima, CSV, ""), V(TorVersion, STRING, NULL), V(LastRotatedOnionKey, ISOTIME, NULL), V(LastWritten, ISOTIME, NULL), V(TotalBuildTimes, UINT, NULL), V(CircuitBuildAbandonedCount, UINT, "0"), VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL), VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL), { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } }; #undef VAR #undef V static int or_state_validate(or_state_t *old_options, or_state_t *options, int from_setconf, char **msg); /** Magic value for or_state_t. */ #define OR_STATE_MAGIC 0x57A73f57 /** "Extra" variable in the state that receives lines we can't parse. This * lets us preserve options from versions of Tor newer than us. */ static config_var_t state_extra_var = { "__extra", CONFIG_TYPE_LINELIST, STRUCT_OFFSET(or_state_t, ExtraLines), NULL }; /** Configuration format for or_state_t. */ static const config_format_t state_format = { sizeof(or_state_t), OR_STATE_MAGIC, STRUCT_OFFSET(or_state_t, magic_), state_abbrevs_, state_vars_, (validate_fn_t)or_state_validate, &state_extra_var, }; /** Persistent serialized state. */ static or_state_t *global_state = NULL; /** Return the persistent state struct for this Tor. */ or_state_t * get_or_state(void) { tor_assert(global_state); return global_state; } /** Return true iff we have loaded the global state for this Tor */ int or_state_loaded(void) { return global_state != NULL; } /** Return true if line is a valid state TransportProxy line. * Return false otherwise. */ static int state_transport_line_is_valid(const char *line) { smartlist_t *items = NULL; char *addrport=NULL; tor_addr_t addr; uint16_t port = 0; int r; items = smartlist_new(); smartlist_split_string(items, line, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); if (smartlist_len(items) != 2) { log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line."); goto err; } addrport = smartlist_get(items, 1); if (tor_addr_port_lookup(addrport, &addr, &port) < 0) { log_warn(LD_CONFIG, "state: Could not parse addrport."); goto err; } if (!port) { log_warn(LD_CONFIG, "state: Transport line did not contain port."); goto err; } r = 1; goto done; err: r = 0; done: SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); return r; } /** Return 0 if all TransportProxy lines in state are well * formed. Otherwise, return -1. */ static int validate_transports_in_state(or_state_t *state) { int broken = 0; config_line_t *line; for (line = state->TransportProxies ; line ; line = line->next) { tor_assert(!strcmp(line->key, "TransportProxy")); if (!state_transport_line_is_valid(line->value)) broken = 1; } if (broken) log_warn(LD_CONFIG, "state: State file seems to be broken."); return 0; } /** Return 0 if every setting in state is reasonable, and a * permissible transition from old_state. Else warn and return -1. * Should have no side effects, except for normalizing the contents of * state. */ /* XXX from_setconf is here because of bug 238 */ static int or_state_validate(or_state_t *old_state, or_state_t *state, int from_setconf, char **msg) { /* We don't use these; only options do. Still, we need to match that * signature. */ (void) from_setconf; (void) old_state; if (entry_guards_parse_state(state, 0, msg)<0) return -1; if (validate_transports_in_state(state)<0) return -1; return 0; } /** Replace the current persistent state with new_state */ static int or_state_set(or_state_t *new_state) { char *err = NULL; int ret = 0; tor_assert(new_state); config_free(&state_format, global_state); global_state = new_state; if (entry_guards_parse_state(global_state, 1, &err)<0) { log_warn(LD_GENERAL,"%s",err); tor_free(err); ret = -1; } if (rep_hist_load_state(global_state, &err)<0) { log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err); tor_free(err); ret = -1; } if (circuit_build_times_parse_state(&circ_times, global_state) < 0) { ret = -1; } return ret; } /** * Save a broken state file to a backup location. */ static void or_state_save_broken(char *fname) { int i; file_status_t status; char *fname2 = NULL; for (i = 0; i < 100; ++i) { tor_asprintf(&fname2, "%s.%d", fname, i); status = file_status(fname2); if (status == FN_NOENT) break; tor_free(fname2); } if (i == 100) { log_warn(LD_BUG, "Unable to parse state in \"%s\"; too many saved bad " "state files to move aside. Discarding the old state file.", fname); unlink(fname); } else { log_warn(LD_BUG, "Unable to parse state in \"%s\". Moving it aside " "to \"%s\". This could be a bug in Tor; please tell " "the developers.", fname, fname2); if (rename(fname, fname2) < 0) { log_warn(LD_BUG, "Weirdly, I couldn't even move the state aside. The " "OS gave an error of %s", strerror(errno)); } } tor_free(fname2); } /** Reload the persistent state from disk, generating a new state as needed. * Return 0 on success, less than 0 on failure. */ int or_state_load(void) { or_state_t *new_state = NULL; char *contents = NULL, *fname; char *errmsg = NULL; int r = -1, badstate = 0; fname = get_datadir_fname("state"); switch (file_status(fname)) { case FN_FILE: if (!(contents = read_file_to_str(fname, 0, NULL))) { log_warn(LD_FS, "Unable to read state file \"%s\"", fname); goto done; } break; case FN_NOENT: break; case FN_ERROR: case FN_DIR: default: log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname); goto done; } new_state = tor_malloc_zero(sizeof(or_state_t)); new_state->magic_ = OR_STATE_MAGIC; config_init(&state_format, new_state); if (contents) { config_line_t *lines=NULL; int assign_retval; if (config_get_lines(contents, &lines, 0)<0) goto done; assign_retval = config_assign(&state_format, new_state, lines, 0, 0, &errmsg); config_free_lines(lines); if (assign_retval<0) badstate = 1; if (errmsg) { log_warn(LD_GENERAL, "%s", errmsg); tor_free(errmsg); } } if (!badstate && or_state_validate(NULL, new_state, 1, &errmsg) < 0) badstate = 1; if (errmsg) { log_warn(LD_GENERAL, "%s", errmsg); tor_free(errmsg); } if (badstate && !contents) { log_warn(LD_BUG, "Uh oh. We couldn't even validate our own default state." " This is a bug in Tor."); goto done; } else if (badstate && contents) { or_state_save_broken(fname); tor_free(contents); config_free(&state_format, new_state); new_state = tor_malloc_zero(sizeof(or_state_t)); new_state->magic_ = OR_STATE_MAGIC; config_init(&state_format, new_state); } else if (contents) { log_info(LD_GENERAL, "Loaded state from \"%s\"", fname); } else { log_info(LD_GENERAL, "Initialized state"); } if (or_state_set(new_state) == -1) { or_state_save_broken(fname); } new_state = NULL; if (!contents) { global_state->next_write = 0; or_state_save(time(NULL)); } r = 0; done: tor_free(fname); tor_free(contents); if (new_state) config_free(&state_format, new_state); return r; } /** Did the last time we tried to write the state file fail? If so, we * should consider disabling such features as preemptive circuit generation * to compute circuit-build-time. */ static int last_state_file_write_failed = 0; /** Return whether the state file failed to write last time we tried. */ int did_last_state_file_write_fail(void) { return last_state_file_write_failed; } /** If writing the state to disk fails, try again after this many seconds. */ #define STATE_WRITE_RETRY_INTERVAL 3600 /** If we're a relay, how often should we checkpoint our state file even * if nothing else dirties it? This will checkpoint ongoing stats like * bandwidth used, per-country user stats, etc. */ #define STATE_RELAY_CHECKPOINT_INTERVAL (12*60*60) /** Write the persistent state to disk. Return 0 for success, <0 on failure. */ int or_state_save(time_t now) { char *state, *contents; char tbuf[ISO_TIME_LEN+1]; char *fname; tor_assert(global_state); if (global_state->next_write > now) return 0; /* Call everything else that might dirty the state even more, in order * to avoid redundant writes. */ entry_guards_update_state(global_state); rep_hist_update_state(global_state); circuit_build_times_update_state(&circ_times, global_state); if (accounting_is_enabled(get_options())) accounting_run_housekeeping(now); global_state->LastWritten = now; tor_free(global_state->TorVersion); tor_asprintf(&global_state->TorVersion, "Tor %s", get_version()); state = config_dump(&state_format, NULL, global_state, 1, 0); format_local_iso_time(tbuf, now); tor_asprintf(&contents, "# Tor state file last generated on %s local time\n" "# Other times below are in UTC\n" "# You *do not* need to edit this file.\n\n%s", tbuf, state); tor_free(state); fname = get_datadir_fname("state"); if (write_str_to_file(fname, contents, 0)<0) { log_warn(LD_FS, "Unable to write state to file \"%s\"; " "will try again later", fname); last_state_file_write_failed = 1; tor_free(fname); tor_free(contents); /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state * changes sooner). */ global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL; return -1; } last_state_file_write_failed = 0; log_info(LD_GENERAL, "Saved state to \"%s\"", fname); tor_free(fname); tor_free(contents); if (server_mode(get_options())) global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL; else global_state->next_write = TIME_MAX; return 0; } /** Return the config line for transport transport in the current state. * Return NULL if there is no config line for transport. */ static config_line_t * get_transport_in_state_by_name(const char *transport) { or_state_t *or_state = get_or_state(); config_line_t *line; config_line_t *ret = NULL; smartlist_t *items = NULL; for (line = or_state->TransportProxies ; line ; line = line->next) { tor_assert(!strcmp(line->key, "TransportProxy")); items = smartlist_new(); smartlist_split_string(items, line->value, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); if (smartlist_len(items) != 2) /* broken state */ goto done; if (!strcmp(smartlist_get(items, 0), transport)) { ret = line; goto done; } SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); items = NULL; } done: if (items) { SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); } return ret; } /** Return string containing the address:port part of the * TransportProxy line for transport transport. * If the line is corrupted, return NULL. */ static const char * get_transport_bindaddr(const char *line, const char *transport) { char *line_tmp = NULL; if (strlen(line) < strlen(transport) + 2) { goto broken_state; } else { /* line should start with the name of the transport and a space. (for example, "obfs2 127.0.0.1:47245") */ tor_asprintf(&line_tmp, "%s ", transport); if (strcmpstart(line, line_tmp)) goto broken_state; tor_free(line_tmp); return (line+strlen(transport)+1); } broken_state: tor_free(line_tmp); return NULL; } /** Return a string containing the address:port that a proxy transport * should bind on. The string is stored on the heap and must be freed * by the caller of this function. */ char * get_stored_bindaddr_for_server_transport(const char *transport) { char *default_addrport = NULL; const char *stored_bindaddr = NULL; config_line_t *line = NULL; { /* See if the user explicitly asked for a specific listening address for this transport. */ char *conf_bindaddr = get_transport_bindaddr_from_config(transport); if (conf_bindaddr) return conf_bindaddr; } line = get_transport_in_state_by_name(transport); if (!line) /* Found no references in state for this transport. */ goto no_bindaddr_found; stored_bindaddr = get_transport_bindaddr(line->value, transport); if (stored_bindaddr) /* found stored bindaddr in state file. */ return tor_strdup(stored_bindaddr); no_bindaddr_found: /** If we didn't find references for this pluggable transport in the state file, we should instruct the pluggable transport proxy to listen on INADDR_ANY on a random ephemeral port. */ tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0"); return default_addrport; } /** Save transport listening on addr:port to state */ void save_transport_to_state(const char *transport, const tor_addr_t *addr, uint16_t port) { or_state_t *state = get_or_state(); char *transport_addrport=NULL; /** find where to write on the state */ config_line_t **next, *line; /* see if this transport is already stored in state */ config_line_t *transport_line = get_transport_in_state_by_name(transport); if (transport_line) { /* if transport already exists in state... */ const char *prev_bindaddr = /* get its addrport... */ get_transport_bindaddr(transport_line->value, transport); transport_addrport = tor_strdup(fmt_addrport(addr, port)); /* if transport in state has the same address as this one, life is good */ if (!strcmp(prev_bindaddr, transport_addrport)) { log_info(LD_CONFIG, "Transport seems to have spawned on its usual " "address:port."); goto done; } else { /* if addrport in state is different than the one we got */ log_info(LD_CONFIG, "Transport seems to have spawned on different " "address:port. Let's update the state file with the new " "address:port"); tor_free(transport_line->value); /* free the old line */ /* replace old addrport line with new line */ tor_asprintf(&transport_line->value, "%s %s", transport, fmt_addrport(addr, port)); } } else { /* never seen this one before; save it in state for next time */ log_info(LD_CONFIG, "It's the first time we see this transport. " "Let's save its address:port"); next = &state->TransportProxies; /* find the last TransportProxy line in the state and point 'next' right after it */ line = state->TransportProxies; while (line) { next = &(line->next); line = line->next; } /* allocate space for the new line and fill it in */ *next = line = tor_malloc_zero(sizeof(config_line_t)); line->key = tor_strdup("TransportProxy"); tor_asprintf(&line->value, "%s %s", transport, fmt_addrport(addr, port)); next = &(line->next); } if (!get_options()->AvoidDiskWrites) or_state_mark_dirty(state, 0); done: tor_free(transport_addrport); } void or_state_free_all(void) { config_free(&state_format, global_state); global_state = NULL; } tor-0.2.4.20/src/or/addressmap.h0000644000175000017500000000522012255745673013204 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ADDRESSMAP_H #define TOR_ADDRESSMAP_H void addressmap_init(void); void addressmap_clear_excluded_trackexithosts(const or_options_t *options); void addressmap_clear_invalid_automaps(const or_options_t *options); void addressmap_clean(time_t now); void addressmap_clear_configured(void); void addressmap_clear_transient(void); void addressmap_free_all(void); #define AMR_FLAG_USE_IPV4_DNS (1u<<0) #define AMR_FLAG_USE_IPV6_DNS (1u<<1) int addressmap_rewrite(char *address, size_t maxlen, unsigned flags, time_t *expires_out, addressmap_entry_source_t *exit_source_out); int addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags, time_t *expires_out); int addressmap_have_mapping(const char *address, int update_timeout); void addressmap_register(const char *address, char *new_address, time_t expires, addressmap_entry_source_t source, const int address_wildcard, const int new_address_wildcard); int parse_virtual_addr_network(const char *val, sa_family_t family, int validate_only, char **msg); int client_dns_incr_failures(const char *address); void client_dns_clear_failures(const char *address); void client_dns_set_addressmap(entry_connection_t *for_conn, const char *address, const tor_addr_t *val, const char *exitname, int ttl); const char *addressmap_register_virtual_address(int type, char *new_address); void addressmap_get_mappings(smartlist_t *sl, time_t min_expires, time_t max_expires, int want_expiry); int address_is_in_virtual_range(const char *addr); void clear_trackexithost_mappings(const char *exitname); void client_dns_set_reverse_addressmap(entry_connection_t *for_conn, const char *address, const char *v, const char *exitname, int ttl); int addressmap_address_should_automap(const char *address, const or_options_t *options); #ifdef ADDRESSMAP_PRIVATE typedef struct virtual_addr_conf_t { tor_addr_t addr; maskbits_t bits; } virtual_addr_conf_t; void get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out); #endif #endif tor-0.2.4.20/src/or/include.am0000644000175000017500000001234012255745673012653 00000000000000bin_PROGRAMS+= src/or/tor noinst_LIBRARIES+= src/or/libtor.a if BUILD_NT_SERVICES tor_platform_source=src/or/ntmain.c else tor_platform_source= endif EXTRA_DIST+= src/or/ntmain.c src/or/or_sha1.i src/or/Makefile.nmake if USE_EXTERNAL_EVDNS evdns_source= else evdns_source=src/ext/eventdns.c endif if CURVE25519_ENABLED onion_ntor_source=src/or/onion_ntor.c else onion_ntor_source= endif src_or_libtor_a_SOURCES = \ src/or/addressmap.c \ src/or/buffers.c \ src/or/channel.c \ src/or/channeltls.c \ src/or/circuitbuild.c \ src/or/circuitlist.c \ src/or/circuitmux.c \ src/or/circuitmux_ewma.c \ src/or/circuitstats.c \ src/or/circuituse.c \ src/or/command.c \ src/or/config.c \ src/or/confparse.c \ src/or/connection.c \ src/or/connection_edge.c \ src/or/connection_or.c \ src/or/control.c \ src/or/cpuworker.c \ src/or/directory.c \ src/or/dirserv.c \ src/or/dirvote.c \ src/or/dns.c \ src/or/dnsserv.c \ src/or/fp_pair.c \ src/or/geoip.c \ src/or/entrynodes.c \ src/or/hibernate.c \ src/or/main.c \ src/or/microdesc.c \ src/or/networkstatus.c \ src/or/nodelist.c \ src/or/onion.c \ src/or/onion_fast.c \ src/or/onion_tap.c \ src/or/transports.c \ src/or/policies.c \ src/or/reasons.c \ src/or/relay.c \ src/or/rendclient.c \ src/or/rendcommon.c \ src/or/rendmid.c \ src/or/rendservice.c \ src/or/rephist.c \ src/or/replaycache.c \ src/or/router.c \ src/or/routerlist.c \ src/or/routerparse.c \ src/or/routerset.c \ src/or/statefile.c \ src/or/status.c \ $(evdns_source) \ $(tor_platform_source) \ $(onion_ntor_source) \ src/or/config_codedigest.c #libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \ # ../common/libor-event.a src_or_tor_SOURCES = src/or/tor_main.c AM_CPPFLAGS += -I$(srcdir)/src/or -Isrc/or src/or/tor_main.o: micro-revision.i AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on windows, but I assure you that it # matters a lot there, and is quite hard to debug if you forget to do it. src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \ src/common/libor-crypto.a $(LIBDONNA) \ src/common/libor-event.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ ORHEADERS = \ src/or/addressmap.h \ src/or/buffers.h \ src/or/channel.h \ src/or/channeltls.h \ src/or/circuitbuild.h \ src/or/circuitlist.h \ src/or/circuitmux.h \ src/or/circuitmux_ewma.h \ src/or/circuitstats.h \ src/or/circuituse.h \ src/or/command.h \ src/or/config.h \ src/or/confparse.h \ src/or/connection.h \ src/or/connection_edge.h \ src/or/connection_or.h \ src/or/control.h \ src/or/cpuworker.h \ src/or/directory.h \ src/or/dirserv.h \ src/or/dirvote.h \ src/or/dns.h \ src/or/dnsserv.h \ src/or/eventdns_tor.h \ src/or/fp_pair.h \ src/or/geoip.h \ src/or/entrynodes.h \ src/or/hibernate.h \ src/or/main.h \ src/or/microdesc.h \ src/or/networkstatus.h \ src/or/nodelist.h \ src/or/ntmain.h \ src/or/onion.h \ src/or/onion_fast.h \ src/or/onion_ntor.h \ src/or/onion_tap.h \ src/or/or.h \ src/or/transports.h \ src/or/policies.h \ src/or/reasons.h \ src/or/relay.h \ src/or/rendclient.h \ src/or/rendcommon.h \ src/or/rendmid.h \ src/or/rendservice.h \ src/or/rephist.h \ src/or/replaycache.h \ src/or/router.h \ src/or/routerlist.h \ src/or/routerset.h \ src/or/routerparse.h \ src/or/statefile.h \ src/or/status.h noinst_HEADERS+= $(ORHEADERS) micro-revision.i src/or/config_codedigest.o: src/or/or_sha1.i micro-revision.i: FORCE @rm -f micro-revision.tmp; \ if test -d "$(top_srcdir)/.git" && \ test -x "`which git 2>&1;true`"; then \ HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \ echo \"$$HASH\" > micro-revision.tmp; \ fi; \ if test ! -f micro-revision.tmp ; then \ if test ! -f micro-revision.i ; then \ echo '""' > micro-revision.i; \ fi; \ elif test ! -f micro-revision.i || \ test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \ mv micro-revision.tmp micro-revision.i; \ fi; true src/or/or_sha1.i: $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS) $(AM_V_GEN)if test "@SHA1SUM@" != none; then \ (cd "$(srcdir)" && "@SHA1SUM@" $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS) ) | \ "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > src/or/or_sha1.i; \ elif test "@OPENSSL@" != none; then \ (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS)) | \ "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > src/or/or_sha1.i; \ else \ rm src/or/or_sha1.i; \ touch src/or/or_sha1.i; \ fi CLEANFILES+= micro-revision.i src/or/micro-revision.i FORCE: tor-0.2.4.20/src/or/geoip.c0000644000175000017500000014426312255745673012172 00000000000000/* Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file geoip.c * \brief Functions related to maintaining an IP-to-country database; * to summarizing client connections by country to entry guards, bridges, * and directory servers; and for statistics on answering network status * requests. */ #define GEOIP_PRIVATE #include "or.h" #include "ht.h" #include "config.h" #include "control.h" #include "dnsserv.h" #include "geoip.h" #include "routerlist.h" static void clear_geoip_db(void); static void init_geoip_countries(void); /** An entry from the GeoIP IPv4 file: maps an IPv4 range to a country. */ typedef struct geoip_ipv4_entry_t { uint32_t ip_low; /**< The lowest IP in the range, in host order */ uint32_t ip_high; /**< The highest IP in the range, in host order */ intptr_t country; /**< An index into geoip_countries */ } geoip_ipv4_entry_t; /** An entry from the GeoIP IPv6 file: maps an IPv6 range to a country. */ typedef struct geoip_ipv6_entry_t { struct in6_addr ip_low; /**< The lowest IP in the range, in host order */ struct in6_addr ip_high; /**< The highest IP in the range, in host order */ intptr_t country; /**< An index into geoip_countries */ } geoip_ipv6_entry_t; /** A per-country record for GeoIP request history. */ typedef struct geoip_country_t { char countrycode[3]; uint32_t n_v3_ns_requests; } geoip_country_t; /** A list of geoip_country_t */ static smartlist_t *geoip_countries = NULL; /** A map from lowercased country codes to their position in geoip_countries. * The index is encoded in the pointer, and 1 is added so that NULL can mean * not found. */ static strmap_t *country_idxplus1_by_lc_code = NULL; /** Lists of all known geoip_ipv4_entry_t and geoip_ipv6_entry_t, sorted * by their respective ip_low. */ static smartlist_t *geoip_ipv4_entries = NULL, *geoip_ipv6_entries = NULL; /** SHA1 digest of the GeoIP files to include in extra-info descriptors. */ static char geoip_digest[DIGEST_LEN]; static char geoip6_digest[DIGEST_LEN]; /** Return the index of the country's entry in the GeoIP * country list if it is a valid 2-letter country code, otherwise * return -1. */ country_t geoip_get_country(const char *country) { void *idxplus1_; intptr_t idx; idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country); if (!idxplus1_) return -1; idx = ((uintptr_t)idxplus1_)-1; return (country_t)idx; } /** Add an entry to a GeoIP table, mapping all IP addresses between low * and high, inclusive, to the 2-letter country code country. */ static void geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high, const char *country) { intptr_t idx; void *idxplus1_; if (tor_addr_family(low) != tor_addr_family(high)) return; if (tor_addr_compare(high, low, CMP_EXACT) < 0) return; idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country); if (!idxplus1_) { geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t)); strlcpy(c->countrycode, country, sizeof(c->countrycode)); tor_strlower(c->countrycode); smartlist_add(geoip_countries, c); idx = smartlist_len(geoip_countries) - 1; strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1)); } else { idx = ((uintptr_t)idxplus1_)-1; } { geoip_country_t *c = smartlist_get(geoip_countries, idx); tor_assert(!strcasecmp(c->countrycode, country)); } if (tor_addr_family(low) == AF_INET) { geoip_ipv4_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv4_entry_t)); ent->ip_low = tor_addr_to_ipv4h(low); ent->ip_high = tor_addr_to_ipv4h(high); ent->country = idx; smartlist_add(geoip_ipv4_entries, ent); } else if (tor_addr_family(low) == AF_INET6) { geoip_ipv6_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv6_entry_t)); ent->ip_low = *tor_addr_to_in6(low); ent->ip_high = *tor_addr_to_in6(high); ent->country = idx; smartlist_add(geoip_ipv6_entries, ent); } } /** Add an entry to the GeoIP table indicated by family, * parsing it from line. The format is as for geoip_load_file(). */ /*private*/ int geoip_parse_entry(const char *line, sa_family_t family) { tor_addr_t low_addr, high_addr; char c[3]; char *country = NULL; if (!geoip_countries) init_geoip_countries(); if (family == AF_INET) { if (!geoip_ipv4_entries) geoip_ipv4_entries = smartlist_new(); } else if (family == AF_INET6) { if (!geoip_ipv6_entries) geoip_ipv6_entries = smartlist_new(); } else { log_warn(LD_GENERAL, "Unsupported family: %d", family); return -1; } while (TOR_ISSPACE(*line)) ++line; if (*line == '#') return 0; if (family == AF_INET) { unsigned int low, high; if (tor_sscanf(line,"%u,%u,%2s", &low, &high, c) == 3 || tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, c) == 3) { tor_addr_from_ipv4h(&low_addr, low); tor_addr_from_ipv4h(&high_addr, high); } else goto fail; country = c; } else { /* AF_INET6 */ char buf[512]; char *low_str, *high_str; struct in6_addr low, high; char *strtok_state; strlcpy(buf, line, sizeof(buf)); low_str = tor_strtok_r(buf, ",", &strtok_state); if (!low_str) goto fail; high_str = tor_strtok_r(NULL, ",", &strtok_state); if (!high_str) goto fail; country = tor_strtok_r(NULL, "\n", &strtok_state); if (!country) goto fail; if (strlen(country) != 2) goto fail; if (tor_inet_pton(AF_INET6, low_str, &low) <= 0) goto fail; tor_addr_from_in6(&low_addr, &low); if (tor_inet_pton(AF_INET6, high_str, &high) <= 0) goto fail; tor_addr_from_in6(&high_addr, &high); } geoip_add_entry(&low_addr, &high_addr, country); return 0; fail: log_warn(LD_GENERAL, "Unable to parse line from GEOIP %s file: %s", family == AF_INET ? "IPv4" : "IPv6", escaped(line)); return -1; } /** Sorting helper: return -1, 1, or 0 based on comparison of two * geoip_ipv4_entry_t */ static int geoip_ipv4_compare_entries_(const void **_a, const void **_b) { const geoip_ipv4_entry_t *a = *_a, *b = *_b; if (a->ip_low < b->ip_low) return -1; else if (a->ip_low > b->ip_low) return 1; else return 0; } /** bsearch helper: return -1, 1, or 0 based on comparison of an IP (a pointer * to a uint32_t in host order) to a geoip_ipv4_entry_t */ static int geoip_ipv4_compare_key_to_entry_(const void *_key, const void **_member) { /* No alignment issue here, since _key really is a pointer to uint32_t */ const uint32_t addr = *(uint32_t *)_key; const geoip_ipv4_entry_t *entry = *_member; if (addr < entry->ip_low) return -1; else if (addr > entry->ip_high) return 1; else return 0; } /** Sorting helper: return -1, 1, or 0 based on comparison of two * geoip_ipv6_entry_t */ static int geoip_ipv6_compare_entries_(const void **_a, const void **_b) { const geoip_ipv6_entry_t *a = *_a, *b = *_b; return fast_memcmp(a->ip_low.s6_addr, b->ip_low.s6_addr, sizeof(struct in6_addr)); } /** bsearch helper: return -1, 1, or 0 based on comparison of an IPv6 * (a pointer to a in6_addr) to a geoip_ipv6_entry_t */ static int geoip_ipv6_compare_key_to_entry_(const void *_key, const void **_member) { const struct in6_addr *addr = (struct in6_addr *)_key; const geoip_ipv6_entry_t *entry = *_member; if (fast_memcmp(addr->s6_addr, entry->ip_low.s6_addr, sizeof(struct in6_addr)) < 0) return -1; else if (fast_memcmp(addr->s6_addr, entry->ip_high.s6_addr, sizeof(struct in6_addr)) > 0) return 1; else return 0; } /** Return 1 if we should collect geoip stats on bridge users, and * include them in our extrainfo descriptor. Else return 0. */ int should_record_bridge_info(const or_options_t *options) { return options->BridgeRelay && options->BridgeRecordUsageByCountry; } /** Set up a new list of geoip countries with no countries (yet) set in it, * except for the unknown country. */ static void init_geoip_countries(void) { geoip_country_t *geoip_unresolved; geoip_countries = smartlist_new(); /* Add a geoip_country_t for requests that could not be resolved to a * country as first element (index 0) to geoip_countries. */ geoip_unresolved = tor_malloc_zero(sizeof(geoip_country_t)); strlcpy(geoip_unresolved->countrycode, "??", sizeof(geoip_unresolved->countrycode)); smartlist_add(geoip_countries, geoip_unresolved); country_idxplus1_by_lc_code = strmap_new(); strmap_set_lc(country_idxplus1_by_lc_code, "??", (void*)(1)); } /** Clear appropriate GeoIP database, based on family, and * reload it from the file filename. Return 0 on success, -1 on * failure. * * Recognized line formats for IPv4 are: * INTIPLOW,INTIPHIGH,CC * and * "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME" * where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as 4-byte unsigned * integers, and CC is a country code. * * Recognized line format for IPv6 is: * IPV6LOW,IPV6HIGH,CC * where IPV6LOW and IPV6HIGH are IPv6 addresses and CC is a country code. * * It also recognizes, and skips over, blank lines and lines that start * with '#' (comments). */ int geoip_load_file(sa_family_t family, const char *filename) { FILE *f; const char *msg = ""; const or_options_t *options = get_options(); int severity = options_need_geoip_info(options, &msg) ? LOG_WARN : LOG_INFO; crypto_digest_t *geoip_digest_env = NULL; tor_assert(family == AF_INET || family == AF_INET6); if (!(f = tor_fopen_cloexec(filename, "r"))) { log_fn(severity, LD_GENERAL, "Failed to open GEOIP file %s. %s", filename, msg); return -1; } if (!geoip_countries) init_geoip_countries(); if (family == AF_INET) { if (geoip_ipv4_entries) { SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, e, tor_free(e)); smartlist_free(geoip_ipv4_entries); } geoip_ipv4_entries = smartlist_new(); } else { /* AF_INET6 */ if (geoip_ipv6_entries) { SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, e, tor_free(e)); smartlist_free(geoip_ipv6_entries); } geoip_ipv6_entries = smartlist_new(); } geoip_digest_env = crypto_digest_new(); log_notice(LD_GENERAL, "Parsing GEOIP %s file %s.", (family == AF_INET) ? "IPv4" : "IPv6", filename); while (!feof(f)) { char buf[512]; if (fgets(buf, (int)sizeof(buf), f) == NULL) break; crypto_digest_add_bytes(geoip_digest_env, buf, strlen(buf)); /* FFFF track full country name. */ geoip_parse_entry(buf, family); } /*XXXX abort and return -1 if no entries/illformed?*/ fclose(f); /* Sort list and remember file digests so that we can include it in * our extra-info descriptors. */ if (family == AF_INET) { smartlist_sort(geoip_ipv4_entries, geoip_ipv4_compare_entries_); /* Okay, now we need to maybe change our mind about what is in * which country. We do this for IPv4 only since that's what we * store in node->country. */ refresh_all_country_info(); crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN); } else { /* AF_INET6 */ smartlist_sort(geoip_ipv6_entries, geoip_ipv6_compare_entries_); crypto_digest_get_digest(geoip_digest_env, geoip6_digest, DIGEST_LEN); } crypto_digest_free(geoip_digest_env); return 0; } /** Given an IP address in host order, return a number representing the * country to which that address belongs, -1 for "No geoip information * available", or 0 for the 'unknown country'. The return value will always * be less than geoip_get_n_countries(). To decode it, call * geoip_get_country_name(). */ int geoip_get_country_by_ipv4(uint32_t ipaddr) { geoip_ipv4_entry_t *ent; if (!geoip_ipv4_entries) return -1; ent = smartlist_bsearch(geoip_ipv4_entries, &ipaddr, geoip_ipv4_compare_key_to_entry_); return ent ? (int)ent->country : 0; } /** Given an IPv6 address, return a number representing the country to * which that address belongs, -1 for "No geoip information available", or * 0 for the 'unknown country'. The return value will always be less than * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). */ int geoip_get_country_by_ipv6(const struct in6_addr *addr) { geoip_ipv6_entry_t *ent; if (!geoip_ipv6_entries) return -1; ent = smartlist_bsearch(geoip_ipv6_entries, addr, geoip_ipv6_compare_key_to_entry_); return ent ? (int)ent->country : 0; } /** Given an IP address, return a number representing the country to which * that address belongs, -1 for "No geoip information available", or 0 for * the 'unknown country'. The return value will always be less than * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). */ int geoip_get_country_by_addr(const tor_addr_t *addr) { if (tor_addr_family(addr) == AF_INET) { return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr)); } else if (tor_addr_family(addr) == AF_INET6) { return geoip_get_country_by_ipv6(tor_addr_to_in6(addr)); } else { return -1; } } /** Return the number of countries recognized by the GeoIP country list. */ int geoip_get_n_countries(void) { if (!geoip_countries) init_geoip_countries(); return (int) smartlist_len(geoip_countries); } /** Return the two-letter country code associated with the number num, * or "??" for an unknown value. */ const char * geoip_get_country_name(country_t num) { if (geoip_countries && num >= 0 && num < smartlist_len(geoip_countries)) { geoip_country_t *c = smartlist_get(geoip_countries, num); return c->countrycode; } else return "??"; } /** Return true iff we have loaded a GeoIP database.*/ int geoip_is_loaded(sa_family_t family) { tor_assert(family == AF_INET || family == AF_INET6); if (geoip_countries == NULL) return 0; if (family == AF_INET) return geoip_ipv4_entries != NULL; else /* AF_INET6 */ return geoip_ipv6_entries != NULL; } /** Return the hex-encoded SHA1 digest of the loaded GeoIP file. The * result does not need to be deallocated, but will be overwritten by the * next call of hex_str(). */ const char * geoip_db_digest(sa_family_t family) { tor_assert(family == AF_INET || family == AF_INET6); if (family == AF_INET) return hex_str(geoip_digest, DIGEST_LEN); else /* AF_INET6 */ return hex_str(geoip6_digest, DIGEST_LEN); } /** Entry in a map from IP address to the last time we've seen an incoming * connection from that IP address. Used by bridges only, to track which * countries have them blocked. */ typedef struct clientmap_entry_t { HT_ENTRY(clientmap_entry_t) node; tor_addr_t addr; /** Time when we last saw this IP address, in MINUTES since the epoch. * * (This will run out of space around 4011 CE. If Tor is still in use around * 4000 CE, please remember to add more bits to last_seen_in_minutes.) */ unsigned int last_seen_in_minutes:30; unsigned int action:2; } clientmap_entry_t; /** Largest allowable value for last_seen_in_minutes. (It's a 30-bit field, * so it can hold up to (1u<<30)-1, or 0x3fffffffu. */ #define MAX_LAST_SEEN_IN_MINUTES 0X3FFFFFFFu /** Map from client IP address to last time seen. */ static HT_HEAD(clientmap, clientmap_entry_t) client_history = HT_INITIALIZER(); /** Hashtable helper: compute a hash of a clientmap_entry_t. */ static INLINE unsigned clientmap_entry_hash(const clientmap_entry_t *a) { return ht_improve_hash(tor_addr_hash(&a->addr)); } /** Hashtable helper: compare two clientmap_entry_t values for equality. */ static INLINE int clientmap_entries_eq(const clientmap_entry_t *a, const clientmap_entry_t *b) { return !tor_addr_compare(&a->addr, &b->addr, CMP_EXACT) && a->action == b->action; } HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash, clientmap_entries_eq); HT_GENERATE(clientmap, clientmap_entry_t, node, clientmap_entry_hash, clientmap_entries_eq, 0.6, malloc, realloc, free); /** Clear history of connecting clients used by entry and bridge stats. */ static void client_history_clear(void) { clientmap_entry_t **ent, **next, *this; for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) { if ((*ent)->action == GEOIP_CLIENT_CONNECT) { this = *ent; next = HT_NEXT_RMV(clientmap, &client_history, ent); tor_free(this); } else { next = HT_NEXT(clientmap, &client_history, ent); } } } /** Note that we've seen a client connect from the IP addr * at time now. Ignored by all but bridges and directories if * configured accordingly. */ void geoip_note_client_seen(geoip_client_action_t action, const tor_addr_t *addr, time_t now) { const or_options_t *options = get_options(); clientmap_entry_t lookup, *ent; if (action == GEOIP_CLIENT_CONNECT) { /* Only remember statistics as entry guard or as bridge. */ if (!options->EntryStatistics && (!(options->BridgeRelay && options->BridgeRecordUsageByCountry))) return; } else { if (options->BridgeRelay || options->BridgeAuthoritativeDir || !options->DirReqStatistics) return; } tor_addr_copy(&lookup.addr, addr); lookup.action = (int)action; ent = HT_FIND(clientmap, &client_history, &lookup); if (! ent) { ent = tor_malloc_zero(sizeof(clientmap_entry_t)); tor_addr_copy(&ent->addr, addr); ent->action = (int)action; HT_INSERT(clientmap, &client_history, ent); } if (now / 60 <= (int)MAX_LAST_SEEN_IN_MINUTES && now >= 0) ent->last_seen_in_minutes = (unsigned)(now/60); else ent->last_seen_in_minutes = 0; if (action == GEOIP_CLIENT_NETWORKSTATUS) { int country_idx = geoip_get_country_by_addr(addr); if (country_idx < 0) country_idx = 0; /** unresolved requests are stored at index 0. */ if (country_idx >= 0 && country_idx < smartlist_len(geoip_countries)) { geoip_country_t *country = smartlist_get(geoip_countries, country_idx); ++country->n_v3_ns_requests; } } } /** HT_FOREACH helper: remove a clientmap_entry_t from the hashtable if it's * older than a certain time. */ static int remove_old_client_helper_(struct clientmap_entry_t *ent, void *_cutoff) { time_t cutoff = *(time_t*)_cutoff / 60; if (ent->last_seen_in_minutes < cutoff) { tor_free(ent); return 1; } else { return 0; } } /** Forget about all clients that haven't connected since cutoff. */ void geoip_remove_old_clients(time_t cutoff) { clientmap_HT_FOREACH_FN(&client_history, remove_old_client_helper_, &cutoff); } /** How many responses are we giving to clients requesting v3 network * statuses? */ static uint32_t ns_v3_responses[GEOIP_NS_RESPONSE_NUM]; /** Note that we've rejected a client's request for a v3 network status * for reason reason at time now. */ void geoip_note_ns_response(geoip_ns_response_t response) { static int arrays_initialized = 0; if (!get_options()->DirReqStatistics) return; if (!arrays_initialized) { memset(ns_v3_responses, 0, sizeof(ns_v3_responses)); arrays_initialized = 1; } tor_assert(response < GEOIP_NS_RESPONSE_NUM); ns_v3_responses[response]++; } /** Do not mention any country from which fewer than this number of IPs have * connected. This conceivably avoids reporting information that could * deanonymize users, though analysis is lacking. */ #define MIN_IPS_TO_NOTE_COUNTRY 1 /** Do not report any geoip data at all if we have fewer than this number of * IPs to report about. */ #define MIN_IPS_TO_NOTE_ANYTHING 1 /** When reporting geoip data about countries, round up to the nearest * multiple of this value. */ #define IP_GRANULARITY 8 /** Helper type: used to sort per-country totals by value. */ typedef struct c_hist_t { char country[3]; /**< Two-letter country code. */ unsigned total; /**< Total IP addresses seen in this country. */ } c_hist_t; /** Sorting helper: return -1, 1, or 0 based on comparison of two * geoip_ipv4_entry_t. Sort in descending order of total, and then by country * code. */ static int c_hist_compare_(const void **_a, const void **_b) { const c_hist_t *a = *_a, *b = *_b; if (a->total > b->total) return -1; else if (a->total < b->total) return 1; else return strcmp(a->country, b->country); } /** When there are incomplete directory requests at the end of a 24-hour * period, consider those requests running for longer than this timeout as * failed, the others as still running. */ #define DIRREQ_TIMEOUT (10*60) /** Entry in a map from either chan->global_identifier for direct requests * or a unique circuit identifier for tunneled requests to request time, * response size, and completion time of a network status request. Used to * measure download times of requests to derive average client * bandwidths. */ typedef struct dirreq_map_entry_t { HT_ENTRY(dirreq_map_entry_t) node; /** Unique identifier for this network status request; this is either the * chan->global_identifier of the dir channel (direct request) or a new * locally unique identifier of a circuit (tunneled request). This ID is * only unique among other direct or tunneled requests, respectively. */ uint64_t dirreq_id; unsigned int state:3; /**< State of this directory request. */ unsigned int type:1; /**< Is this a direct or a tunneled request? */ unsigned int completed:1; /**< Is this request complete? */ /** When did we receive the request and started sending the response? */ struct timeval request_time; size_t response_size; /**< What is the size of the response in bytes? */ struct timeval completion_time; /**< When did the request succeed? */ } dirreq_map_entry_t; /** Map of all directory requests asking for v2 or v3 network statuses in * the current geoip-stats interval. Values are * of type *dirreq_map_entry_t. */ static HT_HEAD(dirreqmap, dirreq_map_entry_t) dirreq_map = HT_INITIALIZER(); static int dirreq_map_ent_eq(const dirreq_map_entry_t *a, const dirreq_map_entry_t *b) { return a->dirreq_id == b->dirreq_id && a->type == b->type; } /* DOCDOC dirreq_map_ent_hash */ static unsigned dirreq_map_ent_hash(const dirreq_map_entry_t *entry) { unsigned u = (unsigned) entry->dirreq_id; u += entry->type << 20; return u; } HT_PROTOTYPE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash, dirreq_map_ent_eq); HT_GENERATE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash, dirreq_map_ent_eq, 0.6, malloc, realloc, free); /** Helper: Put entry into map of directory requests using * type and dirreq_id as key parts. If there is * already an entry for that key, print out a BUG warning and return. */ static void dirreq_map_put_(dirreq_map_entry_t *entry, dirreq_type_t type, uint64_t dirreq_id) { dirreq_map_entry_t *old_ent; tor_assert(entry->type == type); tor_assert(entry->dirreq_id == dirreq_id); /* XXXX we could switch this to HT_INSERT some time, since it seems that * this bug doesn't happen. But since this function doesn't seem to be * critical-path, it's sane to leave it alone. */ old_ent = HT_REPLACE(dirreqmap, &dirreq_map, entry); if (old_ent && old_ent != entry) { log_warn(LD_BUG, "Error when putting directory request into local " "map. There was already an entry for the same identifier."); return; } } /** Helper: Look up and return an entry in the map of directory requests * using type and dirreq_id as key parts. If there * is no such entry, return NULL. */ static dirreq_map_entry_t * dirreq_map_get_(dirreq_type_t type, uint64_t dirreq_id) { dirreq_map_entry_t lookup; lookup.type = type; lookup.dirreq_id = dirreq_id; return HT_FIND(dirreqmap, &dirreq_map, &lookup); } /** Note that an either direct or tunneled (see type) directory * request for a v3 network status with unique ID dirreq_id of size * response_size has started. */ void geoip_start_dirreq(uint64_t dirreq_id, size_t response_size, dirreq_type_t type) { dirreq_map_entry_t *ent; if (!get_options()->DirReqStatistics) return; ent = tor_malloc_zero(sizeof(dirreq_map_entry_t)); ent->dirreq_id = dirreq_id; tor_gettimeofday(&ent->request_time); ent->response_size = response_size; ent->type = type; dirreq_map_put_(ent, type, dirreq_id); } /** Change the state of the either direct or tunneled (see type) * directory request with dirreq_id to new_state and * possibly mark it as completed. If no entry can be found for the given * key parts (e.g., if this is a directory request that we are not * measuring, or one that was started in the previous measurement period), * or if the state cannot be advanced to new_state, do nothing. */ void geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type, dirreq_state_t new_state) { dirreq_map_entry_t *ent; if (!get_options()->DirReqStatistics) return; ent = dirreq_map_get_(type, dirreq_id); if (!ent) return; if (new_state == DIRREQ_IS_FOR_NETWORK_STATUS) return; if (new_state - 1 != ent->state) return; ent->state = new_state; if ((type == DIRREQ_DIRECT && new_state == DIRREQ_FLUSHING_DIR_CONN_FINISHED) || (type == DIRREQ_TUNNELED && new_state == DIRREQ_CHANNEL_BUFFER_FLUSHED)) { tor_gettimeofday(&ent->completion_time); ent->completed = 1; } } /** Return a newly allocated comma-separated string containing statistics * on network status downloads. The string contains the number of completed * requests, timeouts, and still running requests as well as the download * times by deciles and quartiles. Return NULL if we have not observed * requests for long enough. */ static char * geoip_get_dirreq_history(dirreq_type_t type) { char *result = NULL; smartlist_t *dirreq_completed = NULL; uint32_t complete = 0, timeouts = 0, running = 0; int bufsize = 1024, written; dirreq_map_entry_t **ptr, **next, *ent; struct timeval now; tor_gettimeofday(&now); dirreq_completed = smartlist_new(); for (ptr = HT_START(dirreqmap, &dirreq_map); ptr; ptr = next) { ent = *ptr; if (ent->type != type) { next = HT_NEXT(dirreqmap, &dirreq_map, ptr); continue; } else { if (ent->completed) { smartlist_add(dirreq_completed, ent); complete++; next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ptr); } else { if (tv_mdiff(&ent->request_time, &now) / 1000 > DIRREQ_TIMEOUT) timeouts++; else running++; next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ptr); tor_free(ent); } } } #define DIR_REQ_GRANULARITY 4 complete = round_uint32_to_next_multiple_of(complete, DIR_REQ_GRANULARITY); timeouts = round_uint32_to_next_multiple_of(timeouts, DIR_REQ_GRANULARITY); running = round_uint32_to_next_multiple_of(running, DIR_REQ_GRANULARITY); result = tor_malloc_zero(bufsize); written = tor_snprintf(result, bufsize, "complete=%u,timeout=%u," "running=%u", complete, timeouts, running); if (written < 0) { tor_free(result); goto done; } #define MIN_DIR_REQ_RESPONSES 16 if (complete >= MIN_DIR_REQ_RESPONSES) { uint32_t *dltimes; /* We may have rounded 'completed' up. Here we want to use the * real value. */ complete = smartlist_len(dirreq_completed); dltimes = tor_malloc_zero(sizeof(uint32_t) * complete); SMARTLIST_FOREACH_BEGIN(dirreq_completed, dirreq_map_entry_t *, ent) { uint32_t bytes_per_second; uint32_t time_diff = (uint32_t) tv_mdiff(&ent->request_time, &ent->completion_time); if (time_diff == 0) time_diff = 1; /* Avoid DIV/0; "instant" answers are impossible * by law of nature or something, but a milisecond * is a bit greater than "instantly" */ bytes_per_second = (uint32_t)(1000 * ent->response_size / time_diff); dltimes[ent_sl_idx] = bytes_per_second; } SMARTLIST_FOREACH_END(ent); median_uint32(dltimes, complete); /* sorts as a side effect. */ written = tor_snprintf(result + written, bufsize - written, ",min=%u,d1=%u,d2=%u,q1=%u,d3=%u,d4=%u,md=%u," "d6=%u,d7=%u,q3=%u,d8=%u,d9=%u,max=%u", dltimes[0], dltimes[1*complete/10-1], dltimes[2*complete/10-1], dltimes[1*complete/4-1], dltimes[3*complete/10-1], dltimes[4*complete/10-1], dltimes[5*complete/10-1], dltimes[6*complete/10-1], dltimes[7*complete/10-1], dltimes[3*complete/4-1], dltimes[8*complete/10-1], dltimes[9*complete/10-1], dltimes[complete-1]); if (written<0) tor_free(result); tor_free(dltimes); } done: SMARTLIST_FOREACH(dirreq_completed, dirreq_map_entry_t *, ent, tor_free(ent)); smartlist_free(dirreq_completed); return result; } /** Store a newly allocated comma-separated string in * *country_str containing entries for all the countries from * which we've seen enough clients connect as a bridge, directory * server, or entry guard. The entry format is cc=num where num is the * number of IPs we've seen connecting from that country, and cc is a * lowercased country code. *country_str is set to NULL if * we're not ready to export per country data yet. * * Store a newly allocated comma-separated string in ipver_str * containing entries for clients connecting over IPv4 and IPv6. The * format is family=num where num is the nubmer of IPs we've seen * connecting over that protocol family, and family is 'v4' or 'v6'. * * Return 0 on success and -1 if we're missing geoip data. */ int geoip_get_client_history(geoip_client_action_t action, char **country_str, char **ipver_str) { unsigned granularity = IP_GRANULARITY; smartlist_t *entries = NULL; int n_countries = geoip_get_n_countries(); int i; clientmap_entry_t **ent; unsigned *counts = NULL; unsigned total = 0; unsigned ipv4_count = 0, ipv6_count = 0; if (!geoip_is_loaded(AF_INET) && !geoip_is_loaded(AF_INET6)) return -1; counts = tor_malloc_zero(sizeof(unsigned)*n_countries); HT_FOREACH(ent, clientmap, &client_history) { int country; if ((*ent)->action != (int)action) continue; country = geoip_get_country_by_addr(&(*ent)->addr); if (country < 0) country = 0; /** unresolved requests are stored at index 0. */ tor_assert(0 <= country && country < n_countries); ++counts[country]; ++total; switch (tor_addr_family(&(*ent)->addr)) { case AF_INET: ipv4_count++; break; case AF_INET6: ipv6_count++; break; } } if (ipver_str) { smartlist_t *chunks = smartlist_new(); smartlist_add_asprintf(chunks, "v4=%u", round_to_next_multiple_of(ipv4_count, granularity)); smartlist_add_asprintf(chunks, "v6=%u", round_to_next_multiple_of(ipv6_count, granularity)); *ipver_str = smartlist_join_strings(chunks, ",", 0, NULL); SMARTLIST_FOREACH(chunks, char *, c, tor_free(c)); smartlist_free(chunks); } /* Don't record per country data if we haven't seen enough IPs. */ if (total < MIN_IPS_TO_NOTE_ANYTHING) { tor_free(counts); if (country_str) *country_str = NULL; return 0; } /* Make a list of c_hist_t */ entries = smartlist_new(); for (i = 0; i < n_countries; ++i) { unsigned c = counts[i]; const char *countrycode; c_hist_t *ent; /* Only report a country if it has a minimum number of IPs. */ if (c >= MIN_IPS_TO_NOTE_COUNTRY) { c = round_to_next_multiple_of(c, granularity); countrycode = geoip_get_country_name(i); ent = tor_malloc(sizeof(c_hist_t)); strlcpy(ent->country, countrycode, sizeof(ent->country)); ent->total = c; smartlist_add(entries, ent); } } /* Sort entries. Note that we must do this _AFTER_ rounding, or else * the sort order could leak info. */ smartlist_sort(entries, c_hist_compare_); if (country_str) { smartlist_t *chunks = smartlist_new(); SMARTLIST_FOREACH(entries, c_hist_t *, ch, { smartlist_add_asprintf(chunks, "%s=%u", ch->country, ch->total); }); *country_str = smartlist_join_strings(chunks, ",", 0, NULL); SMARTLIST_FOREACH(chunks, char *, c, tor_free(c)); smartlist_free(chunks); } SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c)); smartlist_free(entries); tor_free(counts); return 0; } /** Return a newly allocated string holding the per-country request history * for v3 network statuses in a format suitable for an extra-info document, * or NULL on failure. */ char * geoip_get_request_history(void) { smartlist_t *entries, *strings; char *result; unsigned granularity = IP_GRANULARITY; if (!geoip_countries) return NULL; entries = smartlist_new(); SMARTLIST_FOREACH_BEGIN(geoip_countries, geoip_country_t *, c) { uint32_t tot = 0; c_hist_t *ent; tot = c->n_v3_ns_requests; if (!tot) continue; ent = tor_malloc_zero(sizeof(c_hist_t)); strlcpy(ent->country, c->countrycode, sizeof(ent->country)); ent->total = round_to_next_multiple_of(tot, granularity); smartlist_add(entries, ent); } SMARTLIST_FOREACH_END(c); smartlist_sort(entries, c_hist_compare_); strings = smartlist_new(); SMARTLIST_FOREACH(entries, c_hist_t *, ent, { smartlist_add_asprintf(strings, "%s=%u", ent->country, ent->total); }); result = smartlist_join_strings(strings, ",", 0, NULL); SMARTLIST_FOREACH(strings, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(entries, c_hist_t *, ent, tor_free(ent)); smartlist_free(strings); smartlist_free(entries); return result; } /** Start time of directory request stats or 0 if we're not collecting * directory request statistics. */ static time_t start_of_dirreq_stats_interval; /** Initialize directory request stats. */ void geoip_dirreq_stats_init(time_t now) { start_of_dirreq_stats_interval = now; } /** Reset counters for dirreq stats. */ void geoip_reset_dirreq_stats(time_t now) { SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, { c->n_v3_ns_requests = 0; }); { clientmap_entry_t **ent, **next, *this; for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) { if ((*ent)->action == GEOIP_CLIENT_NETWORKSTATUS) { this = *ent; next = HT_NEXT_RMV(clientmap, &client_history, ent); tor_free(this); } else { next = HT_NEXT(clientmap, &client_history, ent); } } } memset(ns_v3_responses, 0, sizeof(ns_v3_responses)); { dirreq_map_entry_t **ent, **next, *this; for (ent = HT_START(dirreqmap, &dirreq_map); ent != NULL; ent = next) { this = *ent; next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ent); tor_free(this); } } start_of_dirreq_stats_interval = now; } /** Stop collecting directory request stats in a way that we can re-start * doing so in geoip_dirreq_stats_init(). */ void geoip_dirreq_stats_term(void) { geoip_reset_dirreq_stats(0); } /** Return a newly allocated string containing the dirreq statistics * until now, or NULL if we're not collecting dirreq stats. Caller * must ensure start_of_dirreq_stats_interval is in the past. */ char * geoip_format_dirreq_stats(time_t now) { char t[ISO_TIME_LEN+1]; int i; char *v3_ips_string, *v3_reqs_string, *v3_direct_dl_string, *v3_tunneled_dl_string; char *result; if (!start_of_dirreq_stats_interval) return NULL; /* Not initialized. */ tor_assert(now >= start_of_dirreq_stats_interval); format_iso_time(t, now); geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS, &v3_ips_string, NULL); v3_reqs_string = geoip_get_request_history(); #define RESPONSE_GRANULARITY 8 for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) { ns_v3_responses[i] = round_uint32_to_next_multiple_of( ns_v3_responses[i], RESPONSE_GRANULARITY); } #undef RESPONSE_GRANULARITY v3_direct_dl_string = geoip_get_dirreq_history(DIRREQ_DIRECT); v3_tunneled_dl_string = geoip_get_dirreq_history(DIRREQ_TUNNELED); /* Put everything together into a single string. */ tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n" "dirreq-v3-ips %s\n" "dirreq-v3-reqs %s\n" "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u," "not-found=%u,not-modified=%u,busy=%u\n" "dirreq-v3-direct-dl %s\n" "dirreq-v3-tunneled-dl %s\n", t, (unsigned) (now - start_of_dirreq_stats_interval), v3_ips_string ? v3_ips_string : "", v3_reqs_string ? v3_reqs_string : "", ns_v3_responses[GEOIP_SUCCESS], ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS], ns_v3_responses[GEOIP_REJECT_UNAVAILABLE], ns_v3_responses[GEOIP_REJECT_NOT_FOUND], ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED], ns_v3_responses[GEOIP_REJECT_BUSY], v3_direct_dl_string ? v3_direct_dl_string : "", v3_tunneled_dl_string ? v3_tunneled_dl_string : ""); /* Free partial strings. */ tor_free(v3_ips_string); tor_free(v3_reqs_string); tor_free(v3_direct_dl_string); tor_free(v3_tunneled_dl_string); return result; } /** If 24 hours have passed since the beginning of the current dirreq * stats period, write dirreq stats to $DATADIR/stats/dirreq-stats * (possibly overwriting an existing file) and reset counters. Return * when we would next want to write dirreq stats or 0 if we never want to * write. */ time_t geoip_dirreq_stats_write(time_t now) { char *statsdir = NULL, *filename = NULL, *str = NULL; if (!start_of_dirreq_stats_interval) return 0; /* Not initialized. */ if (start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL > now) goto done; /* Not ready to write. */ /* Discard all items in the client history that are too old. */ geoip_remove_old_clients(start_of_dirreq_stats_interval); /* Generate history string .*/ str = geoip_format_dirreq_stats(now); /* Write dirreq-stats string to disk. */ statsdir = get_datadir_fname("stats"); if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { log_warn(LD_HIST, "Unable to create stats/ directory!"); goto done; } filename = get_datadir_fname2("stats", "dirreq-stats"); if (write_str_to_file(filename, str, 0) < 0) log_warn(LD_HIST, "Unable to write dirreq statistics to disk!"); /* Reset measurement interval start. */ geoip_reset_dirreq_stats(now); done: tor_free(statsdir); tor_free(filename); tor_free(str); return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL; } /** Start time of bridge stats or 0 if we're not collecting bridge * statistics. */ static time_t start_of_bridge_stats_interval; /** Initialize bridge stats. */ void geoip_bridge_stats_init(time_t now) { start_of_bridge_stats_interval = now; } /** Stop collecting bridge stats in a way that we can re-start doing so in * geoip_bridge_stats_init(). */ void geoip_bridge_stats_term(void) { client_history_clear(); start_of_bridge_stats_interval = 0; } /** Validate a bridge statistics string as it would be written to a * current extra-info descriptor. Return 1 if the string is valid and * recent enough, or 0 otherwise. */ static int validate_bridge_stats(const char *stats_str, time_t now) { char stats_end_str[ISO_TIME_LEN+1], stats_start_str[ISO_TIME_LEN+1], *eos; const char *BRIDGE_STATS_END = "bridge-stats-end "; const char *BRIDGE_IPS = "bridge-ips "; const char *BRIDGE_IPS_EMPTY_LINE = "bridge-ips\n"; const char *tmp; time_t stats_end_time; int seconds; tor_assert(stats_str); /* Parse timestamp and number of seconds from "bridge-stats-end YYYY-MM-DD HH:MM:SS (N s)" */ tmp = find_str_at_start_of_line(stats_str, BRIDGE_STATS_END); if (!tmp) return 0; tmp += strlen(BRIDGE_STATS_END); if (strlen(tmp) < ISO_TIME_LEN + 6) return 0; strlcpy(stats_end_str, tmp, sizeof(stats_end_str)); if (parse_iso_time(stats_end_str, &stats_end_time) < 0) return 0; if (stats_end_time < now - (25*60*60) || stats_end_time > now + (1*60*60)) return 0; seconds = (int)strtol(tmp + ISO_TIME_LEN + 2, &eos, 10); if (!eos || seconds < 23*60*60) return 0; format_iso_time(stats_start_str, stats_end_time - seconds); /* Parse: "bridge-ips CC=N,CC=N,..." */ tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS); if (!tmp) { /* Look if there is an empty "bridge-ips" line */ tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS_EMPTY_LINE); if (!tmp) return 0; } return 1; } /** Most recent bridge statistics formatted to be written to extra-info * descriptors. */ static char *bridge_stats_extrainfo = NULL; /** Return a newly allocated string holding our bridge usage stats by country * in a format suitable for inclusion in an extrainfo document. Return NULL on * failure. */ char * geoip_format_bridge_stats(time_t now) { char *out = NULL, *country_data = NULL, *ipver_data = NULL; long duration = now - start_of_bridge_stats_interval; char written[ISO_TIME_LEN+1]; if (duration < 0) return NULL; if (!start_of_bridge_stats_interval) return NULL; /* Not initialized. */ format_iso_time(written, now); geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data); tor_asprintf(&out, "bridge-stats-end %s (%ld s)\n" "bridge-ips %s\n" "bridge-ip-versions %s\n", written, duration, country_data ? country_data : "", ipver_data ? ipver_data : ""); tor_free(country_data); tor_free(ipver_data); return out; } /** Return a newly allocated string holding our bridge usage stats by country * in a format suitable for the answer to a controller request. Return NULL on * failure. */ static char * format_bridge_stats_controller(time_t now) { char *out = NULL, *country_data = NULL, *ipver_data = NULL; char started[ISO_TIME_LEN+1]; (void) now; format_iso_time(started, start_of_bridge_stats_interval); geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data); tor_asprintf(&out, "TimeStarted=\"%s\" CountrySummary=%s IPVersions=%s", started, country_data ? country_data : "", ipver_data ? ipver_data : ""); tor_free(country_data); tor_free(ipver_data); return out; } /** Write bridge statistics to $DATADIR/stats/bridge-stats and return * when we should next try to write statistics. */ time_t geoip_bridge_stats_write(time_t now) { char *filename = NULL, *val = NULL, *statsdir = NULL; /* Check if 24 hours have passed since starting measurements. */ if (now < start_of_bridge_stats_interval + WRITE_STATS_INTERVAL) return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL; /* Discard all items in the client history that are too old. */ geoip_remove_old_clients(start_of_bridge_stats_interval); /* Generate formatted string */ val = geoip_format_bridge_stats(now); if (val == NULL) goto done; /* Update the stored value. */ tor_free(bridge_stats_extrainfo); bridge_stats_extrainfo = val; start_of_bridge_stats_interval = now; /* Write it to disk. */ statsdir = get_datadir_fname("stats"); if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) goto done; filename = get_datadir_fname2("stats", "bridge-stats"); write_str_to_file(filename, bridge_stats_extrainfo, 0); /* Tell the controller, "hey, there are clients!" */ { char *controller_str = format_bridge_stats_controller(now); if (controller_str) control_event_clients_seen(controller_str); tor_free(controller_str); } done: tor_free(filename); tor_free(statsdir); return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL; } /** Try to load the most recent bridge statistics from disk, unless we * have finished a measurement interval lately, and check whether they * are still recent enough. */ static void load_bridge_stats(time_t now) { char *fname, *contents; if (bridge_stats_extrainfo) return; fname = get_datadir_fname2("stats", "bridge-stats"); contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); if (contents && validate_bridge_stats(contents, now)) { bridge_stats_extrainfo = contents; } else { tor_free(contents); } tor_free(fname); } /** Return most recent bridge statistics for inclusion in extra-info * descriptors, or NULL if we don't have recent bridge statistics. */ const char * geoip_get_bridge_stats_extrainfo(time_t now) { load_bridge_stats(now); return bridge_stats_extrainfo; } /** Return a new string containing the recent bridge statistics to be returned * to controller clients, or NULL if we don't have any bridge statistics. */ char * geoip_get_bridge_stats_controller(time_t now) { return format_bridge_stats_controller(now); } /** Start time of entry stats or 0 if we're not collecting entry * statistics. */ static time_t start_of_entry_stats_interval; /** Initialize entry stats. */ void geoip_entry_stats_init(time_t now) { start_of_entry_stats_interval = now; } /** Reset counters for entry stats. */ void geoip_reset_entry_stats(time_t now) { client_history_clear(); start_of_entry_stats_interval = now; } /** Stop collecting entry stats in a way that we can re-start doing so in * geoip_entry_stats_init(). */ void geoip_entry_stats_term(void) { geoip_reset_entry_stats(0); } /** Return a newly allocated string containing the entry statistics * until now, or NULL if we're not collecting entry stats. Caller * must ensure start_of_entry_stats_interval lies in the past. */ char * geoip_format_entry_stats(time_t now) { char t[ISO_TIME_LEN+1]; char *data = NULL; char *result; if (!start_of_entry_stats_interval) return NULL; /* Not initialized. */ tor_assert(now >= start_of_entry_stats_interval); geoip_get_client_history(GEOIP_CLIENT_CONNECT, &data, NULL); format_iso_time(t, now); tor_asprintf(&result, "entry-stats-end %s (%u s)\n" "entry-ips %s\n", t, (unsigned) (now - start_of_entry_stats_interval), data ? data : ""); tor_free(data); return result; } /** If 24 hours have passed since the beginning of the current entry stats * period, write entry stats to $DATADIR/stats/entry-stats (possibly * overwriting an existing file) and reset counters. Return when we would * next want to write entry stats or 0 if we never want to write. */ time_t geoip_entry_stats_write(time_t now) { char *statsdir = NULL, *filename = NULL, *str = NULL; if (!start_of_entry_stats_interval) return 0; /* Not initialized. */ if (start_of_entry_stats_interval + WRITE_STATS_INTERVAL > now) goto done; /* Not ready to write. */ /* Discard all items in the client history that are too old. */ geoip_remove_old_clients(start_of_entry_stats_interval); /* Generate history string .*/ str = geoip_format_entry_stats(now); /* Write entry-stats string to disk. */ statsdir = get_datadir_fname("stats"); if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { log_warn(LD_HIST, "Unable to create stats/ directory!"); goto done; } filename = get_datadir_fname2("stats", "entry-stats"); if (write_str_to_file(filename, str, 0) < 0) log_warn(LD_HIST, "Unable to write entry statistics to disk!"); /* Reset measurement interval start. */ geoip_reset_entry_stats(now); done: tor_free(statsdir); tor_free(filename); tor_free(str); return start_of_entry_stats_interval + WRITE_STATS_INTERVAL; } /** Helper used to implement GETINFO ip-to-country/... controller command. */ int getinfo_helper_geoip(control_connection_t *control_conn, const char *question, char **answer, const char **errmsg) { (void)control_conn; if (!strcmpstart(question, "ip-to-country/")) { int c; sa_family_t family; tor_addr_t addr; question += strlen("ip-to-country/"); family = tor_addr_parse(&addr, question); if (family != AF_INET && family != AF_INET6) { *errmsg = "Invalid address family"; return -1; } if (!geoip_is_loaded(family)) { *errmsg = "GeoIP data not loaded"; return -1; } if (family == AF_INET) c = geoip_get_country_by_ipv4(tor_addr_to_ipv4h(&addr)); else /* AF_INET6 */ c = geoip_get_country_by_ipv6(tor_addr_to_in6(&addr)); *answer = tor_strdup(geoip_get_country_name(c)); } return 0; } /** Release all storage held by the GeoIP databases and country list. */ static void clear_geoip_db(void) { if (geoip_countries) { SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, tor_free(c)); smartlist_free(geoip_countries); } strmap_free(country_idxplus1_by_lc_code, NULL); if (geoip_ipv4_entries) { SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, ent, tor_free(ent)); smartlist_free(geoip_ipv4_entries); } if (geoip_ipv6_entries) { SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, ent, tor_free(ent)); smartlist_free(geoip_ipv6_entries); } geoip_countries = NULL; country_idxplus1_by_lc_code = NULL; geoip_ipv4_entries = NULL; geoip_ipv6_entries = NULL; } /** Release all storage held in this file. */ void geoip_free_all(void) { { clientmap_entry_t **ent, **next, *this; for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) { this = *ent; next = HT_NEXT_RMV(clientmap, &client_history, ent); tor_free(this); } HT_CLEAR(clientmap, &client_history); } { dirreq_map_entry_t **ent, **next, *this; for (ent = HT_START(dirreqmap, &dirreq_map); ent != NULL; ent = next) { this = *ent; next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ent); tor_free(this); } HT_CLEAR(dirreqmap, &dirreq_map); } clear_geoip_db(); } tor-0.2.4.20/src/or/connection_or.c0000644000175000017500000024066712255745673013733 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file connection_or.c * \brief Functions to handle OR connections, TLS handshaking, and * cells on the network. **/ #include "or.h" #include "buffers.h" /* * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ #define TOR_CHANNEL_INTERNAL_ #include "channel.h" #include "channeltls.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuitstats.h" #include "command.h" #include "config.h" #include "connection.h" #include "connection_or.h" #include "control.h" #include "dirserv.h" #include "entrynodes.h" #include "geoip.h" #include "main.h" #include "networkstatus.h" #include "nodelist.h" #include "reasons.h" #include "relay.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #ifdef USE_BUFFEREVENTS #include #endif static int connection_tls_finish_handshake(or_connection_t *conn); static int connection_or_launch_v3_or_handshake(or_connection_t *conn); static int connection_or_process_cells_from_inbuf(or_connection_t *conn); static int connection_or_check_valid_tls_handshake(or_connection_t *conn, int started_here, char *digest_rcvd_out); static void connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn); static unsigned int connection_or_is_bad_for_new_circs(or_connection_t *or_conn); static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn); /* * Call this when changing connection state, so notifications to the owning * channel can be handled. */ static void connection_or_change_state(or_connection_t *conn, uint8_t state); #ifdef USE_BUFFEREVENTS static void connection_or_handle_event_cb(struct bufferevent *bufev, short event, void *arg); #include /*XXXX REMOVE */ #endif /**************************************************************/ /** Map from identity digest of connected OR or desired OR to a connection_t * with that identity digest. If there is more than one such connection_t, * they form a linked list, with next_with_same_id as the next pointer. */ static digestmap_t *orconn_identity_map = NULL; /** If conn is listed in orconn_identity_map, remove it, and clear * conn->identity_digest. Otherwise do nothing. */ void connection_or_remove_from_identity_map(or_connection_t *conn) { or_connection_t *tmp; tor_assert(conn); if (!orconn_identity_map) return; tmp = digestmap_get(orconn_identity_map, conn->identity_digest); if (!tmp) { if (!tor_digest_is_zero(conn->identity_digest)) { log_warn(LD_BUG, "Didn't find connection '%s' on identity map when " "trying to remove it.", conn->nickname ? conn->nickname : "NULL"); } return; } if (conn == tmp) { if (conn->next_with_same_id) digestmap_set(orconn_identity_map, conn->identity_digest, conn->next_with_same_id); else digestmap_remove(orconn_identity_map, conn->identity_digest); } else { while (tmp->next_with_same_id) { if (tmp->next_with_same_id == conn) { tmp->next_with_same_id = conn->next_with_same_id; break; } tmp = tmp->next_with_same_id; } } memset(conn->identity_digest, 0, DIGEST_LEN); conn->next_with_same_id = NULL; } /** Remove all entries from the identity-to-orconn map, and clear * all identities in OR conns.*/ void connection_or_clear_identity_map(void) { smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->type == CONN_TYPE_OR) { or_connection_t *or_conn = TO_OR_CONN(conn); memset(or_conn->identity_digest, 0, DIGEST_LEN); or_conn->next_with_same_id = NULL; } }); digestmap_free(orconn_identity_map, NULL); orconn_identity_map = NULL; } /** Change conn->identity_digest to digest, and add conn into * orconn_digest_map. */ static void connection_or_set_identity_digest(or_connection_t *conn, const char *digest) { or_connection_t *tmp; tor_assert(conn); tor_assert(digest); if (!orconn_identity_map) orconn_identity_map = digestmap_new(); if (tor_memeq(conn->identity_digest, digest, DIGEST_LEN)) return; /* If the identity was set previously, remove the old mapping. */ if (! tor_digest_is_zero(conn->identity_digest)) { connection_or_remove_from_identity_map(conn); if (conn->chan) channel_clear_identity_digest(TLS_CHAN_TO_BASE(conn->chan)); } memcpy(conn->identity_digest, digest, DIGEST_LEN); /* If we're setting the ID to zero, don't add a mapping. */ if (tor_digest_is_zero(digest)) return; tmp = digestmap_set(orconn_identity_map, digest, conn); conn->next_with_same_id = tmp; /* Deal with channels */ if (conn->chan) channel_set_identity_digest(TLS_CHAN_TO_BASE(conn->chan), digest); #if 1 /* Testing code to check for bugs in representation. */ for (; tmp; tmp = tmp->next_with_same_id) { tor_assert(tor_memeq(tmp->identity_digest, digest, DIGEST_LEN)); tor_assert(tmp != conn); } #endif } /**************************************************************/ /** Map from a string describing what a non-open OR connection was doing when * failed, to an intptr_t describing the count of connections that failed that * way. Note that the count is stored _as_ the pointer. */ static strmap_t *broken_connection_counts; /** If true, do not record information in broken_connection_counts. */ static int disable_broken_connection_counts = 0; /** Record that an OR connection failed in state. */ static void note_broken_connection(const char *state) { void *ptr; intptr_t val; if (disable_broken_connection_counts) return; if (!broken_connection_counts) broken_connection_counts = strmap_new(); ptr = strmap_get(broken_connection_counts, state); val = (intptr_t)ptr; val++; ptr = (void*)val; strmap_set(broken_connection_counts, state, ptr); } /** Forget all recorded states for failed connections. If * stop_recording is true, don't record any more. */ void clear_broken_connection_map(int stop_recording) { if (broken_connection_counts) strmap_free(broken_connection_counts, NULL); broken_connection_counts = NULL; if (stop_recording) disable_broken_connection_counts = 1; } /** Write a detailed description the state of orconn into the * buflen-byte buffer at buf. This description includes not * only the OR-conn level state but also the TLS state. It's useful for * diagnosing broken handshakes. */ static void connection_or_get_state_description(or_connection_t *orconn, char *buf, size_t buflen) { connection_t *conn = TO_CONN(orconn); const char *conn_state; char tls_state[256]; tor_assert(conn->type == CONN_TYPE_OR); conn_state = conn_state_to_string(conn->type, conn->state); tor_tls_get_state_description(orconn->tls, tls_state, sizeof(tls_state)); tor_snprintf(buf, buflen, "%s with SSL state %s", conn_state, tls_state); } /** Record the current state of orconn as the state of a broken * connection. */ static void connection_or_note_state_when_broken(or_connection_t *orconn) { char buf[256]; if (disable_broken_connection_counts) return; connection_or_get_state_description(orconn, buf, sizeof(buf)); log_info(LD_HANDSHAKE,"Connection died in state '%s'", buf); note_broken_connection(buf); } /** Helper type used to sort connection states and find the most frequent. */ typedef struct broken_state_count_t { intptr_t count; const char *state; } broken_state_count_t; /** Helper function used to sort broken_state_count_t by frequency. */ static int broken_state_count_compare(const void **a_ptr, const void **b_ptr) { const broken_state_count_t *a = *a_ptr, *b = *b_ptr; if (b->count < a->count) return -1; else if (b->count == a->count) return 0; else return 1; } /** Upper limit on the number of different states to report for connection * failure. */ #define MAX_REASONS_TO_REPORT 10 /** Report a list of the top states for failed OR connections at log level * severity, in log domain domain. */ void connection_or_report_broken_states(int severity, int domain) { int total = 0; smartlist_t *items; if (!broken_connection_counts || disable_broken_connection_counts) return; items = smartlist_new(); STRMAP_FOREACH(broken_connection_counts, state, void *, countptr) { broken_state_count_t *c = tor_malloc(sizeof(broken_state_count_t)); c->count = (intptr_t)countptr; total += (int)c->count; c->state = state; smartlist_add(items, c); } STRMAP_FOREACH_END; smartlist_sort(items, broken_state_count_compare); tor_log(severity, domain, "%d connections have failed%s", total, smartlist_len(items) > MAX_REASONS_TO_REPORT ? ". Top reasons:" : ":"); SMARTLIST_FOREACH_BEGIN(items, const broken_state_count_t *, c) { if (c_sl_idx > MAX_REASONS_TO_REPORT) break; tor_log(severity, domain, " %d connections died in state %s", (int)c->count, c->state); } SMARTLIST_FOREACH_END(c); SMARTLIST_FOREACH(items, broken_state_count_t *, c, tor_free(c)); smartlist_free(items); } /** Call this to change or_connection_t states, so the owning channel_tls_t can * be notified. */ static void connection_or_change_state(or_connection_t *conn, uint8_t state) { uint8_t old_state; tor_assert(conn); old_state = conn->base_.state; conn->base_.state = state; if (conn->chan) channel_tls_handle_state_change_on_orconn(conn->chan, conn, old_state, state); } /** Return the number of circuits using an or_connection_t; this used to * be an or_connection_t field, but it got moved to channel_t and we * shouldn't maintain two copies. */ int connection_or_get_num_circuits(or_connection_t *conn) { tor_assert(conn); if (conn->chan) { return channel_num_circuits(TLS_CHAN_TO_BASE(conn->chan)); } else return 0; } /**************************************************************/ /** Pack the cell_t host-order structure src into network-order * in the buffer dest. See tor-spec.txt for details about the * wire format. * * Note that this function doesn't touch dst-\>next: the caller * should set it or clear it as appropriate. */ void cell_pack(packed_cell_t *dst, const cell_t *src, int wide_circ_ids) { char *dest = dst->body; if (wide_circ_ids) { set_uint32(dest, htonl(src->circ_id)); dest += 4; } else { set_uint16(dest, htons(src->circ_id)); dest += 2; memset(dest+CELL_MAX_NETWORK_SIZE-2, 0, 2); /*make sure it's clear */ } set_uint8(dest, src->command); memcpy(dest+1, src->payload, CELL_PAYLOAD_SIZE); } /** Unpack the network-order buffer src into a host-order * cell_t structure dest. */ static void cell_unpack(cell_t *dest, const char *src, int wide_circ_ids) { if (wide_circ_ids) { dest->circ_id = ntohl(get_uint32(src)); src += 4; } else { dest->circ_id = ntohs(get_uint16(src)); src += 2; } dest->command = get_uint8(src); memcpy(dest->payload, src+1, CELL_PAYLOAD_SIZE); } /** Write the header of cell into the first VAR_CELL_MAX_HEADER_SIZE * bytes of hdr_out. Returns number of bytes used. */ int var_cell_pack_header(const var_cell_t *cell, char *hdr_out, int wide_circ_ids) { int r; if (wide_circ_ids) { set_uint32(hdr_out, htonl(cell->circ_id)); hdr_out += 4; r = VAR_CELL_MAX_HEADER_SIZE; } else { set_uint16(hdr_out, htons(cell->circ_id)); hdr_out += 2; r = VAR_CELL_MAX_HEADER_SIZE - 2; } set_uint8(hdr_out, cell->command); set_uint16(hdr_out+1, htons(cell->payload_len)); return r; } /** Allocate and return a new var_cell_t with payload_len bytes of * payload space. */ var_cell_t * var_cell_new(uint16_t payload_len) { size_t size = STRUCT_OFFSET(var_cell_t, payload) + payload_len; var_cell_t *cell = tor_malloc_zero(size); cell->payload_len = payload_len; cell->command = 0; cell->circ_id = 0; return cell; } /** Release all space held by cell. */ void var_cell_free(var_cell_t *cell) { tor_free(cell); } /** We've received an EOF from conn. Mark it for close and return. */ int connection_or_reached_eof(or_connection_t *conn) { tor_assert(conn); log_info(LD_OR,"OR connection reached EOF. Closing."); connection_or_close_normally(conn, 1); return 0; } /** Handle any new bytes that have come in on connection conn. * If conn is in 'open' state, hand it to * connection_or_process_cells_from_inbuf() * (else do nothing). */ int connection_or_process_inbuf(or_connection_t *conn) { /** Don't let the inbuf of a nonopen OR connection grow beyond this many * bytes: it's either a broken client, a non-Tor client, or a DOS * attempt. */ #define MAX_OR_INBUF_WHEN_NONOPEN 0 int ret = 0; tor_assert(conn); switch (conn->base_.state) { case OR_CONN_STATE_PROXY_HANDSHAKING: ret = connection_read_proxy_handshake(TO_CONN(conn)); /* start TLS after handshake completion, or deal with error */ if (ret == 1) { tor_assert(TO_CONN(conn)->proxy_state == PROXY_CONNECTED); if (connection_tls_start_handshake(conn, 0) < 0) ret = -1; /* Touch the channel's active timestamp if there is one */ if (conn->chan) channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); } if (ret < 0) { connection_or_close_for_error(conn, 0); } return ret; case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: #ifdef USE_BUFFEREVENTS if (tor_tls_server_got_renegotiate(conn->tls)) connection_or_tls_renegotiated_cb(conn->tls, conn); if (conn->base_.marked_for_close) return 0; /* fall through. */ #endif case OR_CONN_STATE_OPEN: case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: return connection_or_process_cells_from_inbuf(conn); default: break; /* don't do anything */ } /* This check was necessary with 0.2.2, when the TLS_SERVER_RENEGOTIATING * check would otherwise just let data accumulate. It serves no purpose * in 0.2.3. * * XXX024 Remove this check once we verify that the above paragraph is * 100% true. */ if (buf_datalen(conn->base_.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) { log_fn(LOG_PROTOCOL_WARN, LD_NET, "Accumulated too much data (%d bytes) " "on nonopen OR connection %s %s:%u in state %s; closing.", (int)buf_datalen(conn->base_.inbuf), connection_or_nonopen_was_started_here(conn) ? "to" : "from", conn->base_.address, conn->base_.port, conn_state_to_string(conn->base_.type, conn->base_.state)); connection_or_close_for_error(conn, 0); ret = -1; } return ret; } /** When adding cells to an OR connection's outbuf, keep adding until the * outbuf is at least this long, or we run out of cells. */ #define OR_CONN_HIGHWATER (32*1024) /** Add cells to an OR connection's outbuf whenever the outbuf's data length * drops below this size. */ #define OR_CONN_LOWWATER (16*1024) /** Called whenever we have flushed some data on an or_conn: add more data * from active circuits. */ int connection_or_flushed_some(or_connection_t *conn) { size_t datalen, temp; ssize_t n, flushed; size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids); /* If we're under the low water mark, add cells until we're just over the * high water mark. */ datalen = connection_get_outbuf_len(TO_CONN(conn)); if (datalen < OR_CONN_LOWWATER) { while ((conn->chan) && channel_tls_more_to_flush(conn->chan)) { /* Compute how many more cells we want at most */ n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, cell_network_size); /* Bail out if we don't want any more */ if (n <= 0) break; /* We're still here; try to flush some more cells */ flushed = channel_tls_flush_some_cells(conn->chan, n); /* Bail out if it says it didn't flush anything */ if (flushed <= 0) break; /* How much in the outbuf now? */ temp = connection_get_outbuf_len(TO_CONN(conn)); /* Bail out if we didn't actually increase the outbuf size */ if (temp <= datalen) break; /* Update datalen for the next iteration */ datalen = temp; } } return 0; } /** Connection conn has finished writing and has no bytes left on * its outbuf. * * Otherwise it's in state "open": stop writing and return. * * If conn is broken, mark it for close and return -1, else * return 0. */ int connection_or_finished_flushing(or_connection_t *conn) { tor_assert(conn); assert_connection_ok(TO_CONN(conn),0); switch (conn->base_.state) { case OR_CONN_STATE_PROXY_HANDSHAKING: case OR_CONN_STATE_OPEN: case OR_CONN_STATE_OR_HANDSHAKING_V2: case OR_CONN_STATE_OR_HANDSHAKING_V3: break; default: log_err(LD_BUG,"Called in unexpected state %d.", conn->base_.state); tor_fragile_assert(); return -1; } return 0; } /** Connected handler for OR connections: begin the TLS handshake. */ int connection_or_finished_connecting(or_connection_t *or_conn) { const int proxy_type = or_conn->proxy_type; connection_t *conn; tor_assert(or_conn); conn = TO_CONN(or_conn); tor_assert(conn->state == OR_CONN_STATE_CONNECTING); log_debug(LD_HANDSHAKE,"OR connect() to router at %s:%u finished.", conn->address,conn->port); control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0); if (proxy_type != PROXY_NONE) { /* start proxy handshake */ if (connection_proxy_connect(conn, proxy_type) < 0) { connection_or_close_for_error(or_conn, 0); return -1; } connection_start_reading(conn); connection_or_change_state(or_conn, OR_CONN_STATE_PROXY_HANDSHAKING); return 0; } if (connection_tls_start_handshake(or_conn, 0) < 0) { /* TLS handshaking error of some kind. */ connection_or_close_for_error(or_conn, 0); return -1; } return 0; } /** Called when we're about to finally unlink and free an OR connection: * perform necessary accounting and cleanup */ void connection_or_about_to_close(or_connection_t *or_conn) { time_t now = time(NULL); connection_t *conn = TO_CONN(or_conn); /* Tell the controlling channel we're closed */ if (or_conn->chan) { channel_closed(TLS_CHAN_TO_BASE(or_conn->chan)); or_conn->chan = NULL; } /* Remember why we're closing this connection. */ if (conn->state != OR_CONN_STATE_OPEN) { /* now mark things down as needed */ if (connection_or_nonopen_was_started_here(or_conn)) { const or_options_t *options = get_options(); connection_or_note_state_when_broken(or_conn); rep_hist_note_connect_failed(or_conn->identity_digest, now); entry_guard_register_connect_status(or_conn->identity_digest,0, !options->HTTPSProxy, now); if (conn->state >= OR_CONN_STATE_TLS_HANDSHAKING) { int reason = tls_error_to_orconn_end_reason(or_conn->tls_error); control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED, reason); if (!authdir_mode_tests_reachability(options)) control_event_bootstrap_problem( orconn_end_reason_to_control_string(reason), reason); } } } else if (conn->hold_open_until_flushed) { /* We only set hold_open_until_flushed when we're intentionally * closing a connection. */ rep_hist_note_disconnect(or_conn->identity_digest, now); control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED, tls_error_to_orconn_end_reason(or_conn->tls_error)); } else if (!tor_digest_is_zero(or_conn->identity_digest)) { rep_hist_note_connection_died(or_conn->identity_digest, now); control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED, tls_error_to_orconn_end_reason(or_conn->tls_error)); } } /** Return 1 if identity digest id_digest is known to be a * currently or recently running relay. Otherwise return 0. */ int connection_or_digest_is_known_relay(const char *id_digest) { if (router_get_consensus_status_by_id(id_digest)) return 1; /* It's in the consensus: "yes" */ if (router_get_by_id_digest(id_digest)) return 1; /* Not in the consensus, but we have a descriptor for * it. Probably it was in a recent consensus. "Yes". */ return 0; } /** Set the per-conn read and write limits for conn. If it's a known * relay, we will rely on the global read and write buckets, so give it * per-conn limits that are big enough they'll never matter. But if it's * not a known relay, first check if we set PerConnBwRate/Burst, then * check if the consensus sets them, else default to 'big enough'. * * If reset is true, set the bucket to be full. Otherwise, just * clip the bucket if it happens to be too full. */ static void connection_or_update_token_buckets_helper(or_connection_t *conn, int reset, const or_options_t *options) { int rate, burst; /* per-connection rate limiting params */ if (connection_or_digest_is_known_relay(conn->identity_digest)) { /* It's in the consensus, or we have a descriptor for it meaning it * was probably in a recent consensus. It's a recognized relay: * give it full bandwidth. */ rate = (int)options->BandwidthRate; burst = (int)options->BandwidthBurst; } else { /* Not a recognized relay. Squeeze it down based on the suggested * bandwidth parameters in the consensus, but allow local config * options to override. */ rate = options->PerConnBWRate ? (int)options->PerConnBWRate : networkstatus_get_param(NULL, "perconnbwrate", (int)options->BandwidthRate, 1, INT32_MAX); burst = options->PerConnBWBurst ? (int)options->PerConnBWBurst : networkstatus_get_param(NULL, "perconnbwburst", (int)options->BandwidthBurst, 1, INT32_MAX); } conn->bandwidthrate = rate; conn->bandwidthburst = burst; #ifdef USE_BUFFEREVENTS { const struct timeval *tick = tor_libevent_get_one_tick_timeout(); struct ev_token_bucket_cfg *cfg, *old_cfg; int64_t rate64 = (((int64_t)rate) * options->TokenBucketRefillInterval) / 1000; /* This can't overflow, since TokenBucketRefillInterval <= 1000, * and rate started out less than INT_MAX. */ int rate_per_tick = (int) rate64; cfg = ev_token_bucket_cfg_new(rate_per_tick, burst, rate_per_tick, burst, tick); old_cfg = conn->bucket_cfg; if (conn->base_.bufev) tor_set_bufferevent_rate_limit(conn->base_.bufev, cfg); if (old_cfg) ev_token_bucket_cfg_free(old_cfg); conn->bucket_cfg = cfg; (void) reset; /* No way to do this with libevent yet. */ } #else if (reset) { /* set up the token buckets to be full */ conn->read_bucket = conn->write_bucket = burst; return; } /* If the new token bucket is smaller, take out the extra tokens. * (If it's larger, don't -- the buckets can grow to reach the cap.) */ if (conn->read_bucket > burst) conn->read_bucket = burst; if (conn->write_bucket > burst) conn->write_bucket = burst; #endif } /** Either our set of relays or our per-conn rate limits have changed. * Go through all the OR connections and update their token buckets to make * sure they don't exceed their maximum values. */ void connection_or_update_token_buckets(smartlist_t *conns, const or_options_t *options) { SMARTLIST_FOREACH(conns, connection_t *, conn, { if (connection_speaks_cells(conn)) connection_or_update_token_buckets_helper(TO_OR_CONN(conn), 0, options); }); } /** If we don't necessarily know the router we're connecting to, but we * have an addr/port/id_digest, then fill in as much as we can. Start * by checking to see if this describes a router we know. * started_here is 1 if we are the initiator of conn and * 0 if it's an incoming connection. */ void connection_or_init_conn_from_address(or_connection_t *conn, const tor_addr_t *addr, uint16_t port, const char *id_digest, int started_here) { const node_t *r = node_get_by_id(id_digest); connection_or_set_identity_digest(conn, id_digest); connection_or_update_token_buckets_helper(conn, 1, get_options()); conn->base_.port = port; tor_addr_copy(&conn->base_.addr, addr); tor_addr_copy(&conn->real_addr, addr); if (r) { tor_addr_port_t node_ap; node_get_pref_orport(r, &node_ap); /* XXXX proposal 186 is making this more complex. For now, a conn is canonical when it uses the _preferred_ address. */ if (tor_addr_eq(&conn->base_.addr, &node_ap.addr)) conn->is_canonical = 1; if (!started_here) { /* Override the addr/port, so our log messages will make sense. * This is dangerous, since if we ever try looking up a conn by * its actual addr/port, we won't remember. Careful! */ /* XXXX arma: this is stupid, and it's the reason we need real_addr * to track is_canonical properly. What requires it? */ /* XXXX i believe the reason we did this, originally, is because * we wanted to log what OR a connection was to, and if we logged the * right IP address and port 56244, that wouldn't be as helpful. now we * log the "right" port too, so we know if it's moria1 or moria2. */ tor_addr_copy(&conn->base_.addr, &node_ap.addr); conn->base_.port = node_ap.port; } conn->nickname = tor_strdup(node_get_nickname(r)); tor_free(conn->base_.address); conn->base_.address = tor_dup_addr(&node_ap.addr); } else { const char *n; /* If we're an authoritative directory server, we may know a * nickname for this router. */ n = dirserv_get_nickname_by_digest(id_digest); if (n) { conn->nickname = tor_strdup(n); } else { conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); conn->nickname[0] = '$'; base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, conn->identity_digest, DIGEST_LEN); } tor_free(conn->base_.address); conn->base_.address = tor_dup_addr(addr); } } /** These just pass all the is_bad_for_new_circs manipulation on to * channel_t */ static unsigned int connection_or_is_bad_for_new_circs(or_connection_t *or_conn) { tor_assert(or_conn); if (or_conn->chan) return channel_is_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan)); else return 0; } static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn) { tor_assert(or_conn); if (or_conn->chan) channel_mark_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan)); } /** How old do we let a connection to an OR get before deciding it's * too old for new circuits? */ #define TIME_BEFORE_OR_CONN_IS_TOO_OLD (60*60*24*7) /** Given the head of the linked list for all the or_connections with a given * identity, set elements of that list as is_bad_for_new_circs as * appropriate. Helper for connection_or_set_bad_connections(). * * Specifically, we set the is_bad_for_new_circs flag on: * - all connections if force is true. * - all connections that are too old. * - all open non-canonical connections for which a canonical connection * exists to the same router. * - all open canonical connections for which a 'better' canonical * connection exists to the same router. * - all open non-canonical connections for which a 'better' non-canonical * connection exists to the same router at the same address. * * See channel_is_better() in channel.c for our idea of what makes one OR * connection better than another. */ static void connection_or_group_set_badness(or_connection_t *head, int force) { or_connection_t *or_conn = NULL, *best = NULL; int n_old = 0, n_inprogress = 0, n_canonical = 0, n_other = 0; time_t now = time(NULL); /* Pass 1: expire everything that's old, and see what the status of * everything else is. */ for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { if (or_conn->base_.marked_for_close || connection_or_is_bad_for_new_circs(or_conn)) continue; if (force || or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD < now) { log_info(LD_OR, "Marking OR conn to %s:%d as too old for new circuits " "(fd "TOR_SOCKET_T_FORMAT", %d secs old).", or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, (int)(now - or_conn->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); } if (connection_or_is_bad_for_new_circs(or_conn)) { ++n_old; } else if (or_conn->base_.state != OR_CONN_STATE_OPEN) { ++n_inprogress; } else if (or_conn->is_canonical) { ++n_canonical; } else { ++n_other; } } /* Pass 2: We know how about how good the best connection is. * expire everything that's worse, and find the very best if we can. */ for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { if (or_conn->base_.marked_for_close || connection_or_is_bad_for_new_circs(or_conn)) continue; /* This one doesn't need to be marked bad. */ if (or_conn->base_.state != OR_CONN_STATE_OPEN) continue; /* Don't mark anything bad until we have seen what happens * when the connection finishes. */ if (n_canonical && !or_conn->is_canonical) { /* We have at least one open canonical connection to this router, * and this one is open but not canonical. Mark it bad. */ log_info(LD_OR, "Marking OR conn to %s:%d as unsuitable for new circuits: " "(fd "TOR_SOCKET_T_FORMAT", %d secs old). It is not " "canonical, and we have another connection to that OR that is.", or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, (int)(now - or_conn->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); continue; } if (!best || channel_is_better(now, TLS_CHAN_TO_BASE(or_conn->chan), TLS_CHAN_TO_BASE(best->chan), 0)) { best = or_conn; } } if (!best) return; /* Pass 3: One connection to OR is best. If it's canonical, mark as bad * every other open connection. If it's non-canonical, mark as bad * every other open connection to the same address. * * XXXX This isn't optimal; if we have connections to an OR at multiple * addresses, we'd like to pick the best _for each address_, and mark as * bad every open connection that isn't best for its address. But this * can only occur in cases where the other OR is old (so we have no * canonical connection to it), or where all the connections to the OR are * at noncanonical addresses and we have no good direct connection (which * means we aren't at risk of attaching circuits to it anyway). As * 0.1.2.x dies out, the first case will go away, and the second one is * "mostly harmless", so a fix can wait until somebody is bored. */ for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { if (or_conn->base_.marked_for_close || connection_or_is_bad_for_new_circs(or_conn) || or_conn->base_.state != OR_CONN_STATE_OPEN) continue; if (or_conn != best && channel_is_better(now, TLS_CHAN_TO_BASE(best->chan), TLS_CHAN_TO_BASE(or_conn->chan), 1)) { /* This isn't the best conn, _and_ the best conn is better than it, even when we're being forgiving. */ if (best->is_canonical) { log_info(LD_OR, "Marking OR conn to %s:%d as unsuitable for new circuits: " "(fd "TOR_SOCKET_T_FORMAT", %d secs old). " "We have a better canonical one " "(fd "TOR_SOCKET_T_FORMAT"; %d secs old).", or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, (int)(now - or_conn->base_.timestamp_created), best->base_.s, (int)(now - best->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); } else if (!tor_addr_compare(&or_conn->real_addr, &best->real_addr, CMP_EXACT)) { log_info(LD_OR, "Marking OR conn to %s:%d as unsuitable for new circuits: " "(fd "TOR_SOCKET_T_FORMAT", %d secs old). We have a better " "one with the " "same address (fd "TOR_SOCKET_T_FORMAT"; %d secs old).", or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, (int)(now - or_conn->base_.timestamp_created), best->base_.s, (int)(now - best->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); } } } } /** Go through all the OR connections (or if digest is non-NULL, just * the OR connections with that digest), and set the is_bad_for_new_circs * flag based on the rules in connection_or_group_set_badness() (or just * always set it if force is true). */ void connection_or_set_bad_connections(const char *digest, int force) { if (!orconn_identity_map) return; DIGESTMAP_FOREACH(orconn_identity_map, identity, or_connection_t *, conn) { if (!digest || tor_memeq(digest, conn->identity_digest, DIGEST_LEN)) connection_or_group_set_badness(conn, force); } DIGESTMAP_FOREACH_END; } /** conn is in the 'connecting' state, and it failed to complete * a TCP connection. Send notifications appropriately. * * reason specifies the or_conn_end_reason for the failure; * msg specifies the strerror-style error message. */ void connection_or_connect_failed(or_connection_t *conn, int reason, const char *msg) { control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, reason); if (!authdir_mode_tests_reachability(get_options())) control_event_bootstrap_problem(msg, reason); } /** conn got an error in connection_handle_read_impl() or * connection_handle_write_impl() and is going to die soon. * * reason specifies the or_conn_end_reason for the failure; * msg specifies the strerror-style error message. */ void connection_or_notify_error(or_connection_t *conn, int reason, const char *msg) { channel_t *chan; tor_assert(conn); /* If we're connecting, call connect_failed() too */ if (TO_CONN(conn)->state == OR_CONN_STATE_CONNECTING) connection_or_connect_failed(conn, reason, msg); /* Tell the controlling channel if we have one */ if (conn->chan) { chan = TLS_CHAN_TO_BASE(conn->chan); /* Don't transition if we're already in closing, closed or error */ if (!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR)) { channel_close_for_error(chan); } } /* No need to mark for error because connection.c is about to do that */ } /** Launch a new OR connection to addr:port and expect to * handshake with an OR with identity digest id_digest. Optionally, * pass in a pointer to a channel using this connection. * * If id_digest is me, do nothing. If we're already connected to it, * return that connection. If the connect() is in progress, set the * new conn's state to 'connecting' and return it. If connect() succeeds, * call connection_tls_start_handshake() on it. * * This function is called from router_retry_connections(), for * ORs connecting to ORs, and circuit_establish_circuit(), for * OPs connecting to ORs. * * Return the launched conn, or NULL if it failed. */ or_connection_t * connection_or_connect(const tor_addr_t *_addr, uint16_t port, const char *id_digest, channel_tls_t *chan) { or_connection_t *conn; const or_options_t *options = get_options(); int socket_error = 0; tor_addr_t addr; int r; tor_addr_t proxy_addr; uint16_t proxy_port; int proxy_type; tor_assert(_addr); tor_assert(id_digest); tor_addr_copy(&addr, _addr); if (server_mode(options) && router_digest_is_me(id_digest)) { log_info(LD_PROTOCOL,"Client asked me to connect to myself. Refusing."); return NULL; } conn = or_connection_new(tor_addr_family(&addr)); /* * Set up conn so it's got all the data we need to remember for channels * * This stuff needs to happen before connection_or_init_conn_from_address() * so connection_or_set_identity_digest() and such know where to look to * keep the channel up to date. */ conn->chan = chan; chan->conn = conn; connection_or_init_conn_from_address(conn, &addr, port, id_digest, 1); connection_or_change_state(conn, OR_CONN_STATE_CONNECTING); control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0); conn->is_outgoing = 1; /* If we are using a proxy server, find it and use it. */ r = get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, TO_CONN(conn)); if (r == 0) { conn->proxy_type = proxy_type; if (proxy_type != PROXY_NONE) { tor_addr_copy(&addr, &proxy_addr); port = proxy_port; conn->base_.proxy_state = PROXY_INFANT; } } else { /* get_proxy_addrport() might fail if we have a Bridge line that references a transport, but no ClientTransportPlugin lines defining its transport proxy. If this is the case, let's try to output a useful log message to the user. */ const char *transport_name = find_transport_name_by_bridge_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port); if (transport_name) { log_warn(LD_GENERAL, "We were supposed to connect to bridge '%s' " "using pluggable transport '%s', but we can't find a pluggable " "transport proxy supporting '%s'. This can happen if you " "haven't provided a ClientTransportPlugin line, or if " "your pluggable transport proxy stopped running.", fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port), transport_name, transport_name); } else { log_warn(LD_GENERAL, "Tried to connect to '%s' through a proxy, but " "the proxy address could not be found.", fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port)); } connection_free(TO_CONN(conn)); return NULL; } switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr, port, &socket_error)) { case -1: /* If the connection failed immediately, and we're using * a proxy, our proxy is down. Don't blame the Tor server. */ if (conn->base_.proxy_state == PROXY_INFANT) entry_guard_register_connect_status(conn->identity_digest, 0, 1, time(NULL)); connection_or_connect_failed(conn, errno_to_orconn_end_reason(socket_error), tor_socket_strerror(socket_error)); connection_free(TO_CONN(conn)); return NULL; case 0: connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT); /* writable indicates finish, readable indicates broken link, error indicates broken link on windows */ return conn; /* case 1: fall through */ } if (connection_or_finished_connecting(conn) < 0) { /* already marked for close */ return NULL; } return conn; } /** Mark orconn for close and transition the associated channel, if any, to * the closing state. * * It's safe to call this and connection_or_close_for_error() any time, and * channel layer will treat it as a connection closing for reasons outside * its control, like the remote end closing it. It can also be a local * reason that's specific to connection_t/or_connection_t rather than * the channel mechanism, such as expiration of old connections in * run_connection_housekeeping(). If you want to close a channel_t * from somewhere that logically works in terms of generic channels * rather than connections, use channel_mark_for_close(); see also * the comment on that function in channel.c. */ void connection_or_close_normally(or_connection_t *orconn, int flush) { channel_t *chan = NULL; tor_assert(orconn); if (flush) connection_mark_and_flush_internal(TO_CONN(orconn)); else connection_mark_for_close_internal(TO_CONN(orconn)); if (orconn->chan) { chan = TLS_CHAN_TO_BASE(orconn->chan); /* Don't transition if we're already in closing, closed or error */ if (!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR)) { channel_close_from_lower_layer(chan); } } } /** Mark orconn for close and transition the associated channel, if any, to * the error state. */ void connection_or_close_for_error(or_connection_t *orconn, int flush) { channel_t *chan = NULL; tor_assert(orconn); if (flush) connection_mark_and_flush_internal(TO_CONN(orconn)); else connection_mark_for_close_internal(TO_CONN(orconn)); if (orconn->chan) { chan = TLS_CHAN_TO_BASE(orconn->chan); /* Don't transition if we're already in closing, closed or error */ if (!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR)) { channel_close_for_error(chan); } } } /** Begin the tls handshake with conn. receiving is 0 if * we initiated the connection, else it's 1. * * Assign a new tls object to conn->tls, begin reading on conn, and * pass conn to connection_tls_continue_handshake(). * * Return -1 if conn is broken, else return 0. */ int connection_tls_start_handshake(or_connection_t *conn, int receiving) { channel_listener_t *chan_listener; channel_t *chan; /* Incoming connections will need a new channel passed to the * channel_tls_listener */ if (receiving) { /* It shouldn't already be set */ tor_assert(!(conn->chan)); chan_listener = channel_tls_get_listener(); if (!chan_listener) { chan_listener = channel_tls_start_listener(); command_setup_listener(chan_listener); } chan = channel_tls_handle_incoming(conn); channel_listener_queue_incoming(chan_listener, chan); } connection_or_change_state(conn, OR_CONN_STATE_TLS_HANDSHAKING); tor_assert(!conn->tls); conn->tls = tor_tls_new(conn->base_.s, receiving); if (!conn->tls) { log_warn(LD_BUG,"tor_tls_new failed. Closing."); return -1; } tor_tls_set_logged_address(conn->tls, // XXX client and relay? escaped_safe_str(conn->base_.address)); #ifdef USE_BUFFEREVENTS if (connection_type_uses_bufferevent(TO_CONN(conn))) { const int filtering = get_options()->UseFilteringSSLBufferevents; struct bufferevent *b = tor_tls_init_bufferevent(conn->tls, conn->base_.bufev, conn->base_.s, receiving, filtering); if (!b) { log_warn(LD_BUG,"tor_tls_init_bufferevent failed. Closing."); return -1; } conn->base_.bufev = b; if (conn->bucket_cfg) tor_set_bufferevent_rate_limit(conn->base_.bufev, conn->bucket_cfg); connection_enable_rate_limiting(TO_CONN(conn)); connection_configure_bufferevent_callbacks(TO_CONN(conn)); bufferevent_setcb(b, connection_handle_read_cb, connection_handle_write_cb, connection_or_handle_event_cb,/* overriding this one*/ TO_CONN(conn)); } #endif connection_start_reading(TO_CONN(conn)); log_debug(LD_HANDSHAKE,"starting TLS handshake on fd "TOR_SOCKET_T_FORMAT, conn->base_.s); note_crypto_pk_op(receiving ? TLS_HANDSHAKE_S : TLS_HANDSHAKE_C); IF_HAS_BUFFEREVENT(TO_CONN(conn), { /* ???? */; }) ELSE_IF_NO_BUFFEREVENT { if (connection_tls_continue_handshake(conn) < 0) return -1; } return 0; } /** Block all future attempts to renegotiate on 'conn' */ void connection_or_block_renegotiation(or_connection_t *conn) { tor_tls_t *tls = conn->tls; if (!tls) return; tor_tls_set_renegotiate_callback(tls, NULL, NULL); tor_tls_block_renegotiation(tls); } /** Invoked on the server side from inside tor_tls_read() when the server * gets a successful TLS renegotiation from the client. */ static void connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn) { or_connection_t *conn = _conn; (void)tls; /* Don't invoke this again. */ connection_or_block_renegotiation(conn); if (connection_tls_finish_handshake(conn) < 0) { /* XXXX_TLS double-check that it's ok to do this from inside read. */ /* XXXX_TLS double-check that this verifies certificates. */ connection_or_close_for_error(conn, 0); } } /** Move forward with the tls handshake. If it finishes, hand * conn to connection_tls_finish_handshake(). * * Return -1 if conn is broken, else return 0. */ int connection_tls_continue_handshake(or_connection_t *conn) { int result; check_no_tls_errors(); again: if (conn->base_.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { // log_notice(LD_OR, "Renegotiate with %p", conn->tls); result = tor_tls_renegotiate(conn->tls); // log_notice(LD_OR, "Result: %d", result); } else { tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING); // log_notice(LD_OR, "Continue handshake with %p", conn->tls); result = tor_tls_handshake(conn->tls); // log_notice(LD_OR, "Result: %d", result); } switch (result) { CASE_TOR_TLS_ERROR_ANY: log_info(LD_OR,"tls error [%s]. breaking connection.", tor_tls_err_to_string(result)); return -1; case TOR_TLS_DONE: if (! tor_tls_used_v1_handshake(conn->tls)) { if (!tor_tls_is_server(conn->tls)) { if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { if (tor_tls_received_v3_certificate(conn->tls)) { log_info(LD_OR, "Client got a v3 cert! Moving on to v3 " "handshake with ciphersuite %s", tor_tls_get_ciphersuite_name(conn->tls)); return connection_or_launch_v3_or_handshake(conn); } else { log_debug(LD_OR, "Done with initial SSL handshake (client-side)." " Requesting renegotiation."); connection_or_change_state(conn, OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING); goto again; } } // log_notice(LD_OR,"Done. state was %d.", conn->base_.state); } else { /* v2/v3 handshake, but not a client. */ log_debug(LD_OR, "Done with initial SSL handshake (server-side). " "Expecting renegotiation or VERSIONS cell"); tor_tls_set_renegotiate_callback(conn->tls, connection_or_tls_renegotiated_cb, conn); connection_or_change_state(conn, OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); connection_stop_writing(TO_CONN(conn)); connection_start_reading(TO_CONN(conn)); return 0; } } return connection_tls_finish_handshake(conn); case TOR_TLS_WANTWRITE: connection_start_writing(TO_CONN(conn)); log_debug(LD_OR,"wanted write"); return 0; case TOR_TLS_WANTREAD: /* handshaking conns are *always* reading */ log_debug(LD_OR,"wanted read"); return 0; case TOR_TLS_CLOSE: log_info(LD_OR,"tls closed. breaking connection."); return -1; } return 0; } #ifdef USE_BUFFEREVENTS static void connection_or_handle_event_cb(struct bufferevent *bufev, short event, void *arg) { struct or_connection_t *conn = TO_OR_CONN(arg); /* XXXX cut-and-paste code; should become a function. */ if (event & BEV_EVENT_CONNECTED) { if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { if (tor_tls_finish_handshake(conn->tls) < 0) { log_warn(LD_OR, "Problem finishing handshake"); connection_or_close_for_error(conn, 0); return; } } if (! tor_tls_used_v1_handshake(conn->tls)) { if (!tor_tls_is_server(conn->tls)) { if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { if (tor_tls_received_v3_certificate(conn->tls)) { log_info(LD_OR, "Client got a v3 cert!"); if (connection_or_launch_v3_or_handshake(conn) < 0) connection_or_close_for_error(conn, 0); return; } else { connection_or_change_state(conn, OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING); tor_tls_unblock_renegotiation(conn->tls); if (bufferevent_ssl_renegotiate(conn->base_.bufev)<0) { log_warn(LD_OR, "Start_renegotiating went badly."); connection_or_close_for_error(conn, 0); } tor_tls_unblock_renegotiation(conn->tls); return; /* ???? */ } } } else { const int handshakes = tor_tls_get_num_server_handshakes(conn->tls); if (handshakes == 1) { /* v2 or v3 handshake, as a server. Only got one handshake, so * wait for the next one. */ tor_tls_set_renegotiate_callback(conn->tls, connection_or_tls_renegotiated_cb, conn); connection_or_change_state(conn, OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); } else if (handshakes == 2) { /* v2 handshake, as a server. Two handshakes happened already, * so we treat renegotiation as done. */ connection_or_tls_renegotiated_cb(conn->tls, conn); } else if (handshakes > 2) { log_warn(LD_OR, "More than two handshakes done on connection. " "Closing."); connection_or_close_for_error(conn, 0); } else { log_warn(LD_BUG, "We were unexpectedly told that a connection " "got %d handshakes. Closing.", handshakes); connection_or_close_for_error(conn, 0); } return; } } connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT); if (connection_tls_finish_handshake(conn) < 0) connection_or_close_for_error(conn, 0); /* ???? */ return; } if (event & BEV_EVENT_ERROR) { unsigned long err; while ((err = bufferevent_get_openssl_error(bufev))) { tor_tls_log_one_error(conn->tls, err, LOG_WARN, LD_OR, "handshaking (with bufferevent)"); } } connection_handle_event_cb(bufev, event, arg); } #endif /** Return 1 if we initiated this connection, or 0 if it started * out as an incoming connection. */ int connection_or_nonopen_was_started_here(or_connection_t *conn) { tor_assert(conn->base_.type == CONN_TYPE_OR); if (!conn->tls) return 1; /* it's still in proxy states or something */ if (conn->handshake_state) return conn->handshake_state->started_here; return !tor_tls_is_server(conn->tls); } /** Conn just completed its handshake. Return 0 if all is well, and * return -1 if he is lying, broken, or otherwise something is wrong. * * If we initiated this connection (started_here is true), make sure * the other side sent a correctly formed certificate. If I initiated the * connection, make sure it's the right guy. * * Otherwise (if we _didn't_ initiate this connection), it's okay for * the certificate to be weird or absent. * * If we return 0, and the certificate is as expected, write a hash of the * identity key into digest_rcvd_out, which must have DIGEST_LEN * space in it. * If the certificate is invalid or missing on an incoming connection, * we return 0 and set digest_rcvd_out to DIGEST_LEN NUL bytes. * (If we return -1, the contents of this buffer are undefined.) * * As side effects, * 1) Set conn->circ_id_type according to tor-spec.txt. * 2) If we're an authdirserver and we initiated the connection: drop all * descriptors that claim to be on that IP/port but that aren't * this guy; and note that this guy is reachable. * 3) If this is a bridge and we didn't configure its identity * fingerprint, remember the keyid we just learned. */ static int connection_or_check_valid_tls_handshake(or_connection_t *conn, int started_here, char *digest_rcvd_out) { crypto_pk_t *identity_rcvd=NULL; const or_options_t *options = get_options(); int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; const char *safe_address = started_here ? conn->base_.address : safe_str_client(conn->base_.address); const char *conn_type = started_here ? "outgoing" : "incoming"; int has_cert = 0; check_no_tls_errors(); has_cert = tor_tls_peer_has_cert(conn->tls); if (started_here && !has_cert) { log_info(LD_HANDSHAKE,"Tried connecting to router at %s:%d, but it didn't " "send a cert! Closing.", safe_address, conn->base_.port); return -1; } else if (!has_cert) { log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. " "That's ok."); } check_no_tls_errors(); if (has_cert) { int v = tor_tls_verify(started_here?severity:LOG_INFO, conn->tls, &identity_rcvd); if (started_here && v<0) { log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s:%d: It" " has a cert but it's invalid. Closing.", safe_address, conn->base_.port); return -1; } else if (v<0) { log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert " "chain; ignoring."); } else { log_debug(LD_HANDSHAKE, "The certificate seems to be valid on %s connection " "with %s:%d", conn_type, safe_address, conn->base_.port); } check_no_tls_errors(); } if (identity_rcvd) { crypto_pk_get_digest(identity_rcvd, digest_rcvd_out); } else { memset(digest_rcvd_out, 0, DIGEST_LEN); } tor_assert(conn->chan); channel_set_circid_type(TLS_CHAN_TO_BASE(conn->chan), identity_rcvd, 1); crypto_pk_free(identity_rcvd); if (started_here) return connection_or_client_learned_peer_id(conn, (const uint8_t*)digest_rcvd_out); return 0; } /** Called when we (as a connection initiator) have definitively, * authenticatedly, learned that ID of the Tor instance on the other * side of conn is peer_id. For v1 and v2 handshakes, * this is right after we get a certificate chain in a TLS handshake * or renegotiation. For v3 handshakes, this is right after we get a * certificate chain in a CERTS cell. * * If we want any particular ID before, record the one we got. * * If we wanted an ID, but we didn't get it, log a warning and return -1. * * If we're testing reachability, remember what we learned. * * Return 0 on success, -1 on failure. */ int connection_or_client_learned_peer_id(or_connection_t *conn, const uint8_t *peer_id) { const or_options_t *options = get_options(); int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; if (tor_digest_is_zero(conn->identity_digest)) { connection_or_set_identity_digest(conn, (const char*)peer_id); tor_free(conn->nickname); conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); conn->nickname[0] = '$'; base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, conn->identity_digest, DIGEST_LEN); log_info(LD_HANDSHAKE, "Connected to router %s at %s:%d without knowing " "its key. Hoping for the best.", conn->nickname, conn->base_.address, conn->base_.port); /* if it's a bridge and we didn't know its identity fingerprint, now * we do -- remember it for future attempts. */ learned_router_identity(&conn->base_.addr, conn->base_.port, (const char*)peer_id); } if (tor_memneq(peer_id, conn->identity_digest, DIGEST_LEN)) { /* I was aiming for a particular digest. I didn't get it! */ char seen[HEX_DIGEST_LEN+1]; char expected[HEX_DIGEST_LEN+1]; base16_encode(seen, sizeof(seen), (const char*)peer_id, DIGEST_LEN); base16_encode(expected, sizeof(expected), conn->identity_digest, DIGEST_LEN); log_fn(severity, LD_HANDSHAKE, "Tried connecting to router at %s:%d, but identity key was not " "as expected: wanted %s but got %s.", conn->base_.address, conn->base_.port, expected, seen); entry_guard_register_connect_status(conn->identity_digest, 0, 1, time(NULL)); control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, END_OR_CONN_REASON_OR_IDENTITY); if (!authdir_mode_tests_reachability(options)) control_event_bootstrap_problem( "Unexpected identity in router certificate", END_OR_CONN_REASON_OR_IDENTITY); return -1; } if (authdir_mode_tests_reachability(options)) { dirserv_orconn_tls_done(&conn->base_.addr, conn->base_.port, (const char*)peer_id); } return 0; } /** Return when a client used this, for connection.c, since client_used * is now one of the timestamps of channel_t */ time_t connection_or_client_used(or_connection_t *conn) { tor_assert(conn); if (conn->chan) { return channel_when_last_client(TLS_CHAN_TO_BASE(conn->chan)); } else return 0; } /** The v1/v2 TLS handshake is finished. * * Make sure we are happy with the person we just handshaked with. * * If he initiated the connection, make sure he's not already connected, * then initialize conn from the information in router. * * If all is successful, call circuit_n_conn_done() to handle events * that have been pending on the base_.address), tor_tls_get_ciphersuite_name(conn->tls)); directory_set_dirty(); if (connection_or_check_valid_tls_handshake(conn, started_here, digest_rcvd) < 0) return -1; circuit_build_times_network_is_live(&circ_times); if (tor_tls_used_v1_handshake(conn->tls)) { conn->link_proto = 1; if (!started_here) { connection_or_init_conn_from_address(conn, &conn->base_.addr, conn->base_.port, digest_rcvd, 0); } tor_tls_block_renegotiation(conn->tls); return connection_or_set_state_open(conn); } else { connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2); if (connection_init_or_handshake_state(conn, started_here) < 0) return -1; if (!started_here) { connection_or_init_conn_from_address(conn, &conn->base_.addr, conn->base_.port, digest_rcvd, 0); } return connection_or_send_versions(conn, 0); } } /** * Called as client when initial TLS handshake is done, and we notice * that we got a v3-handshake signalling certificate from the server. * Set up structures, do bookkeeping, and send the versions cell. * Return 0 on success and -1 on failure. */ static int connection_or_launch_v3_or_handshake(or_connection_t *conn) { tor_assert(connection_or_nonopen_was_started_here(conn)); tor_assert(tor_tls_received_v3_certificate(conn->tls)); circuit_build_times_network_is_live(&circ_times); connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V3); if (connection_init_or_handshake_state(conn, 1) < 0) return -1; return connection_or_send_versions(conn, 1); } /** Allocate a new connection handshake state for the connection * conn. Return 0 on success, -1 on failure. */ int connection_init_or_handshake_state(or_connection_t *conn, int started_here) { or_handshake_state_t *s; if (conn->handshake_state) { log_warn(LD_BUG, "Duplicate call to connection_init_or_handshake_state!"); return 0; } s = conn->handshake_state = tor_malloc_zero(sizeof(or_handshake_state_t)); s->started_here = started_here ? 1 : 0; s->digest_sent_data = 1; s->digest_received_data = 1; return 0; } /** Free all storage held by state. */ void or_handshake_state_free(or_handshake_state_t *state) { if (!state) return; crypto_digest_free(state->digest_sent); crypto_digest_free(state->digest_received); tor_cert_free(state->auth_cert); tor_cert_free(state->id_cert); memwipe(state, 0xBE, sizeof(or_handshake_state_t)); tor_free(state); } /** * Remember that cell has been transmitted (if incoming is * false) or received (if incoming is true) during a V3 handshake using * state. * * (We don't record the cell, but we keep a digest of everything sent or * received during the v3 handshake, and the client signs it in an * authenticate cell.) */ void or_handshake_state_record_cell(or_connection_t *conn, or_handshake_state_t *state, const cell_t *cell, int incoming) { size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids); crypto_digest_t *d, **dptr; packed_cell_t packed; if (incoming) { if (!state->digest_received_data) return; } else { if (!state->digest_sent_data) return; } if (!incoming) { log_warn(LD_BUG, "We shouldn't be sending any non-variable-length cells " "while making a handshake digest. But we think we are sending " "one with type %d.", (int)cell->command); } dptr = incoming ? &state->digest_received : &state->digest_sent; if (! *dptr) *dptr = crypto_digest256_new(DIGEST_SHA256); d = *dptr; /* Re-packing like this is a little inefficient, but we don't have to do this very often at all. */ cell_pack(&packed, cell, conn->wide_circ_ids); crypto_digest_add_bytes(d, packed.body, cell_network_size); memwipe(&packed, 0, sizeof(packed)); } /** Remember that a variable-length cell has been transmitted (if * incoming is false) or received (if incoming is true) during a * V3 handshake using state. * * (We don't record the cell, but we keep a digest of everything sent or * received during the v3 handshake, and the client signs it in an * authenticate cell.) */ void or_handshake_state_record_var_cell(or_connection_t *conn, or_handshake_state_t *state, const var_cell_t *cell, int incoming) { crypto_digest_t *d, **dptr; int n; char buf[VAR_CELL_MAX_HEADER_SIZE]; if (incoming) { if (!state->digest_received_data) return; } else { if (!state->digest_sent_data) return; } dptr = incoming ? &state->digest_received : &state->digest_sent; if (! *dptr) *dptr = crypto_digest256_new(DIGEST_SHA256); d = *dptr; n = var_cell_pack_header(cell, buf, conn->wide_circ_ids); crypto_digest_add_bytes(d, buf, n); crypto_digest_add_bytes(d, (const char *)cell->payload, cell->payload_len); memwipe(buf, 0, sizeof(buf)); } /** Set conn's state to OR_CONN_STATE_OPEN, and tell other subsystems * as appropriate. Called when we are done with all TLS and OR handshaking. */ int connection_or_set_state_open(or_connection_t *conn) { connection_or_change_state(conn, OR_CONN_STATE_OPEN); control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED, 0); or_handshake_state_free(conn->handshake_state); conn->handshake_state = NULL; IF_HAS_BUFFEREVENT(TO_CONN(conn), { connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT); }) ELSE_IF_NO_BUFFEREVENT { connection_start_reading(TO_CONN(conn)); } return 0; } /** Pack cell into wire-format, and write it onto conn's outbuf. * For cells that use or affect a circuit, this should only be called by * connection_or_flush_from_first_active_circuit(). */ void connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn) { packed_cell_t networkcell; size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids); tor_assert(cell); tor_assert(conn); cell_pack(&networkcell, cell, conn->wide_circ_ids); connection_write_to_buf(networkcell.body, cell_network_size, TO_CONN(conn)); /* Touch the channel's active timestamp if there is one */ if (conn->chan) channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) or_handshake_state_record_cell(conn, conn->handshake_state, cell, 0); if (cell->command != CELL_PADDING) conn->timestamp_last_added_nonpadding = approx_time(); } /** Pack a variable-length cell into wire-format, and write it onto * conn's outbuf. Right now, this DOES NOT support cells that * affect a circuit. */ void connection_or_write_var_cell_to_buf(const var_cell_t *cell, or_connection_t *conn) { int n; char hdr[VAR_CELL_MAX_HEADER_SIZE]; tor_assert(cell); tor_assert(conn); n = var_cell_pack_header(cell, hdr, conn->wide_circ_ids); connection_write_to_buf(hdr, n, TO_CONN(conn)); connection_write_to_buf((char*)cell->payload, cell->payload_len, TO_CONN(conn)); if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) or_handshake_state_record_var_cell(conn, conn->handshake_state, cell, 0); if (cell->command != CELL_PADDING) conn->timestamp_last_added_nonpadding = approx_time(); /* Touch the channel's active timestamp if there is one */ if (conn->chan) channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); } /** See whether there's a variable-length cell waiting on or_conn's * inbuf. Return values as for fetch_var_cell_from_buf(). */ static int connection_fetch_var_cell_from_buf(or_connection_t *or_conn, var_cell_t **out) { connection_t *conn = TO_CONN(or_conn); IF_HAS_BUFFEREVENT(conn, { struct evbuffer *input = bufferevent_get_input(conn->bufev); return fetch_var_cell_from_evbuffer(input, out, or_conn->link_proto); }) ELSE_IF_NO_BUFFEREVENT { return fetch_var_cell_from_buf(conn->inbuf, out, or_conn->link_proto); } } /** Process cells from conn's inbuf. * * Loop: while inbuf contains a cell, pull it off the inbuf, unpack it, * and hand it to command_process_cell(). * * Always return 0. */ static int connection_or_process_cells_from_inbuf(or_connection_t *conn) { var_cell_t *var_cell; while (1) { log_debug(LD_OR, TOR_SOCKET_T_FORMAT": starting, inbuf_datalen %d " "(%d pending in tls object).", conn->base_.s,(int)connection_get_inbuf_len(TO_CONN(conn)), tor_tls_get_pending_bytes(conn->tls)); if (connection_fetch_var_cell_from_buf(conn, &var_cell)) { if (!var_cell) return 0; /* not yet. */ /* Touch the channel's active timestamp if there is one */ if (conn->chan) channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); circuit_build_times_network_is_live(&circ_times); channel_tls_handle_var_cell(var_cell, conn); var_cell_free(var_cell); } else { const int wide_circ_ids = conn->wide_circ_ids; size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids); char buf[CELL_MAX_NETWORK_SIZE]; cell_t cell; if (connection_get_inbuf_len(TO_CONN(conn)) < cell_network_size) /* whole response available? */ return 0; /* not yet */ /* Touch the channel's active timestamp if there is one */ if (conn->chan) channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); circuit_build_times_network_is_live(&circ_times); connection_fetch_from_buf(buf, cell_network_size, TO_CONN(conn)); /* retrieve cell info from buf (create the host-order struct from the * network-order string) */ cell_unpack(&cell, buf, wide_circ_ids); channel_tls_handle_cell(&cell, conn); } } } /** Array of recognized link protocol versions. */ static const uint16_t or_protocol_versions[] = { 1, 2, 3, 4 }; /** Number of versions in or_protocol_versions. */ static const int n_or_protocol_versions = (int)( sizeof(or_protocol_versions)/sizeof(uint16_t) ); /** Return true iff v is a link protocol version that this Tor * implementation believes it can support. */ int is_or_protocol_version_known(uint16_t v) { int i; for (i = 0; i < n_or_protocol_versions; ++i) { if (or_protocol_versions[i] == v) return 1; } return 0; } /** Send a VERSIONS cell on conn, telling the other host about the * link protocol versions that this Tor can support. * * If v3_plus, this is part of a V3 protocol handshake, so only * allow protocol version v3 or later. If not v3_plus, this is * not part of a v3 protocol handshake, so don't allow protocol v3 or * later. **/ int connection_or_send_versions(or_connection_t *conn, int v3_plus) { var_cell_t *cell; int i; int n_versions = 0; const int min_version = v3_plus ? 3 : 0; const int max_version = v3_plus ? UINT16_MAX : 2; tor_assert(conn->handshake_state && !conn->handshake_state->sent_versions_at); cell = var_cell_new(n_or_protocol_versions * 2); cell->command = CELL_VERSIONS; for (i = 0; i < n_or_protocol_versions; ++i) { uint16_t v = or_protocol_versions[i]; if (v < min_version || v > max_version) continue; set_uint16(cell->payload+(2*n_versions), htons(v)); ++n_versions; } cell->payload_len = n_versions * 2; connection_or_write_var_cell_to_buf(cell, conn); conn->handshake_state->sent_versions_at = time(NULL); var_cell_free(cell); return 0; } /** Send a NETINFO cell on conn, telling the other server what we know * about their address, our address, and the current time. */ int connection_or_send_netinfo(or_connection_t *conn) { cell_t cell; time_t now = time(NULL); const routerinfo_t *me; int len; uint8_t *out; tor_assert(conn->handshake_state); if (conn->handshake_state->sent_netinfo) { log_warn(LD_BUG, "Attempted to send an extra netinfo cell on a connection " "where we already sent one."); return 0; } memset(&cell, 0, sizeof(cell_t)); cell.command = CELL_NETINFO; /* Timestamp, if we're a relay. */ if (public_server_mode(get_options()) || ! conn->is_outgoing) set_uint32(cell.payload, htonl((uint32_t)now)); /* Their address. */ out = cell.payload + 4; /* We use &conn->real_addr below, unless it hasn't yet been set. If it * hasn't yet been set, we know that base_.addr hasn't been tampered with * yet either. */ len = append_address_to_payload(out, !tor_addr_is_null(&conn->real_addr) ? &conn->real_addr : &conn->base_.addr); if (len<0) return -1; out += len; /* My address -- only include it if I'm a public relay, or if I'm a * bridge and this is an incoming connection. If I'm a bridge and this * is an outgoing connection, act like a normal client and omit it. */ if ((public_server_mode(get_options()) || !conn->is_outgoing) && (me = router_get_my_routerinfo())) { tor_addr_t my_addr; *out++ = 1 + !tor_addr_is_null(&me->ipv6_addr); tor_addr_from_ipv4h(&my_addr, me->addr); len = append_address_to_payload(out, &my_addr); if (len < 0) return -1; out += len; if (!tor_addr_is_null(&me->ipv6_addr)) { len = append_address_to_payload(out, &me->ipv6_addr); if (len < 0) return -1; } } else { *out = 0; } conn->handshake_state->digest_sent_data = 0; conn->handshake_state->sent_netinfo = 1; connection_or_write_cell_to_buf(&cell, conn); return 0; } /** Send a CERTS cell on the connection conn. Return 0 on success, -1 * on failure. */ int connection_or_send_certs_cell(or_connection_t *conn) { const tor_cert_t *link_cert = NULL, *id_cert = NULL; const uint8_t *link_encoded = NULL, *id_encoded = NULL; size_t link_len, id_len; var_cell_t *cell; size_t cell_len; ssize_t pos; int server_mode; tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3); if (! conn->handshake_state) return -1; server_mode = ! conn->handshake_state->started_here; if (tor_tls_get_my_certs(server_mode, &link_cert, &id_cert) < 0) return -1; tor_cert_get_der(link_cert, &link_encoded, &link_len); tor_cert_get_der(id_cert, &id_encoded, &id_len); cell_len = 1 /* 1 byte: num certs in cell */ + 2 * ( 1 + 2 ) /* For each cert: 1 byte for type, 2 for length */ + link_len + id_len; cell = var_cell_new(cell_len); cell->command = CELL_CERTS; cell->payload[0] = 2; pos = 1; if (server_mode) cell->payload[pos] = OR_CERT_TYPE_TLS_LINK; /* Link cert */ else cell->payload[pos] = OR_CERT_TYPE_AUTH_1024; /* client authentication */ set_uint16(&cell->payload[pos+1], htons(link_len)); memcpy(&cell->payload[pos+3], link_encoded, link_len); pos += 3 + link_len; cell->payload[pos] = OR_CERT_TYPE_ID_1024; /* ID cert */ set_uint16(&cell->payload[pos+1], htons(id_len)); memcpy(&cell->payload[pos+3], id_encoded, id_len); pos += 3 + id_len; tor_assert(pos == (int)cell_len); /* Otherwise we just smashed the heap */ connection_or_write_var_cell_to_buf(cell, conn); var_cell_free(cell); return 0; } /** Send an AUTH_CHALLENGE cell on the connection conn. Return 0 * on success, -1 on failure. */ int connection_or_send_auth_challenge_cell(or_connection_t *conn) { var_cell_t *cell; uint8_t *cp; uint8_t challenge[OR_AUTH_CHALLENGE_LEN]; tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3); if (! conn->handshake_state) return -1; if (crypto_rand((char*)challenge, OR_AUTH_CHALLENGE_LEN) < 0) return -1; cell = var_cell_new(OR_AUTH_CHALLENGE_LEN + 4); cell->command = CELL_AUTH_CHALLENGE; memcpy(cell->payload, challenge, OR_AUTH_CHALLENGE_LEN); cp = cell->payload + OR_AUTH_CHALLENGE_LEN; set_uint16(cp, htons(1)); /* We recognize one authentication type. */ set_uint16(cp+2, htons(AUTHTYPE_RSA_SHA256_TLSSECRET)); connection_or_write_var_cell_to_buf(cell, conn); var_cell_free(cell); memwipe(challenge, 0, sizeof(challenge)); return 0; } /** Compute the main body of an AUTHENTICATE cell that a client can use * to authenticate itself on a v3 handshake for conn. Write it to the * outlen-byte buffer at out. * * If server is true, only calculate the first * V3_AUTH_FIXED_PART_LEN bytes -- the part of the authenticator that's * determined by the rest of the handshake, and which match the provided value * exactly. * * If server is false and signing_key is NULL, calculate the * first V3_AUTH_BODY_LEN bytes of the authenticator (that is, everything * that should be signed), but don't actually sign it. * * If server is false and signing_key is provided, calculate the * entire authenticator, signed with signing_key. * * Return the length of the cell body on success, and -1 on failure. */ int connection_or_compute_authenticate_cell_body(or_connection_t *conn, uint8_t *out, size_t outlen, crypto_pk_t *signing_key, int server) { uint8_t *ptr; /* assert state is reasonable XXXX */ if (outlen < V3_AUTH_FIXED_PART_LEN || (!server && outlen < V3_AUTH_BODY_LEN)) return -1; ptr = out; /* Type: 8 bytes. */ memcpy(ptr, "AUTH0001", 8); ptr += 8; { const tor_cert_t *id_cert=NULL, *link_cert=NULL; const digests_t *my_digests, *their_digests; const uint8_t *my_id, *their_id, *client_id, *server_id; if (tor_tls_get_my_certs(server, &link_cert, &id_cert)) return -1; my_digests = tor_cert_get_id_digests(id_cert); their_digests = tor_cert_get_id_digests(conn->handshake_state->id_cert); tor_assert(my_digests); tor_assert(their_digests); my_id = (uint8_t*)my_digests->d[DIGEST_SHA256]; their_id = (uint8_t*)their_digests->d[DIGEST_SHA256]; client_id = server ? their_id : my_id; server_id = server ? my_id : their_id; /* Client ID digest: 32 octets. */ memcpy(ptr, client_id, 32); ptr += 32; /* Server ID digest: 32 octets. */ memcpy(ptr, server_id, 32); ptr += 32; } { crypto_digest_t *server_d, *client_d; if (server) { server_d = conn->handshake_state->digest_sent; client_d = conn->handshake_state->digest_received; } else { client_d = conn->handshake_state->digest_sent; server_d = conn->handshake_state->digest_received; } /* Server log digest : 32 octets */ crypto_digest_get_digest(server_d, (char*)ptr, 32); ptr += 32; /* Client log digest : 32 octets */ crypto_digest_get_digest(client_d, (char*)ptr, 32); ptr += 32; } { /* Digest of cert used on TLS link : 32 octets. */ const tor_cert_t *cert = NULL; tor_cert_t *freecert = NULL; if (server) { tor_tls_get_my_certs(1, &cert, NULL); } else { freecert = tor_tls_get_peer_cert(conn->tls); cert = freecert; } if (!cert) return -1; memcpy(ptr, tor_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32); if (freecert) tor_cert_free(freecert); ptr += 32; } /* HMAC of clientrandom and serverrandom using master key : 32 octets */ tor_tls_get_tlssecrets(conn->tls, ptr); ptr += 32; tor_assert(ptr - out == V3_AUTH_FIXED_PART_LEN); if (server) return V3_AUTH_FIXED_PART_LEN; // ptr-out /* 8 octets were reserved for the current time, but we're trying to get out * of the habit of sending time around willynilly. Fortunately, nothing * checks it. That's followed by 16 bytes of nonce. */ crypto_rand((char*)ptr, 24); ptr += 24; tor_assert(ptr - out == V3_AUTH_BODY_LEN); if (!signing_key) return V3_AUTH_BODY_LEN; // ptr - out { int siglen; char d[32]; crypto_digest256(d, (char*)out, ptr-out, DIGEST_SHA256); siglen = crypto_pk_private_sign(signing_key, (char*)ptr, outlen - (ptr-out), d, 32); if (siglen < 0) return -1; ptr += siglen; tor_assert(ptr <= out+outlen); return (int)(ptr - out); } } /** Send an AUTHENTICATE cell on the connection conn. Return 0 on * success, -1 on failure */ int connection_or_send_authenticate_cell(or_connection_t *conn, int authtype) { var_cell_t *cell; crypto_pk_t *pk = tor_tls_get_my_client_auth_key(); int authlen; size_t cell_maxlen; /* XXXX make sure we're actually supposed to send this! */ if (!pk) { log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key"); return -1; } if (authtype != AUTHTYPE_RSA_SHA256_TLSSECRET) { log_warn(LD_BUG, "Tried to send authenticate cell with unknown " "authentication type %d", authtype); return -1; } cell_maxlen = 4 + /* overhead */ V3_AUTH_BODY_LEN + /* Authentication body */ crypto_pk_keysize(pk) + /* Max signature length */ 16 /* add a few extra bytes just in case. */; cell = var_cell_new(cell_maxlen); cell->command = CELL_AUTHENTICATE; set_uint16(cell->payload, htons(AUTHTYPE_RSA_SHA256_TLSSECRET)); /* skip over length ; we don't know that yet. */ authlen = connection_or_compute_authenticate_cell_body(conn, cell->payload+4, cell_maxlen-4, pk, 0 /* not server */); if (authlen < 0) { log_warn(LD_BUG, "Unable to compute authenticate cell!"); var_cell_free(cell); return -1; } tor_assert(authlen + 4 <= cell->payload_len); set_uint16(cell->payload+2, htons(authlen)); cell->payload_len = authlen + 4; connection_or_write_var_cell_to_buf(cell, conn); var_cell_free(cell); return 0; } tor-0.2.4.20/src/or/ntmain.c0000644000175000017500000006075212255745673012355 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define MAIN_PRIVATE #include "or.h" #include "config.h" #include "main.h" #include "ntmain.h" #ifdef HAVE_EVENT2_EVENT_H #include #else #include #endif #include #define GENSRV_SERVICENAME "tor" #define GENSRV_DISPLAYNAME "Tor Win32 Service" #define GENSRV_DESCRIPTION \ "Provides an anonymous Internet communication system" #define GENSRV_USERACCT "NT AUTHORITY\\LocalService" // Cheating: using the pre-defined error codes, tricks Windows into displaying // a semi-related human-readable error message if startup fails as // opposed to simply scaring people with Error: 0xffffffff #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE static SERVICE_STATUS service_status; static SERVICE_STATUS_HANDLE hStatus; /* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This * is a job for arguments, not globals. Alas, some of the functions that * use them use them need to have fixed signatures, so they can be passed * to the NT service functions. */ static char **backup_argv; static int backup_argc; static void nt_service_control(DWORD request); static void nt_service_body(int argc, char **argv); static void nt_service_main(void); static SC_HANDLE nt_service_open_scm(void); static SC_HANDLE nt_service_open(SC_HANDLE hSCManager); static int nt_service_start(SC_HANDLE hService); static int nt_service_stop(SC_HANDLE hService); static int nt_service_install(int argc, char **argv); static int nt_service_remove(void); static int nt_service_cmd_start(void); static int nt_service_cmd_stop(void); /** Struct to hold dynamically loaded NT-service related function pointers. */ struct service_fns { int loaded; /** @{ */ /** Function pointers for Windows API functions related to service * management. These are NULL, or they point to the . They're set by * calling the LOAD macro below. */ BOOL (WINAPI *ChangeServiceConfig2A_fn)( SC_HANDLE hService, DWORD dwInfoLevel, LPVOID lpInfo); BOOL (WINAPI *CloseServiceHandle_fn)( SC_HANDLE hSCObject); BOOL (WINAPI *ControlService_fn)( SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus); SC_HANDLE (WINAPI *CreateServiceA_fn)( SC_HANDLE hSCManager, LPCSTR lpServiceName, LPCSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies, LPCSTR lpServiceStartName, LPCSTR lpPassword); BOOL (WINAPI *DeleteService_fn)( SC_HANDLE hService); SC_HANDLE (WINAPI *OpenSCManagerA_fn)( LPCSTR lpMachineName, LPCSTR lpDatabaseName, DWORD dwDesiredAccess); SC_HANDLE (WINAPI *OpenServiceA_fn)( SC_HANDLE hSCManager, LPCSTR lpServiceName, DWORD dwDesiredAccess); BOOL (WINAPI *QueryServiceStatus_fn)( SC_HANDLE hService, LPSERVICE_STATUS lpServiceStatus); SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpHandlerProc); BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS); BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)( const SERVICE_TABLE_ENTRYA* lpServiceTable); BOOL (WINAPI *StartServiceA_fn)( SC_HANDLE hService, DWORD dwNumServiceArgs, LPCSTR* lpServiceArgVectors); BOOL (WINAPI *LookupAccountNameA_fn)( LPCSTR lpSystemName, LPCSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPTSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse); /** @} */ } service_fns = { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; /** Loads functions used by NT services. Returns on success, or prints a * complaint to stdout and exits on error. */ static void nt_service_loadlibrary(void) { HMODULE library = 0; void *fn; if (service_fns.loaded) return; if (!(library = load_windows_system_library(TEXT("advapi32.dll")))) { log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use " "NT services on Windows 98? That doesn't work."); goto err; } /* Helper macro: try to load a function named f from "library" into * service_functions.f_fn. On failure, log an error message, and goto * err. */ #define LOAD(f) STMT_BEGIN \ if (!(fn = GetProcAddress(library, #f))) { \ log_err(LD_BUG, \ "Couldn't find %s in advapi32.dll! We probably got the " \ "name wrong.", #f); \ goto err; \ } else { \ service_fns.f ## _fn = fn; \ } \ STMT_END LOAD(ChangeServiceConfig2A); LOAD(CloseServiceHandle); LOAD(ControlService); LOAD(CreateServiceA); LOAD(DeleteService); LOAD(OpenSCManagerA); LOAD(OpenServiceA); LOAD(QueryServiceStatus); LOAD(RegisterServiceCtrlHandlerA); LOAD(SetServiceStatus); LOAD(StartServiceCtrlDispatcherA); LOAD(StartServiceA); LOAD(LookupAccountNameA); service_fns.loaded = 1; return; err: printf("Unable to load library support for NT services: exiting.\n"); exit(1); } /** If we're compiled to run as an NT service, and the service wants to * shut down, then change our current status and return 1. Else * return 0. */ int nt_service_is_stopping(void) { /* If we haven't loaded the function pointers, we can't possibly be an NT * service trying to shut down. */ if (!service_fns.loaded) return 0; if (service_status.dwCurrentState == SERVICE_STOP_PENDING) { service_status.dwWin32ExitCode = 0; service_status.dwCurrentState = SERVICE_STOPPED; service_fns.SetServiceStatus_fn(hStatus, &service_status); return 1; } else if (service_status.dwCurrentState == SERVICE_STOPPED) { return 1; } return 0; } /** Set the dwCurrentState field for our service to state. */ void nt_service_set_state(DWORD state) { service_status.dwCurrentState = state; } /** Handles service control requests, such as stopping or starting the * Tor service. */ static void nt_service_control(DWORD request) { static struct timeval exit_now; exit_now.tv_sec = 0; exit_now.tv_usec = 0; nt_service_loadlibrary(); switch (request) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: log_notice(LD_GENERAL, "Got stop/shutdown request; shutting down cleanly."); service_status.dwCurrentState = SERVICE_STOP_PENDING; event_base_loopexit(tor_libevent_get_base(), &exit_now); return; } service_fns.SetServiceStatus_fn(hStatus, &service_status); } /** Called when the service is started via the system's service control * manager. This calls tor_init() and starts the main event loop. If * tor_init() fails, the service will be stopped and exit code set to * NT_SERVICE_ERROR_TORINIT_FAILED. */ static void nt_service_body(int argc, char **argv) { int r; (void) argc; /* unused */ (void) argv; /* unused */ nt_service_loadlibrary(); service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwCurrentState = SERVICE_START_PENDING; service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; service_status.dwWin32ExitCode = 0; service_status.dwServiceSpecificExitCode = 0; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 1000; hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME, (LPHANDLER_FUNCTION) nt_service_control); if (hStatus == 0) { /* Failed to register the service control handler function */ return; } r = tor_init(backup_argc, backup_argv); if (r) { /* Failed to start the Tor service */ r = NT_SERVICE_ERROR_TORINIT_FAILED; service_status.dwCurrentState = SERVICE_STOPPED; service_status.dwWin32ExitCode = r; service_status.dwServiceSpecificExitCode = r; service_fns.SetServiceStatus_fn(hStatus, &service_status); return; } /* Set the service's status to SERVICE_RUNNING and start the main * event loop */ service_status.dwCurrentState = SERVICE_RUNNING; service_fns.SetServiceStatus_fn(hStatus, &service_status); do_main_loop(); tor_cleanup(); } /** Main service entry point. Starts the service control dispatcher and waits * until the service status is set to SERVICE_STOPPED. */ static void nt_service_main(void) { SERVICE_TABLE_ENTRYA table[2]; DWORD result = 0; char *errmsg; nt_service_loadlibrary(); table[0].lpServiceName = (char*)GENSRV_SERVICENAME; table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body; table[1].lpServiceName = NULL; table[1].lpServiceProc = NULL; if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) { result = GetLastError(); errmsg = format_win32_error(result); printf("Service error %d : %s\n", (int) result, errmsg); tor_free(errmsg); if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { if (tor_init(backup_argc, backup_argv) < 0) return; switch (get_options()->command) { case CMD_RUN_TOR: do_main_loop(); break; case CMD_LIST_FINGERPRINT: case CMD_HASH_PASSWORD: case CMD_VERIFY_CONFIG: log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, " "--hash-password, or --verify-config) in NT service."); break; case CMD_RUN_UNITTESTS: default: log_err(LD_CONFIG, "Illegal command number %d: internal error.", get_options()->command); } tor_cleanup(); } } } /** Return a handle to the service control manager on success, or NULL on * failure. */ static SC_HANDLE nt_service_open_scm(void) { SC_HANDLE hSCManager; char *errmsg = NULL; nt_service_loadlibrary(); if ((hSCManager = service_fns.OpenSCManagerA_fn( NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) { errmsg = format_win32_error(GetLastError()); printf("OpenSCManager() failed : %s\n", errmsg); tor_free(errmsg); } return hSCManager; } /** Open a handle to the Tor service using hSCManager. Return NULL * on failure. */ static SC_HANDLE nt_service_open(SC_HANDLE hSCManager) { SC_HANDLE hService; char *errmsg = NULL; nt_service_loadlibrary(); if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME, SERVICE_ALL_ACCESS)) == NULL) { errmsg = format_win32_error(GetLastError()); printf("OpenService() failed : %s\n", errmsg); tor_free(errmsg); } return hService; } /** Start the Tor service. Return 0 if the service is started or was * previously running. Return -1 on error. */ static int nt_service_start(SC_HANDLE hService) { char *errmsg = NULL; nt_service_loadlibrary(); service_fns.QueryServiceStatus_fn(hService, &service_status); if (service_status.dwCurrentState == SERVICE_RUNNING) { printf("Service is already running\n"); return 0; } if (service_fns.StartServiceA_fn(hService, 0, NULL)) { /* Loop until the service has finished attempting to start */ while (service_fns.QueryServiceStatus_fn(hService, &service_status) && (service_status.dwCurrentState == SERVICE_START_PENDING)) { Sleep(500); } /* Check if it started successfully or not */ if (service_status.dwCurrentState == SERVICE_RUNNING) { printf("Service started successfully\n"); return 0; } else { errmsg = format_win32_error(service_status.dwWin32ExitCode); printf("Service failed to start : %s\n", errmsg); tor_free(errmsg); } } else { errmsg = format_win32_error(GetLastError()); printf("StartService() failed : %s\n", errmsg); tor_free(errmsg); } return -1; } /** Stop the Tor service. Return 0 if the service is stopped or was not * previously running. Return -1 on error. */ static int nt_service_stop(SC_HANDLE hService) { /** Wait at most 10 seconds for the service to stop. */ #define MAX_SERVICE_WAIT_TIME 10 int wait_time; char *errmsg = NULL; nt_service_loadlibrary(); service_fns.QueryServiceStatus_fn(hService, &service_status); if (service_status.dwCurrentState == SERVICE_STOPPED) { printf("Service is already stopped\n"); return 0; } if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP, &service_status)) { wait_time = 0; while (service_fns.QueryServiceStatus_fn(hService, &service_status) && (service_status.dwCurrentState != SERVICE_STOPPED) && (wait_time < MAX_SERVICE_WAIT_TIME)) { Sleep(1000); wait_time++; } if (service_status.dwCurrentState == SERVICE_STOPPED) { printf("Service stopped successfully\n"); return 0; } else if (wait_time == MAX_SERVICE_WAIT_TIME) { printf("Service did not stop within %d seconds.\n", wait_time); } else { errmsg = format_win32_error(GetLastError()); printf("QueryServiceStatus() failed : %s\n",errmsg); tor_free(errmsg); } } else { errmsg = format_win32_error(GetLastError()); printf("ControlService() failed : %s\n", errmsg); tor_free(errmsg); } return -1; } /** Build a formatted command line used for the NT service. Return a * pointer to the formatted string on success, or NULL on failure. Set * *using_default_torrc to true if we're going to use the default * location to torrc, or 1 if an option was specified on the command line. */ static char * nt_service_command_line(int *using_default_torrc) { TCHAR tor_exe[MAX_PATH+1]; char tor_exe_ascii[MAX_PATH*2+1]; char *command=NULL, *options=NULL; smartlist_t *sl; int i; *using_default_torrc = 1; /* Get the location of tor.exe */ if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH)) return NULL; /* Get the service arguments */ sl = smartlist_new(); for (i = 1; i < backup_argc; ++i) { if (!strcmp(backup_argv[i], "--options") || !strcmp(backup_argv[i], "-options")) { while (++i < backup_argc) { if (!strcmp(backup_argv[i], "-f")) *using_default_torrc = 0; smartlist_add(sl, backup_argv[i]); } } } if (smartlist_len(sl)) options = smartlist_join_strings(sl,"\" \"",0,NULL); smartlist_free(sl); #ifdef UNICODE wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii)); tor_exe_ascii[sizeof(tor_exe_ascii)-1] = '\0'; #else strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii)); #endif /* Allocate a string for the NT service command line and */ /* Format the service command */ if (options) { tor_asprintf(&command, "\"%s\" --nt-service \"%s\"", tor_exe_ascii, options); } else { /* ! options */ tor_asprintf(&command, "\"%s\" --nt-service", tor_exe_ascii); } tor_free(options); return command; } /** Creates a Tor NT service, set to start on boot. The service will be * started if installation succeeds. Returns 0 on success, or -1 on * failure. */ static int nt_service_install(int argc, char **argv) { /* Notes about developing NT services: * * 1. Don't count on your CWD. If an absolute path is not given, the * fopen() function goes wrong. * 2. The parameters given to the nt_service_body() function differ * from those given to main() function. */ SC_HANDLE hSCManager = NULL; SC_HANDLE hService = NULL; SERVICE_DESCRIPTIONA sdBuff; char *command; char *errmsg; const char *user_acct = NULL; const char *password = ""; int i; OSVERSIONINFOEX info; SID_NAME_USE sidUse; DWORD sidLen = 0, domainLen = 0; int is_win2k_or_worse = 0; int using_default_torrc = 0; nt_service_loadlibrary(); /* Open the service control manager so we can create a new service */ if ((hSCManager = nt_service_open_scm()) == NULL) return -1; /* Build the command line used for the service */ if ((command = nt_service_command_line(&using_default_torrc)) == NULL) { printf("Unable to build service command line.\n"); service_fns.CloseServiceHandle_fn(hSCManager); return -1; } for (i=1; i < argc; ++i) { if (!strcmp(argv[i], "--user") && i+1"); /* Create the Tor service, set to auto-start on boot */ if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME, GENSRV_DISPLAYNAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, command, NULL, NULL, NULL, user_acct, password)) == NULL) { errmsg = format_win32_error(GetLastError()); printf("CreateService() failed : %s\n", errmsg); service_fns.CloseServiceHandle_fn(hSCManager); tor_free(errmsg); tor_free(command); return -1; } printf("Done with CreateService.\n"); /* Set the service's description */ sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION; service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION, &sdBuff); printf("Service installed successfully\n"); /* Start the service initially */ nt_service_start(hService); service_fns.CloseServiceHandle_fn(hService); service_fns.CloseServiceHandle_fn(hSCManager); tor_free(command); return 0; } /** Removes the Tor NT service. Returns 0 if the service was successfully * removed, or -1 on error. */ static int nt_service_remove(void) { SC_HANDLE hSCManager = NULL; SC_HANDLE hService = NULL; char *errmsg; nt_service_loadlibrary(); if ((hSCManager = nt_service_open_scm()) == NULL) return -1; if ((hService = nt_service_open(hSCManager)) == NULL) { service_fns.CloseServiceHandle_fn(hSCManager); return -1; } nt_service_stop(hService); if (service_fns.DeleteService_fn(hService) == FALSE) { errmsg = format_win32_error(GetLastError()); printf("DeleteService() failed : %s\n", errmsg); tor_free(errmsg); service_fns.CloseServiceHandle_fn(hService); service_fns.CloseServiceHandle_fn(hSCManager); return -1; } service_fns.CloseServiceHandle_fn(hService); service_fns.CloseServiceHandle_fn(hSCManager); printf("Service removed successfully\n"); return 0; } /** Starts the Tor service. Returns 0 on success, or -1 on error. */ static int nt_service_cmd_start(void) { SC_HANDLE hSCManager; SC_HANDLE hService; int start; if ((hSCManager = nt_service_open_scm()) == NULL) return -1; if ((hService = nt_service_open(hSCManager)) == NULL) { service_fns.CloseServiceHandle_fn(hSCManager); return -1; } start = nt_service_start(hService); service_fns.CloseServiceHandle_fn(hService); service_fns.CloseServiceHandle_fn(hSCManager); return start; } /** Stops the Tor service. Returns 0 on success, or -1 on error. */ static int nt_service_cmd_stop(void) { SC_HANDLE hSCManager; SC_HANDLE hService; int stop; if ((hSCManager = nt_service_open_scm()) == NULL) return -1; if ((hService = nt_service_open(hSCManager)) == NULL) { service_fns.CloseServiceHandle_fn(hSCManager); return -1; } stop = nt_service_stop(hService); service_fns.CloseServiceHandle_fn(hService); service_fns.CloseServiceHandle_fn(hSCManager); return stop; } int nt_service_parse_options(int argc, char **argv, int *should_exit) { backup_argv = argv; backup_argc = argc; *should_exit = 0; if ((argc >= 3) && (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) { nt_service_loadlibrary(); *should_exit = 1; if (!strcmp(argv[2], "install")) return nt_service_install(argc, argv); if (!strcmp(argv[2], "remove")) return nt_service_remove(); if (!strcmp(argv[2], "start")) return nt_service_cmd_start(); if (!strcmp(argv[2], "stop")) return nt_service_cmd_stop(); printf("Unrecognized service command '%s'\n", argv[2]); return 1; } if (argc >= 2) { if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) { nt_service_loadlibrary(); nt_service_main(); *should_exit = 1; return 0; } // These values have been deprecated since 0.1.1.2-alpha; we've warned // about them since 0.1.2.7-alpha. if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) { nt_service_loadlibrary(); fprintf(stderr, "The %s option is deprecated; use \"--service install\" instead.", argv[1]); *should_exit = 1; return nt_service_install(argc, argv); } if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) { nt_service_loadlibrary(); fprintf(stderr, "The %s option is deprecated; use \"--service remove\" instead.", argv[1]); *should_exit = 1; return nt_service_remove(); } } *should_exit = 0; return 0; } tor-0.2.4.20/src/or/circuitstats.h0000644000175000017500000000560312255745673013607 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file circuitstats.h * \brief Header file for circuitstats.c **/ #ifndef TOR_CIRCUITSTATS_H #define TOR_CIRCUITSTATS_H extern circuit_build_times_t circ_times; int circuit_build_times_disabled(void); int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt); void circuit_build_times_update_state(circuit_build_times_t *cbt, or_state_t *state); int circuit_build_times_parse_state(circuit_build_times_t *cbt, or_state_t *state); void circuit_build_times_count_timeout(circuit_build_times_t *cbt, int did_onehop); int circuit_build_times_count_close(circuit_build_times_t *cbt, int did_onehop, time_t start_time); void circuit_build_times_set_timeout(circuit_build_times_t *cbt); int circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time); int circuit_build_times_needs_circuits(circuit_build_times_t *cbt); int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt); void circuit_build_times_init(circuit_build_times_t *cbt); void circuit_build_times_free_timeouts(circuit_build_times_t *cbt); void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, networkstatus_t *ns); double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt); double circuit_build_times_close_rate(const circuit_build_times_t *cbt); #ifdef CIRCUITSTATS_PRIVATE double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, double quantile); build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt, double q_lo, double q_hi); void circuit_build_times_initial_alpha(circuit_build_times_t *cbt, double quantile, double time_ms); int circuit_build_times_update_alpha(circuit_build_times_t *cbt); double circuit_build_times_cdf(circuit_build_times_t *cbt, double x); void circuitbuild_running_unit_tests(void); void circuit_build_times_reset(circuit_build_times_t *cbt); /* Network liveness functions */ int circuit_build_times_network_check_changed(circuit_build_times_t *cbt); #endif /* Network liveness functions */ void circuit_build_times_network_is_live(circuit_build_times_t *cbt); int circuit_build_times_network_check_live(circuit_build_times_t *cbt); void circuit_build_times_network_circ_success(circuit_build_times_t *cbt); /* DOCDOC circuit_build_times_get_bw_scale */ int circuit_build_times_get_bw_scale(networkstatus_t *ns); #endif tor-0.2.4.20/src/or/circuitlist.c0000644000175000017500000016044112255745673013421 00000000000000/* Copyright 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file circuitlist.c * \brief Manage the global circuit list. **/ #include "or.h" #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuituse.h" #include "circuitstats.h" #include "connection.h" #include "config.h" #include "connection_edge.h" #include "connection_or.h" #include "control.h" #include "networkstatus.h" #include "nodelist.h" #include "onion.h" #include "onion_fast.h" #include "policies.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" #include "rephist.h" #include "routerlist.h" #include "routerset.h" #include "ht.h" /********* START VARIABLES **********/ /** A global list of all circuits at this hop. */ circuit_t *global_circuitlist=NULL; /** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */ static smartlist_t *circuits_pending_chans = NULL; static void circuit_free(circuit_t *circ); static void circuit_free_cpath(crypt_path_t *cpath); static void circuit_free_cpath_node(crypt_path_t *victim); static void cpath_ref_decref(crypt_path_reference_t *cpath_ref); /********* END VARIABLES ************/ /** A map from channel and circuit ID to circuit. (Lookup performance is * very important here, since we need to do it every time a cell arrives.) */ typedef struct chan_circid_circuit_map_t { HT_ENTRY(chan_circid_circuit_map_t) node; channel_t *chan; circid_t circ_id; circuit_t *circuit; } chan_circid_circuit_map_t; /** Helper for hash tables: compare the channel and circuit ID for a and * b, and return less than, equal to, or greater than zero appropriately. */ static INLINE int chan_circid_entries_eq_(chan_circid_circuit_map_t *a, chan_circid_circuit_map_t *b) { return a->chan == b->chan && a->circ_id == b->circ_id; } /** Helper: return a hash based on circuit ID and the pointer value of * chan in a. */ static INLINE unsigned int chan_circid_entry_hash_(chan_circid_circuit_map_t *a) { return ((unsigned)a->circ_id) ^ (unsigned)(uintptr_t)(a->chan); } /** Map from [chan,circid] to circuit. */ static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t) chan_circid_map = HT_INITIALIZER(); HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node, chan_circid_entry_hash_, chan_circid_entries_eq_) HT_GENERATE(chan_circid_map, chan_circid_circuit_map_t, node, chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6, malloc, realloc, free) /** The most recently returned entry from circuit_get_by_circid_chan; * used to improve performance when many cells arrive in a row from the * same circuit. */ chan_circid_circuit_map_t *_last_circid_chan_ent = NULL; /** Implementation helper for circuit_set_{p,n}_circid_channel: A circuit ID * and/or channel for circ has just changed from old_chan, old_id * to chan, id. Adjust the chan,circid map as appropriate, removing * the old entry (if any) and adding a new one. */ static void circuit_set_circid_chan_helper(circuit_t *circ, int direction, circid_t id, channel_t *chan) { chan_circid_circuit_map_t search; chan_circid_circuit_map_t *found; channel_t *old_chan, **chan_ptr; circid_t old_id, *circid_ptr; int make_active, attached = 0; if (direction == CELL_DIRECTION_OUT) { chan_ptr = &circ->n_chan; circid_ptr = &circ->n_circ_id; make_active = circ->n_chan_cells.n > 0; } else { or_circuit_t *c = TO_OR_CIRCUIT(circ); chan_ptr = &c->p_chan; circid_ptr = &c->p_circ_id; make_active = c->p_chan_cells.n > 0; } old_chan = *chan_ptr; old_id = *circid_ptr; if (id == old_id && chan == old_chan) return; if (_last_circid_chan_ent && ((old_id == _last_circid_chan_ent->circ_id && old_chan == _last_circid_chan_ent->chan) || (id == _last_circid_chan_ent->circ_id && chan == _last_circid_chan_ent->chan))) { _last_circid_chan_ent = NULL; } if (old_chan) { /* * If we're changing channels or ID and had an old channel and a non * zero old ID and weren't marked for close (i.e., we should have been * attached), detach the circuit. ID changes require this because * circuitmux hashes on (channel_id, circuit_id). */ if (old_id != 0 && (old_chan != chan || old_id != id) && !(circ->marked_for_close)) { tor_assert(old_chan->cmux); circuitmux_detach_circuit(old_chan->cmux, circ); } /* we may need to remove it from the conn-circid map */ search.circ_id = old_id; search.chan = old_chan; found = HT_REMOVE(chan_circid_map, &chan_circid_map, &search); if (found) { tor_free(found); if (direction == CELL_DIRECTION_OUT) { /* One fewer circuits use old_chan as n_chan */ --(old_chan->num_n_circuits); } else { /* One fewer circuits use old_chan as p_chan */ --(old_chan->num_p_circuits); } } } /* Change the values only after we have possibly made the circuit inactive * on the previous chan. */ *chan_ptr = chan; *circid_ptr = id; if (chan == NULL) return; /* now add the new one to the conn-circid map */ search.circ_id = id; search.chan = chan; found = HT_FIND(chan_circid_map, &chan_circid_map, &search); if (found) { found->circuit = circ; } else { found = tor_malloc_zero(sizeof(chan_circid_circuit_map_t)); found->circ_id = id; found->chan = chan; found->circuit = circ; HT_INSERT(chan_circid_map, &chan_circid_map, found); } /* * Attach to the circuitmux if we're changing channels or IDs and * have a new channel and ID to use and the circuit is not marked for * close. */ if (chan && id != 0 && (old_chan != chan || old_id != id) && !(circ->marked_for_close)) { tor_assert(chan->cmux); circuitmux_attach_circuit(chan->cmux, circ, direction); attached = 1; } /* * This is a no-op if we have no cells, but if we do it marks us active to * the circuitmux */ if (make_active && attached) update_circuit_on_cmux(circ, direction); /* Adjust circuit counts on new channel */ if (direction == CELL_DIRECTION_OUT) { ++chan->num_n_circuits; } else { ++chan->num_p_circuits; } } /** Set the p_conn field of a circuit circ, along * with the corresponding circuit ID, and add the circuit as appropriate * to the (chan,id)-\>circuit map. */ void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id, channel_t *chan) { circuit_set_circid_chan_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN, id, chan); if (chan) tor_assert(bool_eq(circ->p_chan_cells.n, circ->next_active_on_p_chan)); } /** Set the n_conn field of a circuit circ, along * with the corresponding circuit ID, and add the circuit as appropriate * to the (chan,id)-\>circuit map. */ void circuit_set_n_circid_chan(circuit_t *circ, circid_t id, channel_t *chan) { circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan); if (chan) tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan)); } /** Change the state of circ to state, adding it to or removing * it from lists as appropriate. */ void circuit_set_state(circuit_t *circ, uint8_t state) { tor_assert(circ); if (state == circ->state) return; if (!circuits_pending_chans) circuits_pending_chans = smartlist_new(); if (circ->state == CIRCUIT_STATE_CHAN_WAIT) { /* remove from waiting-circuit list. */ smartlist_remove(circuits_pending_chans, circ); } if (state == CIRCUIT_STATE_CHAN_WAIT) { /* add to waiting-circuit list. */ smartlist_add(circuits_pending_chans, circ); } if (state == CIRCUIT_STATE_OPEN) tor_assert(!circ->n_chan_create_cell); circ->state = state; } /** Add circ to the global list of circuits. This is called only from * within circuit_new. */ static void circuit_add(circuit_t *circ) { if (!global_circuitlist) { /* first one */ global_circuitlist = circ; circ->next = NULL; } else { circ->next = global_circuitlist; global_circuitlist = circ; } } /** Append to out all circuits in state CHAN_WAIT waiting for * the given connection. */ void circuit_get_all_pending_on_channel(smartlist_t *out, channel_t *chan) { tor_assert(out); tor_assert(chan); if (!circuits_pending_chans) return; SMARTLIST_FOREACH_BEGIN(circuits_pending_chans, circuit_t *, circ) { if (circ->marked_for_close) continue; if (!circ->n_hop) continue; tor_assert(circ->state == CIRCUIT_STATE_CHAN_WAIT); if (tor_digest_is_zero(circ->n_hop->identity_digest)) { /* Look at addr/port. This is an unkeyed connection. */ if (!channel_matches_extend_info(chan, circ->n_hop)) continue; } else { /* We expected a key. See if it's the right one. */ if (tor_memneq(chan->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) continue; } smartlist_add(out, circ); } SMARTLIST_FOREACH_END(circ); } /** Return the number of circuits in state CHAN_WAIT, waiting for the given * channel. */ int circuit_count_pending_on_channel(channel_t *chan) { int cnt; smartlist_t *sl = smartlist_new(); tor_assert(chan); circuit_get_all_pending_on_channel(sl, chan); cnt = smartlist_len(sl); smartlist_free(sl); log_debug(LD_CIRC,"or_conn to %s at %s, %d pending circs", chan->nickname ? chan->nickname : "NULL", channel_get_canonical_remote_descr(chan), cnt); return cnt; } /** Detach from the global circuit list, and deallocate, all * circuits that have been marked for close. */ void circuit_close_all_marked(void) { circuit_t *tmp,*m; while (global_circuitlist && global_circuitlist->marked_for_close) { tmp = global_circuitlist->next; circuit_free(global_circuitlist); global_circuitlist = tmp; } tmp = global_circuitlist; while (tmp && tmp->next) { if (tmp->next->marked_for_close) { m = tmp->next->next; circuit_free(tmp->next); tmp->next = m; /* Need to check new tmp->next; don't advance tmp. */ } else { /* Advance tmp. */ tmp = tmp->next; } } } /** Return the head of the global linked list of circuits. */ circuit_t * circuit_get_global_list_(void) { return global_circuitlist; } /** Function to make circ-\>state human-readable */ const char * circuit_state_to_string(int state) { static char buf[64]; switch (state) { case CIRCUIT_STATE_BUILDING: return "doing handshakes"; case CIRCUIT_STATE_ONIONSKIN_PENDING: return "processing the onion"; case CIRCUIT_STATE_CHAN_WAIT: return "connecting to server"; case CIRCUIT_STATE_OPEN: return "open"; default: log_warn(LD_BUG, "Unknown circuit state %d", state); tor_snprintf(buf, sizeof(buf), "unknown state [%d]", state); return buf; } } /** Map a circuit purpose to a string suitable to be displayed to a * controller. */ const char * circuit_purpose_to_controller_string(uint8_t purpose) { static char buf[32]; switch (purpose) { case CIRCUIT_PURPOSE_OR: case CIRCUIT_PURPOSE_INTRO_POINT: case CIRCUIT_PURPOSE_REND_POINT_WAITING: case CIRCUIT_PURPOSE_REND_ESTABLISHED: return "SERVER"; /* A controller should never see these, actually. */ case CIRCUIT_PURPOSE_C_GENERAL: return "GENERAL"; case CIRCUIT_PURPOSE_C_INTRODUCING: case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: return "HS_CLIENT_INTRO"; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: case CIRCUIT_PURPOSE_C_REND_READY: case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: case CIRCUIT_PURPOSE_C_REND_JOINED: return "HS_CLIENT_REND"; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: case CIRCUIT_PURPOSE_S_INTRO: return "HS_SERVICE_INTRO"; case CIRCUIT_PURPOSE_S_CONNECT_REND: case CIRCUIT_PURPOSE_S_REND_JOINED: return "HS_SERVICE_REND"; case CIRCUIT_PURPOSE_TESTING: return "TESTING"; case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT: return "MEASURE_TIMEOUT"; case CIRCUIT_PURPOSE_CONTROLLER: return "CONTROLLER"; case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: return "PATH_BIAS_TESTING"; default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); return buf; } } /** Return a string specifying the state of the hidden-service circuit * purpose purpose, or NULL if purpose is not a * hidden-service-related circuit purpose. */ const char * circuit_purpose_to_controller_hs_state_string(uint8_t purpose) { switch (purpose) { default: log_fn(LOG_WARN, LD_BUG, "Unrecognized circuit purpose: %d", (int)purpose); tor_fragile_assert(); /* fall through */ case CIRCUIT_PURPOSE_OR: case CIRCUIT_PURPOSE_C_GENERAL: case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT: case CIRCUIT_PURPOSE_TESTING: case CIRCUIT_PURPOSE_CONTROLLER: case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: return NULL; case CIRCUIT_PURPOSE_INTRO_POINT: return "OR_HSSI_ESTABLISHED"; case CIRCUIT_PURPOSE_REND_POINT_WAITING: return "OR_HSCR_ESTABLISHED"; case CIRCUIT_PURPOSE_REND_ESTABLISHED: return "OR_HS_R_JOINED"; case CIRCUIT_PURPOSE_C_INTRODUCING: return "HSCI_CONNECTING"; case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: return "HSCI_INTRO_SENT"; case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: return "HSCI_DONE"; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: return "HSCR_CONNECTING"; case CIRCUIT_PURPOSE_C_REND_READY: return "HSCR_ESTABLISHED_IDLE"; case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: return "HSCR_ESTABLISHED_WAITING"; case CIRCUIT_PURPOSE_C_REND_JOINED: return "HSCR_JOINED"; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: return "HSSI_CONNECTING"; case CIRCUIT_PURPOSE_S_INTRO: return "HSSI_ESTABLISHED"; case CIRCUIT_PURPOSE_S_CONNECT_REND: return "HSSR_CONNECTING"; case CIRCUIT_PURPOSE_S_REND_JOINED: return "HSSR_JOINED"; } } /** Return a human-readable string for the circuit purpose purpose. */ const char * circuit_purpose_to_string(uint8_t purpose) { static char buf[32]; switch (purpose) { case CIRCUIT_PURPOSE_OR: return "Circuit at relay"; case CIRCUIT_PURPOSE_INTRO_POINT: return "Acting as intro point"; case CIRCUIT_PURPOSE_REND_POINT_WAITING: return "Acting as rendevous (pending)"; case CIRCUIT_PURPOSE_REND_ESTABLISHED: return "Acting as rendevous (established)"; case CIRCUIT_PURPOSE_C_GENERAL: return "General-purpose client"; case CIRCUIT_PURPOSE_C_INTRODUCING: return "Hidden service client: Connecting to intro point"; case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: return "Hidden service client: Waiting for ack from intro point"; case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: return "Hidden service client: Received ack from intro point"; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: return "Hidden service client: Establishing rendezvous point"; case CIRCUIT_PURPOSE_C_REND_READY: return "Hidden service client: Pending rendezvous point"; case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: return "Hidden service client: Pending rendezvous point (ack received)"; case CIRCUIT_PURPOSE_C_REND_JOINED: return "Hidden service client: Active rendezvous point"; case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT: return "Measuring circuit timeout"; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: return "Hidden service: Establishing introduction point"; case CIRCUIT_PURPOSE_S_INTRO: return "Hidden service: Introduction point"; case CIRCUIT_PURPOSE_S_CONNECT_REND: return "Hidden service: Connecting to rendezvous point"; case CIRCUIT_PURPOSE_S_REND_JOINED: return "Hidden service: Active rendezvous point"; case CIRCUIT_PURPOSE_TESTING: return "Testing circuit"; case CIRCUIT_PURPOSE_CONTROLLER: return "Circuit made by controller"; case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: return "Path-bias testing circuit"; default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); return buf; } } /** Pick a reasonable package_window to start out for our circuits. * Originally this was hard-coded at 1000, but now the consensus votes * on the answer. See proposal 168. */ int32_t circuit_initial_package_window(void) { int32_t num = networkstatus_get_param(NULL, "circwindow", CIRCWINDOW_START, CIRCWINDOW_START_MIN, CIRCWINDOW_START_MAX); /* If the consensus tells us a negative number, we'd assert. */ if (num < 0) num = CIRCWINDOW_START; return num; } /** Initialize the common elements in a circuit_t, and add it to the global * list. */ static void init_circuit_base(circuit_t *circ) { tor_gettimeofday(&circ->timestamp_created); // Gets reset when we send CREATE_FAST. // circuit_expire_building() expects these to be equal // until the orconn is built. circ->timestamp_began = circ->timestamp_created; circ->package_window = circuit_initial_package_window(); circ->deliver_window = CIRCWINDOW_START; circuit_add(circ); } /** Allocate space for a new circuit, initializing with p_circ_id * and p_conn. Add it to the global circuit list. */ origin_circuit_t * origin_circuit_new(void) { origin_circuit_t *circ; /* never zero, since a global ID of 0 is treated specially by the * controller */ static uint32_t n_circuits_allocated = 1; circ = tor_malloc_zero(sizeof(origin_circuit_t)); circ->base_.magic = ORIGIN_CIRCUIT_MAGIC; circ->next_stream_id = crypto_rand_int(1<<16); circ->global_identifier = n_circuits_allocated++; circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; circ->remaining_relay_early_cells -= crypto_rand_int(2); init_circuit_base(TO_CIRCUIT(circ)); circ_times.last_circ_at = approx_time(); return circ; } /** Allocate a new or_circuit_t, connected to p_conn as * p_circ_id. If p_conn is NULL, the circuit is unattached. */ or_circuit_t * or_circuit_new(circid_t p_circ_id, channel_t *p_chan) { /* CircIDs */ or_circuit_t *circ; circ = tor_malloc_zero(sizeof(or_circuit_t)); circ->base_.magic = OR_CIRCUIT_MAGIC; if (p_chan) circuit_set_p_circid_chan(circ, p_circ_id, p_chan); circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; init_circuit_base(TO_CIRCUIT(circ)); return circ; } /** Deallocate space associated with circ. */ static void circuit_free(circuit_t *circ) { void *mem; size_t memlen; if (!circ) return; if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); mem = ocirc; memlen = sizeof(origin_circuit_t); tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC); if (ocirc->build_state) { extend_info_free(ocirc->build_state->chosen_exit); circuit_free_cpath_node(ocirc->build_state->pending_final_cpath); cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref); } tor_free(ocirc->build_state); circuit_free_cpath(ocirc->cpath); crypto_pk_free(ocirc->intro_key); rend_data_free(ocirc->rend_data); tor_free(ocirc->dest_address); if (ocirc->socks_username) { memwipe(ocirc->socks_username, 0x12, ocirc->socks_username_len); tor_free(ocirc->socks_username); } if (ocirc->socks_password) { memwipe(ocirc->socks_password, 0x06, ocirc->socks_password_len); tor_free(ocirc->socks_password); } addr_policy_list_free(ocirc->prepend_policy); } else { or_circuit_t *ocirc = TO_OR_CIRCUIT(circ); /* Remember cell statistics for this circuit before deallocating. */ if (get_options()->CellStatistics) rep_hist_buffer_stats_add_circ(circ, time(NULL)); mem = ocirc; memlen = sizeof(or_circuit_t); tor_assert(circ->magic == OR_CIRCUIT_MAGIC); crypto_cipher_free(ocirc->p_crypto); crypto_digest_free(ocirc->p_digest); crypto_cipher_free(ocirc->n_crypto); crypto_digest_free(ocirc->n_digest); if (ocirc->rend_splice) { or_circuit_t *other = ocirc->rend_splice; tor_assert(other->base_.magic == OR_CIRCUIT_MAGIC); other->rend_splice = NULL; } /* remove from map. */ circuit_set_p_circid_chan(ocirc, 0, NULL); /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(ô->p_chan_cells); } extend_info_free(circ->n_hop); tor_free(circ->n_chan_create_cell); /* Remove from map. */ circuit_set_n_circid_chan(circ, 0, NULL); /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(&circ->n_chan_cells); memwipe(mem, 0xAA, memlen); /* poison memory */ tor_free(mem); } /** Deallocate space associated with the linked list cpath. */ static void circuit_free_cpath(crypt_path_t *cpath) { crypt_path_t *victim, *head=cpath; if (!cpath) return; /* it's a doubly linked list, so we have to notice when we've * gone through it once. */ while (cpath->next && cpath->next != head) { victim = cpath; cpath = victim->next; circuit_free_cpath_node(victim); } circuit_free_cpath_node(cpath); } /** Release all storage held by circuits. */ void circuit_free_all(void) { circuit_t *next; while (global_circuitlist) { next = global_circuitlist->next; if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist); while (or_circ->resolving_streams) { edge_connection_t *next_conn; next_conn = or_circ->resolving_streams->next_stream; connection_free(TO_CONN(or_circ->resolving_streams)); or_circ->resolving_streams = next_conn; } } circuit_free(global_circuitlist); global_circuitlist = next; } smartlist_free(circuits_pending_chans); circuits_pending_chans = NULL; HT_CLEAR(chan_circid_map, &chan_circid_map); } /** Deallocate space associated with the cpath node victim. */ static void circuit_free_cpath_node(crypt_path_t *victim) { if (!victim) return; crypto_cipher_free(victim->f_crypto); crypto_cipher_free(victim->b_crypto); crypto_digest_free(victim->f_digest); crypto_digest_free(victim->b_digest); onion_handshake_state_release(&victim->handshake_state); crypto_dh_free(victim->rend_dh_handshake_state); extend_info_free(victim->extend_info); memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */ tor_free(victim); } /** Release a crypt_path_reference_t*, which may be NULL. */ static void cpath_ref_decref(crypt_path_reference_t *cpath_ref) { if (cpath_ref != NULL) { if (--(cpath_ref->refcount) == 0) { circuit_free_cpath_node(cpath_ref->cpath); tor_free(cpath_ref); } } } /** A helper function for circuit_dump_by_conn() below. Log a bunch * of information about circuit circ. */ static void circuit_dump_conn_details(int severity, circuit_t *circ, int conn_array_index, const char *type, circid_t this_circid, circid_t other_circid) { tor_log(severity, LD_CIRC, "Conn %d has %s circuit: circID %u " "(other side %u), state %d (%s), born %ld:", conn_array_index, type, (unsigned)this_circid, (unsigned)other_circid, circ->state, circuit_state_to_string(circ->state), (long)circ->timestamp_began.tv_sec); if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ)); } } /** Log, at severity severity, information about each circuit * that is connected to conn. */ void circuit_dump_by_conn(connection_t *conn, int severity) { circuit_t *circ; edge_connection_t *tmpconn; for (circ = global_circuitlist; circ; circ = circ->next) { circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0; if (circ->marked_for_close) { continue; } if (!CIRCUIT_IS_ORIGIN(circ)) { p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; } if (CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (TO_CONN(tmpconn) == conn) { circuit_dump_conn_details(severity, circ, conn->conn_array_index, "App-ward", p_circ_id, n_circ_id); } } } if (! CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (TO_CONN(tmpconn) == conn) { circuit_dump_conn_details(severity, circ, conn->conn_array_index, "Exit-ward", n_circ_id, p_circ_id); } } } } } /** A helper function for circuit_dump_by_chan() below. Log a bunch * of information about circuit circ. */ static void circuit_dump_chan_details(int severity, circuit_t *circ, channel_t *chan, const char *type, circid_t this_circid, circid_t other_circid) { tor_log(severity, LD_CIRC, "Conn %p has %s circuit: circID %u " "(other side %u), state %d (%s), born %ld:", chan, type, (unsigned)this_circid, (unsigned)other_circid, circ->state, circuit_state_to_string(circ->state), (long)circ->timestamp_began.tv_sec); if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ)); } } /** Log, at severity severity, information about each circuit * that is connected to chan. */ void circuit_dump_by_chan(channel_t *chan, int severity) { circuit_t *circ; tor_assert(chan); for (circ = global_circuitlist; circ; circ = circ->next) { circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0; if (circ->marked_for_close) { continue; } if (!CIRCUIT_IS_ORIGIN(circ)) { p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; } if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_chan && TO_OR_CIRCUIT(circ)->p_chan == chan) { circuit_dump_chan_details(severity, circ, chan, "App-ward", p_circ_id, n_circ_id); } if (circ->n_chan && circ->n_chan == chan) { circuit_dump_chan_details(severity, circ, chan, "Exit-ward", n_circ_id, p_circ_id); } if (!circ->n_chan && circ->n_hop && channel_matches_extend_info(chan, circ->n_hop) && tor_memeq(chan->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) { circuit_dump_chan_details(severity, circ, chan, (circ->state == CIRCUIT_STATE_OPEN && !CIRCUIT_IS_ORIGIN(circ)) ? "Endpoint" : "Pending", n_circ_id, p_circ_id); } } } /** Return the circuit whose global ID is id, or NULL if no * such circuit exists. */ origin_circuit_t * circuit_get_by_global_id(uint32_t id) { circuit_t *circ; for (circ=global_circuitlist;circ;circ = circ->next) { if (CIRCUIT_IS_ORIGIN(circ) && TO_ORIGIN_CIRCUIT(circ)->global_identifier == id) { if (circ->marked_for_close) return NULL; else return TO_ORIGIN_CIRCUIT(circ); } } return NULL; } /** Return a circ such that: * - circ-\>n_circ_id or circ-\>p_circ_id is equal to circ_id, and * - circ is attached to chan, either as p_chan or n_chan. * Return NULL if no such circuit exists. */ static INLINE circuit_t * circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan) { chan_circid_circuit_map_t search; chan_circid_circuit_map_t *found; if (_last_circid_chan_ent && circ_id == _last_circid_chan_ent->circ_id && chan == _last_circid_chan_ent->chan) { found = _last_circid_chan_ent; } else { search.circ_id = circ_id; search.chan = chan; found = HT_FIND(chan_circid_map, &chan_circid_map, &search); _last_circid_chan_ent = found; } if (found && found->circuit) { log_debug(LD_CIRC, "circuit_get_by_circid_channel_impl() returning circuit %p for" " circ_id %u, channel ID " U64_FORMAT " (%p)", found->circuit, (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier), chan); return found->circuit; } log_debug(LD_CIRC, "circuit_get_by_circid_channel_impl() found nothing for" " circ_id %u, channel ID " U64_FORMAT " (%p)", (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier), chan); return NULL; /* The rest of this checks for bugs. Disabled by default. */ /* We comment it out because coverity complains otherwise. { circuit_t *circ; for (circ=global_circuitlist;circ;circ = circ->next) { if (! CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); if (or_circ->p_chan == chan && or_circ->p_circ_id == circ_id) { log_warn(LD_BUG, "circuit matches p_chan, but not in hash table (Bug!)"); return circ; } } if (circ->n_chan == chan && circ->n_circ_id == circ_id) { log_warn(LD_BUG, "circuit matches n_chan, but not in hash table (Bug!)"); return circ; } } return NULL; } */ } /** Return a circ such that: * - circ-\>n_circ_id or circ-\>p_circ_id is equal to circ_id, and * - circ is attached to chan, either as p_chan or n_chan. * - circ is not marked for close. * Return NULL if no such circuit exists. */ circuit_t * circuit_get_by_circid_channel(circid_t circ_id, channel_t *chan) { circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan); if (!circ || circ->marked_for_close) return NULL; else return circ; } /** Return a circ such that: * - circ-\>n_circ_id or circ-\>p_circ_id is equal to circ_id, and * - circ is attached to chan, either as p_chan or n_chan. * Return NULL if no such circuit exists. */ circuit_t * circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, channel_t *chan) { return circuit_get_by_circid_channel_impl(circ_id, chan); } /** Return true iff the circuit ID circ_id is currently used by a * circuit, marked or not, on chan. */ int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan) { return circuit_get_by_circid_channel_impl(circ_id, chan) != NULL; } /** Return the circuit that a given edge connection is using. */ circuit_t * circuit_get_by_edge_conn(edge_connection_t *conn) { circuit_t *circ; circ = conn->on_circuit; tor_assert(!circ || (CIRCUIT_IS_ORIGIN(circ) ? circ->magic == ORIGIN_CIRCUIT_MAGIC : circ->magic == OR_CIRCUIT_MAGIC)); return circ; } /** For each circuit that has chan as n_chan or p_chan, unlink the * circuit from the chan,circid map, and mark it for close if it hasn't * been marked already. */ void circuit_unlink_all_from_channel(channel_t *chan, int reason) { circuit_t *circ; channel_unlink_all_circuits(chan); for (circ = global_circuitlist; circ; circ = circ->next) { int mark = 0; if (circ->n_chan == chan) { circuit_set_n_circid_chan(circ, 0, NULL); mark = 1; /* If we didn't request this closure, pass the remote * bit to mark_for_close. */ if (chan->reason_for_closing != CHANNEL_CLOSE_REQUESTED) reason |= END_CIRC_REASON_FLAG_REMOTE; } if (! CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); if (or_circ->p_chan == chan) { circuit_set_p_circid_chan(or_circ, 0, NULL); mark = 1; } } if (mark && !circ->marked_for_close) circuit_mark_for_close(circ, reason); } } /** Return a circ such that * - circ-\>rend_data-\>onion_address is equal to * rend_data-\>onion_address, * - circ-\>rend_data-\>rend_cookie is equal to * rend_data-\>rend_cookie, and * - circ-\>purpose is equal to CIRCUIT_PURPOSE_C_REND_READY. * * Return NULL if no such circuit exists. */ origin_circuit_t * circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data) { circuit_t *circ; for (circ = global_circuitlist; circ; circ = circ->next) { if (!circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (ocirc->rend_data && !rend_cmp_service_ids(rend_data->onion_address, ocirc->rend_data->onion_address) && tor_memeq(ocirc->rend_data->rend_cookie, rend_data->rend_cookie, REND_COOKIE_LEN)) return ocirc; } } return NULL; } /** Return the first circuit originating here in global_circuitlist after * start whose purpose is purpose, and where * digest (if set) matches the rend_pk_digest field. Return NULL if no * circuit is found. If start is NULL, begin at the start of the list. */ origin_circuit_t * circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, const char *digest, uint8_t purpose) { circuit_t *circ; tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(purpose)); if (start == NULL) circ = global_circuitlist; else circ = TO_CIRCUIT(start)->next; for ( ; circ; circ = circ->next) { if (circ->marked_for_close) continue; if (circ->purpose != purpose) continue; if (!digest) return TO_ORIGIN_CIRCUIT(circ); else if (TO_ORIGIN_CIRCUIT(circ)->rend_data && tor_memeq(TO_ORIGIN_CIRCUIT(circ)->rend_data->rend_pk_digest, digest, DIGEST_LEN)) return TO_ORIGIN_CIRCUIT(circ); } return NULL; } /** Return the first OR circuit in the global list whose purpose is * purpose, and whose rend_token is the len-byte * token. */ static or_circuit_t * circuit_get_by_rend_token_and_purpose(uint8_t purpose, const char *token, size_t len) { circuit_t *circ; for (circ = global_circuitlist; circ; circ = circ->next) { if (! circ->marked_for_close && circ->purpose == purpose && tor_memeq(TO_OR_CIRCUIT(circ)->rend_token, token, len)) return TO_OR_CIRCUIT(circ); } return NULL; } /** Return the circuit waiting for a rendezvous with the provided cookie. * Return NULL if no such circuit is found. */ or_circuit_t * circuit_get_rendezvous(const char *cookie) { return circuit_get_by_rend_token_and_purpose( CIRCUIT_PURPOSE_REND_POINT_WAITING, cookie, REND_COOKIE_LEN); } /** Return the circuit waiting for intro cells of the given digest. * Return NULL if no such circuit is found. */ or_circuit_t * circuit_get_intro_point(const char *digest) { return circuit_get_by_rend_token_and_purpose( CIRCUIT_PURPOSE_INTRO_POINT, digest, DIGEST_LEN); } /** Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL, * has a timestamp_dirty value of 0, has flags matching the CIRCLAUNCH_* * flags in flags, and if info is defined, does not already use info * as any of its hops; or NULL if no circuit fits this description. * * The purpose argument (currently ignored) refers to the purpose of * the circuit we want to create, not the purpose of the circuit we want to * cannibalize. * * If !CIRCLAUNCH_NEED_UPTIME, prefer returning non-uptime circuits. */ origin_circuit_t * circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags) { circuit_t *circ_; origin_circuit_t *best=NULL; int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0; int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0; int internal = (flags & CIRCLAUNCH_IS_INTERNAL) != 0; const or_options_t *options = get_options(); /* Make sure we're not trying to create a onehop circ by * cannibalization. */ tor_assert(!(flags & CIRCLAUNCH_ONEHOP_TUNNEL)); log_debug(LD_CIRC, "Hunting for a circ to cannibalize: purpose %d, uptime %d, " "capacity %d, internal %d", purpose, need_uptime, need_capacity, internal); for (circ_=global_circuitlist; circ_; circ_ = circ_->next) { if (CIRCUIT_IS_ORIGIN(circ_) && circ_->state == CIRCUIT_STATE_OPEN && !circ_->marked_for_close && circ_->purpose == CIRCUIT_PURPOSE_C_GENERAL && !circ_->timestamp_dirty) { origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(circ_); if ((!need_uptime || circ->build_state->need_uptime) && (!need_capacity || circ->build_state->need_capacity) && (internal == circ->build_state->is_internal) && !circ->unusable_for_new_conns && circ->remaining_relay_early_cells && circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN && !circ->build_state->onehop_tunnel && !circ->isolation_values_set) { if (info) { /* need to make sure we don't duplicate hops */ crypt_path_t *hop = circ->cpath; const node_t *ri1 = node_get_by_id(info->identity_digest); do { const node_t *ri2; if (tor_memeq(hop->extend_info->identity_digest, info->identity_digest, DIGEST_LEN)) goto next; if (ri1 && (ri2 = node_get_by_id(hop->extend_info->identity_digest)) && nodes_in_same_family(ri1, ri2)) goto next; hop=hop->next; } while (hop!=circ->cpath); } if (options->ExcludeNodes) { /* Make sure no existing nodes in the circuit are excluded for * general use. (This may be possible if StrictNodes is 0, and we * thought we needed to use an otherwise excluded node for, say, a * directory operation.) */ crypt_path_t *hop = circ->cpath; do { if (routerset_contains_extendinfo(options->ExcludeNodes, hop->extend_info)) goto next; hop = hop->next; } while (hop != circ->cpath); } if (!best || (best->build_state->need_uptime && !need_uptime)) best = circ; next: ; } } } return best; } /** Return the number of hops in circuit's path. */ int circuit_get_cpath_len(origin_circuit_t *circ) { int n = 0; if (circ && circ->cpath) { crypt_path_t *cpath, *cpath_next = NULL; for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) { cpath_next = cpath->next; ++n; } } return n; } /** Return the hopnumth hop in circ->cpath, or NULL if there * aren't that many hops in the list. */ crypt_path_t * circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum) { if (circ && circ->cpath && hopnum > 0) { crypt_path_t *cpath, *cpath_next = NULL; for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) { cpath_next = cpath->next; if (--hopnum <= 0) return cpath; } } return NULL; } /** Go through the circuitlist; mark-for-close each circuit that starts * at us but has not yet been used. */ void circuit_mark_all_unused_circs(void) { circuit_t *circ; for (circ=global_circuitlist; circ; circ = circ->next) { if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && !circ->timestamp_dirty) circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } } /** Go through the circuitlist; for each circuit that starts at us * and is dirty, frob its timestamp_dirty so we won't use it for any * new streams. * * This is useful for letting the user change pseudonyms, so new * streams will not be linkable to old streams. */ void circuit_mark_all_dirty_circs_as_unusable(void) { circuit_t *circ; for (circ=global_circuitlist; circ; circ = circ->next) { if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && circ->timestamp_dirty) { mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ)); } } } /** Mark circ to be closed next time we call * circuit_close_all_marked(). Do any cleanup needed: * - If state is onionskin_pending, remove circ from the onion_pending * list. * - If circ isn't open yet: call circuit_build_failed() if we're * the origin, and in either case call circuit_rep_hist_note_result() * to note stats. * - If purpose is C_INTRODUCE_ACK_WAIT, report the intro point * failure we just had to the hidden service client module. * - If purpose is C_INTRODUCING and reason isn't TIMEOUT, * report to the hidden service client module that the intro point * we just tried may be unreachable. * - Send appropriate destroys and edge_destroys for conns and * streams attached to circ. * - If circ->rend_splice is set (we are the midpoint of a joined * rendezvous stream), then mark the other circuit to close as well. */ void circuit_mark_for_close_(circuit_t *circ, int reason, int line, const char *file) { int orig_reason = reason; /* Passed to the controller */ assert_circuit_ok(circ); tor_assert(line); tor_assert(file); if (circ->marked_for_close) { log_warn(LD_BUG, "Duplicate call to circuit_mark_for_close at %s:%d" " (first at %s:%d)", file, line, circ->marked_for_close_file, circ->marked_for_close); return; } if (reason == END_CIRC_AT_ORIGIN) { if (!CIRCUIT_IS_ORIGIN(circ)) { log_warn(LD_BUG, "Specified 'at-origin' non-reason for ending circuit, " "but circuit was not at origin. (called %s:%d, purpose=%d)", file, line, circ->purpose); } reason = END_CIRC_REASON_NONE; } if (CIRCUIT_IS_ORIGIN(circ)) { if (pathbias_check_close(TO_ORIGIN_CIRCUIT(circ), reason) == -1) { /* Don't close it yet, we need to test it first */ return; } /* We don't send reasons when closing circuits at the origin. */ reason = END_CIRC_REASON_NONE; } if (reason & END_CIRC_REASON_FLAG_REMOTE) reason &= ~END_CIRC_REASON_FLAG_REMOTE; if (reason < END_CIRC_REASON_MIN_ || reason > END_CIRC_REASON_MAX_) { if (!(orig_reason & END_CIRC_REASON_FLAG_REMOTE)) log_warn(LD_BUG, "Reason %d out of range at %s:%d", reason, file, line); reason = END_CIRC_REASON_NONE; } if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) { onion_pending_remove(TO_OR_CIRCUIT(circ)); } /* If the circuit ever became OPEN, we sent it to the reputation history * module then. If it isn't OPEN, we send it there now to remember which * links worked and which didn't. */ if (circ->state != CIRCUIT_STATE_OPEN) { if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); circuit_build_failed(ocirc); /* take actions if necessary */ circuit_rep_hist_note_result(ocirc); } } if (circ->state == CIRCUIT_STATE_CHAN_WAIT) { if (circuits_pending_chans) smartlist_remove(circuits_pending_chans, circ); } if (CIRCUIT_IS_ORIGIN(circ)) { control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ), (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED, orig_reason); } if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); int timed_out = (reason == END_CIRC_REASON_TIMEOUT); tor_assert(circ->state == CIRCUIT_STATE_OPEN); tor_assert(ocirc->build_state->chosen_exit); tor_assert(ocirc->rend_data); /* treat this like getting a nack from it */ log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s", safe_str_client(ocirc->rend_data->onion_address), safe_str_client(build_state_get_exit_nickname(ocirc->build_state)), timed_out ? "Recording timeout." : "Removing from descriptor."); rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, ocirc->rend_data, timed_out ? INTRO_POINT_FAILURE_TIMEOUT : INTRO_POINT_FAILURE_GENERIC); } else if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING && reason != END_CIRC_REASON_TIMEOUT) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); if (ocirc->build_state->chosen_exit && ocirc->rend_data) { log_info(LD_REND, "Failed intro circ %s to %s " "(building circuit to intro point). " "Marking intro point as possibly unreachable.", safe_str_client(ocirc->rend_data->onion_address), safe_str_client(build_state_get_exit_nickname(ocirc->build_state))); rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, ocirc->rend_data, INTRO_POINT_FAILURE_UNREACHABLE); } } if (circ->n_chan) { circuit_clear_cell_queue(circ, circ->n_chan); /* Only send destroy if the channel isn't closing anyway */ if (!(circ->n_chan->state == CHANNEL_STATE_CLOSING || circ->n_chan->state == CHANNEL_STATE_CLOSED || circ->n_chan->state == CHANNEL_STATE_ERROR)) { channel_send_destroy(circ->n_circ_id, circ->n_chan, reason); } circuitmux_detach_circuit(circ->n_chan->cmux, circ); } if (! CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); edge_connection_t *conn; for (conn=or_circ->n_streams; conn; conn=conn->next_stream) connection_edge_destroy(or_circ->p_circ_id, conn); or_circ->n_streams = NULL; while (or_circ->resolving_streams) { conn = or_circ->resolving_streams; or_circ->resolving_streams = conn->next_stream; if (!conn->base_.marked_for_close) { /* The client will see a DESTROY, and infer that the connections * are closing because the circuit is getting torn down. No need * to send an end cell. */ conn->edge_has_sent_end = 1; conn->end_reason = END_STREAM_REASON_DESTROY; conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED; connection_mark_for_close(TO_CONN(conn)); } conn->on_circuit = NULL; } if (or_circ->p_chan) { circuit_clear_cell_queue(circ, or_circ->p_chan); /* Only send destroy if the channel isn't closing anyway */ if (!(or_circ->p_chan->state == CHANNEL_STATE_CLOSING || or_circ->p_chan->state == CHANNEL_STATE_CLOSED || or_circ->p_chan->state == CHANNEL_STATE_ERROR)) { channel_send_destroy(or_circ->p_circ_id, or_circ->p_chan, reason); } circuitmux_detach_circuit(or_circ->p_chan->cmux, circ); } } else { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); edge_connection_t *conn; for (conn=ocirc->p_streams; conn; conn=conn->next_stream) connection_edge_destroy(circ->n_circ_id, conn); ocirc->p_streams = NULL; } circ->marked_for_close = line; circ->marked_for_close_file = file; if (!CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); if (or_circ->rend_splice) { if (!or_circ->rend_splice->base_.marked_for_close) { /* do this after marking this circuit, to avoid infinite recursion. */ circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason); } or_circ->rend_splice = NULL; } } } /** Given a marked circuit circ, aggressively free its cell queues to * recover memory. */ static void marked_circuit_free_cells(circuit_t *circ) { if (!circ->marked_for_close) { log_warn(LD_BUG, "Called on non-marked circuit"); return; } cell_queue_clear(&circ->n_chan_cells); if (! CIRCUIT_IS_ORIGIN(circ)) cell_queue_clear(& TO_OR_CIRCUIT(circ)->p_chan_cells); } /** Return the number of cells used by the circuit c's cell queues. */ static size_t n_cells_in_circ_queues(const circuit_t *c) { size_t n = c->n_chan_cells.n; if (! CIRCUIT_IS_ORIGIN(c)) { circuit_t *cc = (circuit_t *) c; n += TO_OR_CIRCUIT(cc)->p_chan_cells.n; } return n; } /** * Return the age of the oldest cell queued on c, in milliseconds. * Return 0 if there are no cells queued on c. Requires that now be * the current time in milliseconds since the epoch, truncated. * * This function will return incorrect results if the oldest cell queued on * the circuit is older than 2**32 msec (about 49 days) old. */ static uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now) { uint32_t age = 0; if (c->n_chan_cells.head) age = now - c->n_chan_cells.head->inserted_time; if (! CIRCUIT_IS_ORIGIN(c)) { const or_circuit_t *orcirc = TO_OR_CIRCUIT((circuit_t*)c); if (orcirc->p_chan_cells.head) { uint32_t age2 = now - orcirc->p_chan_cells.head->inserted_time; if (age2 > age) return age2; } } return age; } /** Temporary variable for circuits_compare_by_oldest_queued_cell_ This is a * kludge to work around the fact that qsort doesn't provide a way for * comparison functions to take an extra argument. */ static uint32_t circcomp_now_tmp; /** Helper to sort a list of circuit_t by age of oldest cell, in descending * order. Requires that circcomp_now_tmp is set correctly. */ static int circuits_compare_by_oldest_queued_cell_(const void **a_, const void **b_) { const circuit_t *a = *a_; const circuit_t *b = *b_; uint32_t age_a = circuit_max_queued_cell_age(a, circcomp_now_tmp); uint32_t age_b = circuit_max_queued_cell_age(b, circcomp_now_tmp); if (age_a < age_b) return 1; else if (age_a == age_b) return 0; else return -1; } #define FRACTION_OF_CELLS_TO_RETAIN_ON_OOM 0.90 /** We're out of memory for cells, having allocated current_allocation * bytes' worth. Kill the 'worst' circuits until we're under * FRACTION_OF_CIRCS_TO_RETAIN_ON_OOM of our maximum usage. */ void circuits_handle_oom(size_t current_allocation) { /* Let's hope there's enough slack space for this allocation here... */ smartlist_t *circlist = smartlist_new(); circuit_t *circ; size_t n_cells_removed=0, n_cells_to_remove; int n_circuits_killed=0; struct timeval now; log_notice(LD_GENERAL, "We're low on memory. Killing circuits with " "over-long queues. (This behavior is controlled by " "MaxMemInCellQueues.)"); { size_t mem_target = (size_t)(get_options()->MaxMemInCellQueues * FRACTION_OF_CELLS_TO_RETAIN_ON_OOM); size_t mem_to_recover; if (current_allocation <= mem_target) return; mem_to_recover = current_allocation - mem_target; n_cells_to_remove = CEIL_DIV(mem_to_recover, packed_cell_mem_cost()); } /* This algorithm itself assumes that you've got enough memory slack * to actually run it. */ for (circ = global_circuitlist; circ; circ = circ->next) smartlist_add(circlist, circ); /* Set circcomp_now_tmp so that the sort can work. */ tor_gettimeofday_cached(&now); circcomp_now_tmp = (uint32_t)tv_to_msec(&now); /* This is O(n log n); there are faster algorithms we could use instead. * Let's hope this doesn't happen enough to be in the critical path. */ smartlist_sort(circlist, circuits_compare_by_oldest_queued_cell_); /* Okay, now the worst circuits are at the front of the list. Let's mark * them, and reclaim their storage aggressively. */ SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) { size_t n = n_cells_in_circ_queues(circ); if (! circ->marked_for_close) { circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); } marked_circuit_free_cells(circ); ++n_circuits_killed; n_cells_removed += n; if (n_cells_removed >= n_cells_to_remove) break; } SMARTLIST_FOREACH_END(circ); clean_cell_pool(); /* In case this helps. */ log_notice(LD_GENERAL, "Removed "U64_FORMAT" bytes by killing %d circuits.", U64_PRINTF_ARG(n_cells_removed * packed_cell_mem_cost()), n_circuits_killed); smartlist_free(circlist); } /** Verify that cpath layer cp has all of its invariants * correct. Trigger an assert if anything is invalid. */ void assert_cpath_layer_ok(const crypt_path_t *cp) { // tor_assert(cp->addr); /* these are zero for rendezvous extra-hops */ // tor_assert(cp->port); tor_assert(cp); tor_assert(cp->magic == CRYPT_PATH_MAGIC); switch (cp->state) { case CPATH_STATE_OPEN: tor_assert(cp->f_crypto); tor_assert(cp->b_crypto); /* fall through */ case CPATH_STATE_CLOSED: /*XXXX Assert that there's no handshake_state either. */ tor_assert(!cp->rend_dh_handshake_state); break; case CPATH_STATE_AWAITING_KEYS: /* tor_assert(cp->dh_handshake_state); */ break; default: log_fn(LOG_ERR, LD_BUG, "Unexpected state %d", cp->state); tor_assert(0); } tor_assert(cp->package_window >= 0); tor_assert(cp->deliver_window >= 0); } /** Verify that cpath cp has all of its invariants * correct. Trigger an assert if anything is invalid. */ static void assert_cpath_ok(const crypt_path_t *cp) { const crypt_path_t *start = cp; do { assert_cpath_layer_ok(cp); /* layers must be in sequence of: "open* awaiting? closed*" */ if (cp != start) { if (cp->state == CPATH_STATE_AWAITING_KEYS) { tor_assert(cp->prev->state == CPATH_STATE_OPEN); } else if (cp->state == CPATH_STATE_OPEN) { tor_assert(cp->prev->state == CPATH_STATE_OPEN); } } cp = cp->next; tor_assert(cp); } while (cp != start); } /** Verify that circuit c has all of its invariants * correct. Trigger an assert if anything is invalid. */ void assert_circuit_ok(const circuit_t *c) { edge_connection_t *conn; const or_circuit_t *or_circ = NULL; const origin_circuit_t *origin_circ = NULL; tor_assert(c); tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC); tor_assert(c->purpose >= CIRCUIT_PURPOSE_MIN_ && c->purpose <= CIRCUIT_PURPOSE_MAX_); { /* Having a separate variable for this pleases GCC 4.2 in ways I hope I * never understand. -NM. */ circuit_t *nonconst_circ = (circuit_t*) c; if (CIRCUIT_IS_ORIGIN(c)) origin_circ = TO_ORIGIN_CIRCUIT(nonconst_circ); else or_circ = TO_OR_CIRCUIT(nonconst_circ); } if (c->n_chan) { tor_assert(!c->n_hop); if (c->n_circ_id) { /* We use the _impl variant here to make sure we don't fail on marked * circuits, which would not be returned by the regular function. */ circuit_t *c2 = circuit_get_by_circid_channel_impl(c->n_circ_id, c->n_chan); tor_assert(c == c2); } } if (or_circ && or_circ->p_chan) { if (or_circ->p_circ_id) { /* ibid */ circuit_t *c2 = circuit_get_by_circid_channel_impl(or_circ->p_circ_id, or_circ->p_chan); tor_assert(c == c2); } } if (or_circ) for (conn = or_circ->n_streams; conn; conn = conn->next_stream) tor_assert(conn->base_.type == CONN_TYPE_EXIT); tor_assert(c->deliver_window >= 0); tor_assert(c->package_window >= 0); if (c->state == CIRCUIT_STATE_OPEN) { tor_assert(!c->n_chan_create_cell); if (or_circ) { tor_assert(or_circ->n_crypto); tor_assert(or_circ->p_crypto); tor_assert(or_circ->n_digest); tor_assert(or_circ->p_digest); } } if (c->state == CIRCUIT_STATE_CHAN_WAIT && !c->marked_for_close) { tor_assert(circuits_pending_chans && smartlist_contains(circuits_pending_chans, c)); } else { tor_assert(!circuits_pending_chans || !smartlist_contains(circuits_pending_chans, c)); } if (origin_circ && origin_circ->cpath) { assert_cpath_ok(origin_circ->cpath); } if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) { tor_assert(or_circ); if (!c->marked_for_close) { tor_assert(or_circ->rend_splice); tor_assert(or_circ->rend_splice->rend_splice == or_circ); } tor_assert(or_circ->rend_splice != or_circ); } else { tor_assert(!or_circ || !or_circ->rend_splice); } } tor-0.2.4.20/src/or/statefile.h0000644000175000017500000000125612255745673013046 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_STATEFILE_H #define TOR_STATEFILE_H or_state_t *get_or_state(void); int did_last_state_file_write_fail(void); int or_state_save(time_t now); void save_transport_to_state(const char *transport_name, const tor_addr_t *addr, uint16_t port); char *get_stored_bindaddr_for_server_transport(const char *transport); int or_state_load(void); int or_state_loaded(void); void or_state_free_all(void); #endif tor-0.2.4.20/src/or/command.h0000644000175000017500000000152612255745673012504 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file command.h * \brief Header file for command.c. **/ #ifndef TOR_COMMAND_H #define TOR_COMMAND_H #include "channel.h" void command_process_cell(channel_t *chan, cell_t *cell); void command_process_var_cell(channel_t *chan, var_cell_t *cell); void command_setup_channel(channel_t *chan); void command_setup_listener(channel_listener_t *chan_l); extern uint64_t stats_n_padding_cells_processed; extern uint64_t stats_n_create_cells_processed; extern uint64_t stats_n_created_cells_processed; extern uint64_t stats_n_relay_cells_processed; extern uint64_t stats_n_destroy_cells_processed; #endif tor-0.2.4.20/src/or/connection.c0000644000175000017500000044565512255745673013237 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file connection.c * \brief General high-level functions to handle reading and writing * on connections. **/ #include "or.h" #include "buffers.h" /* * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ #define TOR_CHANNEL_INTERNAL_ #include "channel.h" #include "channeltls.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuituse.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "connection_or.h" #include "control.h" #include "cpuworker.h" #include "directory.h" #include "dirserv.h" #include "dns.h" #include "dnsserv.h" #include "entrynodes.h" #include "geoip.h" #include "main.h" #include "policies.h" #include "reasons.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" #include "rephist.h" #include "router.h" #include "transports.h" #include "routerparse.h" #ifdef USE_BUFFEREVENTS #include #endif #ifdef HAVE_PWD_H #include #endif static connection_t *connection_listener_new( const struct sockaddr *listensockaddr, socklen_t listensocklen, int type, const char *address, const port_cfg_t *portcfg); static void connection_init(time_t now, connection_t *conn, int type, int socket_family); static int connection_init_accepted_conn(connection_t *conn, const listener_connection_t *listener); static int connection_handle_listener_read(connection_t *conn, int new_type); #ifndef USE_BUFFEREVENTS static int connection_bucket_should_increase(int bucket, or_connection_t *conn); #endif static int connection_finished_flushing(connection_t *conn); static int connection_flushed_some(connection_t *conn); static int connection_finished_connecting(connection_t *conn); static int connection_reached_eof(connection_t *conn); static int connection_read_to_buf(connection_t *conn, ssize_t *max_to_read, int *socket_error); static int connection_process_inbuf(connection_t *conn, int package_partial); static void client_check_address_changed(tor_socket_t sock); static void set_constrained_socket_buffers(tor_socket_t sock, int size); static const char *connection_proxy_state_to_string(int state); static int connection_read_https_proxy_response(connection_t *conn); static void connection_send_socks5_connect(connection_t *conn); static const char *proxy_type_to_string(int proxy_type); static int get_proxy_type(void); /** The last addresses that our network interface seemed to have been * binding to. We use this as one way to detect when our IP changes. * * XXX024 We should really use the entire list of interfaces here. **/ static tor_addr_t *last_interface_ipv4 = NULL; /* DOCDOC last_interface_ipv6 */ static tor_addr_t *last_interface_ipv6 = NULL; /** A list of tor_addr_t for addresses we've used in outgoing connections. * Used to detect IP address changes. */ static smartlist_t *outgoing_addrs = NULL; #define CASE_ANY_LISTENER_TYPE \ case CONN_TYPE_OR_LISTENER: \ case CONN_TYPE_AP_LISTENER: \ case CONN_TYPE_DIR_LISTENER: \ case CONN_TYPE_CONTROL_LISTENER: \ case CONN_TYPE_AP_TRANS_LISTENER: \ case CONN_TYPE_AP_NATD_LISTENER: \ case CONN_TYPE_AP_DNS_LISTENER /**************************************************************/ /** * Return the human-readable name for the connection type type */ const char * conn_type_to_string(int type) { static char buf[64]; switch (type) { case CONN_TYPE_OR_LISTENER: return "OR listener"; case CONN_TYPE_OR: return "OR"; case CONN_TYPE_EXIT: return "Exit"; case CONN_TYPE_AP_LISTENER: return "Socks listener"; case CONN_TYPE_AP_TRANS_LISTENER: return "Transparent pf/netfilter listener"; case CONN_TYPE_AP_NATD_LISTENER: return "Transparent natd listener"; case CONN_TYPE_AP_DNS_LISTENER: return "DNS listener"; case CONN_TYPE_AP: return "Socks"; case CONN_TYPE_DIR_LISTENER: return "Directory listener"; case CONN_TYPE_DIR: return "Directory"; case CONN_TYPE_CPUWORKER: return "CPU worker"; case CONN_TYPE_CONTROL_LISTENER: return "Control listener"; case CONN_TYPE_CONTROL: return "Control"; default: log_warn(LD_BUG, "unknown connection type %d", type); tor_snprintf(buf, sizeof(buf), "unknown [%d]", type); return buf; } } /** * Return the human-readable name for the connection state state * for the connection type type */ const char * conn_state_to_string(int type, int state) { static char buf[96]; switch (type) { CASE_ANY_LISTENER_TYPE: if (state == LISTENER_STATE_READY) return "ready"; break; case CONN_TYPE_OR: switch (state) { case OR_CONN_STATE_CONNECTING: return "connect()ing"; case OR_CONN_STATE_PROXY_HANDSHAKING: return "handshaking (proxy)"; case OR_CONN_STATE_TLS_HANDSHAKING: return "handshaking (TLS)"; case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING: return "renegotiating (TLS, v2 handshake)"; case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: return "waiting for renegotiation or V3 handshake"; case OR_CONN_STATE_OR_HANDSHAKING_V2: return "handshaking (Tor, v2 handshake)"; case OR_CONN_STATE_OR_HANDSHAKING_V3: return "handshaking (Tor, v3 handshake)"; case OR_CONN_STATE_OPEN: return "open"; } break; case CONN_TYPE_EXIT: switch (state) { case EXIT_CONN_STATE_RESOLVING: return "waiting for dest info"; case EXIT_CONN_STATE_CONNECTING: return "connecting"; case EXIT_CONN_STATE_OPEN: return "open"; case EXIT_CONN_STATE_RESOLVEFAILED: return "resolve failed"; } break; case CONN_TYPE_AP: switch (state) { case AP_CONN_STATE_SOCKS_WAIT: return "waiting for socks info"; case AP_CONN_STATE_NATD_WAIT: return "waiting for natd dest info"; case AP_CONN_STATE_RENDDESC_WAIT: return "waiting for rendezvous desc"; case AP_CONN_STATE_CONTROLLER_WAIT: return "waiting for controller"; case AP_CONN_STATE_CIRCUIT_WAIT: return "waiting for circuit"; case AP_CONN_STATE_CONNECT_WAIT: return "waiting for connect response"; case AP_CONN_STATE_RESOLVE_WAIT: return "waiting for resolve response"; case AP_CONN_STATE_OPEN: return "open"; } break; case CONN_TYPE_DIR: switch (state) { case DIR_CONN_STATE_CONNECTING: return "connecting"; case DIR_CONN_STATE_CLIENT_SENDING: return "client sending"; case DIR_CONN_STATE_CLIENT_READING: return "client reading"; case DIR_CONN_STATE_CLIENT_FINISHED: return "client finished"; case DIR_CONN_STATE_SERVER_COMMAND_WAIT: return "waiting for command"; case DIR_CONN_STATE_SERVER_WRITING: return "writing"; } break; case CONN_TYPE_CPUWORKER: switch (state) { case CPUWORKER_STATE_IDLE: return "idle"; case CPUWORKER_STATE_BUSY_ONION: return "busy with onion"; } break; case CONN_TYPE_CONTROL: switch (state) { case CONTROL_CONN_STATE_OPEN: return "open (protocol v1)"; case CONTROL_CONN_STATE_NEEDAUTH: return "waiting for authentication (protocol v1)"; } break; } log_warn(LD_BUG, "unknown connection state %d (type %d)", state, type); tor_snprintf(buf, sizeof(buf), "unknown state [%d] on unknown [%s] connection", state, conn_type_to_string(type)); return buf; } #ifdef USE_BUFFEREVENTS /** Return true iff the connection's type is one that can use a bufferevent-based implementation. */ int connection_type_uses_bufferevent(connection_t *conn) { switch (conn->type) { case CONN_TYPE_AP: case CONN_TYPE_EXIT: case CONN_TYPE_DIR: case CONN_TYPE_CONTROL: case CONN_TYPE_OR: case CONN_TYPE_CPUWORKER: return 1; default: return 0; } } #endif /** Allocate and return a new dir_connection_t, initialized as by * connection_init(). */ dir_connection_t * dir_connection_new(int socket_family) { dir_connection_t *dir_conn = tor_malloc_zero(sizeof(dir_connection_t)); connection_init(time(NULL), TO_CONN(dir_conn), CONN_TYPE_DIR, socket_family); return dir_conn; } /** Allocate and return a new or_connection_t, initialized as by * connection_init(). * * Set timestamp_last_added_nonpadding to now. * * Assign a pseudorandom next_circ_id between 0 and 2**15. * * Initialize active_circuit_pqueue. * * Set active_circuit_pqueue_last_recalibrated to current cell_ewma tick. */ or_connection_t * or_connection_new(int socket_family) { or_connection_t *or_conn = tor_malloc_zero(sizeof(or_connection_t)); time_t now = time(NULL); connection_init(now, TO_CONN(or_conn), CONN_TYPE_OR, socket_family); or_conn->timestamp_last_added_nonpadding = time(NULL); return or_conn; } /** Allocate and return a new entry_connection_t, initialized as by * connection_init(). * * Allocate space to store the socks_request. */ entry_connection_t * entry_connection_new(int type, int socket_family) { entry_connection_t *entry_conn = tor_malloc_zero(sizeof(entry_connection_t)); tor_assert(type == CONN_TYPE_AP); connection_init(time(NULL), ENTRY_TO_CONN(entry_conn), type, socket_family); entry_conn->socks_request = socks_request_new(); /* If this is coming from a listener, we'll set it up based on the listener * in a little while. Otherwise, we're doing this as a linked connection * of some kind, and we should set it up here based on the socket family */ if (socket_family == AF_INET) entry_conn->ipv4_traffic_ok = 1; else if (socket_family == AF_INET6) entry_conn->ipv6_traffic_ok = 1; return entry_conn; } /** Allocate and return a new edge_connection_t, initialized as by * connection_init(). */ edge_connection_t * edge_connection_new(int type, int socket_family) { edge_connection_t *edge_conn = tor_malloc_zero(sizeof(edge_connection_t)); tor_assert(type == CONN_TYPE_EXIT); connection_init(time(NULL), TO_CONN(edge_conn), type, socket_family); return edge_conn; } /** Allocate and return a new control_connection_t, initialized as by * connection_init(). */ control_connection_t * control_connection_new(int socket_family) { control_connection_t *control_conn = tor_malloc_zero(sizeof(control_connection_t)); connection_init(time(NULL), TO_CONN(control_conn), CONN_TYPE_CONTROL, socket_family); log_notice(LD_CONTROL, "New control connection opened."); return control_conn; } /** Allocate and return a new listener_connection_t, initialized as by * connection_init(). */ listener_connection_t * listener_connection_new(int type, int socket_family) { listener_connection_t *listener_conn = tor_malloc_zero(sizeof(listener_connection_t)); connection_init(time(NULL), TO_CONN(listener_conn), type, socket_family); return listener_conn; } /** Allocate, initialize, and return a new connection_t subtype of type * to make or receive connections of address family socket_family. The * type should be one of the CONN_TYPE_* constants. */ connection_t * connection_new(int type, int socket_family) { switch (type) { case CONN_TYPE_OR: return TO_CONN(or_connection_new(socket_family)); case CONN_TYPE_EXIT: return TO_CONN(edge_connection_new(type, socket_family)); case CONN_TYPE_AP: return ENTRY_TO_CONN(entry_connection_new(type, socket_family)); case CONN_TYPE_DIR: return TO_CONN(dir_connection_new(socket_family)); case CONN_TYPE_CONTROL: return TO_CONN(control_connection_new(socket_family)); CASE_ANY_LISTENER_TYPE: return TO_CONN(listener_connection_new(type, socket_family)); default: { connection_t *conn = tor_malloc_zero(sizeof(connection_t)); connection_init(time(NULL), conn, type, socket_family); return conn; } } } /** Initializes conn. (you must call connection_add() to link it into the main * array). * * Set conn-\>magic to the correct value. * * Set conn-\>type to type. Set conn-\>s and conn-\>conn_array_index to * -1 to signify they are not yet assigned. * * Initialize conn's timestamps to now. */ static void connection_init(time_t now, connection_t *conn, int type, int socket_family) { static uint64_t n_connections_allocated = 1; switch (type) { case CONN_TYPE_OR: conn->magic = OR_CONNECTION_MAGIC; break; case CONN_TYPE_EXIT: conn->magic = EDGE_CONNECTION_MAGIC; break; case CONN_TYPE_AP: conn->magic = ENTRY_CONNECTION_MAGIC; break; case CONN_TYPE_DIR: conn->magic = DIR_CONNECTION_MAGIC; break; case CONN_TYPE_CONTROL: conn->magic = CONTROL_CONNECTION_MAGIC; break; CASE_ANY_LISTENER_TYPE: conn->magic = LISTENER_CONNECTION_MAGIC; break; default: conn->magic = BASE_CONNECTION_MAGIC; break; } conn->s = TOR_INVALID_SOCKET; /* give it a default of 'not used' */ conn->conn_array_index = -1; /* also default to 'not used' */ conn->global_identifier = n_connections_allocated++; conn->type = type; conn->socket_family = socket_family; #ifndef USE_BUFFEREVENTS if (!connection_is_listener(conn)) { /* listeners never use their buf */ conn->inbuf = buf_new(); conn->outbuf = buf_new(); } #endif conn->timestamp_created = now; conn->timestamp_lastread = now; conn->timestamp_lastwritten = now; } /** Create a link between conn_a and conn_b. */ void connection_link_connections(connection_t *conn_a, connection_t *conn_b) { tor_assert(! SOCKET_OK(conn_a->s)); tor_assert(! SOCKET_OK(conn_b->s)); conn_a->linked = 1; conn_b->linked = 1; conn_a->linked_conn = conn_b; conn_b->linked_conn = conn_a; } /** Deallocate memory used by conn. Deallocate its buffers if * necessary, close its socket if necessary, and mark the directory as dirty * if conn is an OR or OP connection. */ static void connection_free_(connection_t *conn) { void *mem; size_t memlen; if (!conn) return; switch (conn->type) { case CONN_TYPE_OR: tor_assert(conn->magic == OR_CONNECTION_MAGIC); mem = TO_OR_CONN(conn); memlen = sizeof(or_connection_t); break; case CONN_TYPE_AP: tor_assert(conn->magic == ENTRY_CONNECTION_MAGIC); mem = TO_ENTRY_CONN(conn); memlen = sizeof(entry_connection_t); break; case CONN_TYPE_EXIT: tor_assert(conn->magic == EDGE_CONNECTION_MAGIC); mem = TO_EDGE_CONN(conn); memlen = sizeof(edge_connection_t); break; case CONN_TYPE_DIR: tor_assert(conn->magic == DIR_CONNECTION_MAGIC); mem = TO_DIR_CONN(conn); memlen = sizeof(dir_connection_t); break; case CONN_TYPE_CONTROL: tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC); mem = TO_CONTROL_CONN(conn); memlen = sizeof(control_connection_t); break; CASE_ANY_LISTENER_TYPE: tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC); mem = TO_LISTENER_CONN(conn); memlen = sizeof(listener_connection_t); break; default: tor_assert(conn->magic == BASE_CONNECTION_MAGIC); mem = conn; memlen = sizeof(connection_t); break; } if (conn->linked) { log_info(LD_GENERAL, "Freeing linked %s connection [%s] with %d " "bytes on inbuf, %d on outbuf.", conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state), (int)connection_get_inbuf_len(conn), (int)connection_get_outbuf_len(conn)); } if (!connection_is_listener(conn)) { buf_free(conn->inbuf); buf_free(conn->outbuf); } else { if (conn->socket_family == AF_UNIX) { /* For now only control ports can be Unix domain sockets * and listeners at the same time */ tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER); if (unlink(conn->address) < 0 && errno != ENOENT) { log_warn(LD_NET, "Could not unlink %s: %s", conn->address, strerror(errno)); } } } tor_free(conn->address); if (connection_speaks_cells(conn)) { or_connection_t *or_conn = TO_OR_CONN(conn); tor_tls_free(or_conn->tls); or_conn->tls = NULL; or_handshake_state_free(or_conn->handshake_state); or_conn->handshake_state = NULL; tor_free(or_conn->nickname); } if (conn->type == CONN_TYPE_AP) { entry_connection_t *entry_conn = TO_ENTRY_CONN(conn); tor_free(entry_conn->chosen_exit_name); tor_free(entry_conn->original_dest_address); if (entry_conn->socks_request) socks_request_free(entry_conn->socks_request); if (entry_conn->pending_optimistic_data) { generic_buffer_free(entry_conn->pending_optimistic_data); } if (entry_conn->sending_optimistic_data) { generic_buffer_free(entry_conn->sending_optimistic_data); } } if (CONN_IS_EDGE(conn)) { rend_data_free(TO_EDGE_CONN(conn)->rend_data); } if (conn->type == CONN_TYPE_CONTROL) { control_connection_t *control_conn = TO_CONTROL_CONN(conn); tor_free(control_conn->safecookie_client_hash); tor_free(control_conn->incoming_cmd); } tor_free(conn->read_event); /* Probably already freed by connection_free. */ tor_free(conn->write_event); /* Probably already freed by connection_free. */ IF_HAS_BUFFEREVENT(conn, { /* This was a workaround to handle bugs in some old versions of libevent * where callbacks can occur after calling bufferevent_free(). Setting * the callbacks to NULL prevented this. It shouldn't be necessary any * more, but let's not tempt fate for now. */ bufferevent_setcb(conn->bufev, NULL, NULL, NULL, NULL); bufferevent_free(conn->bufev); conn->bufev = NULL; }); if (conn->type == CONN_TYPE_DIR) { dir_connection_t *dir_conn = TO_DIR_CONN(conn); tor_free(dir_conn->requested_resource); tor_zlib_free(dir_conn->zlib_state); if (dir_conn->fingerprint_stack) { SMARTLIST_FOREACH(dir_conn->fingerprint_stack, char *, cp, tor_free(cp)); smartlist_free(dir_conn->fingerprint_stack); } cached_dir_decref(dir_conn->cached_dir); rend_data_free(dir_conn->rend_data); } if (SOCKET_OK(conn->s)) { log_debug(LD_NET,"closing fd %d.",(int)conn->s); tor_close_socket(conn->s); conn->s = TOR_INVALID_SOCKET; } if (conn->type == CONN_TYPE_OR && !tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) { log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest"); connection_or_remove_from_identity_map(TO_OR_CONN(conn)); } #ifdef USE_BUFFEREVENTS if (conn->type == CONN_TYPE_OR && TO_OR_CONN(conn)->bucket_cfg) { ev_token_bucket_cfg_free(TO_OR_CONN(conn)->bucket_cfg); TO_OR_CONN(conn)->bucket_cfg = NULL; } #endif memwipe(mem, 0xCC, memlen); /* poison memory */ tor_free(mem); } /** Make sure conn isn't in any of the global conn lists; then free it. */ void connection_free(connection_t *conn) { if (!conn) return; tor_assert(!connection_is_on_closeable_list(conn)); tor_assert(!connection_in_array(conn)); if (conn->linked_conn) { log_err(LD_BUG, "Called with conn->linked_conn still set."); tor_fragile_assert(); conn->linked_conn->linked_conn = NULL; if (! conn->linked_conn->marked_for_close && conn->linked_conn->reading_from_linked_conn) connection_start_reading(conn->linked_conn); conn->linked_conn = NULL; } if (connection_speaks_cells(conn)) { if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) { connection_or_remove_from_identity_map(TO_OR_CONN(conn)); } } if (conn->type == CONN_TYPE_CONTROL) { connection_control_closed(TO_CONTROL_CONN(conn)); } connection_unregister_events(conn); connection_free_(conn); } /** * Called when we're about to finally unlink and free a connection: * perform necessary accounting and cleanup * - Directory conns that failed to fetch a rendezvous descriptor * need to inform pending rendezvous streams. * - OR conns need to call rep_hist_note_*() to record status. * - AP conns need to send a socks reject if necessary. * - Exit conns need to call connection_dns_remove() if necessary. * - AP and Exit conns need to send an end cell if they can. * - DNS conns need to fail any resolves that are pending on them. * - OR and edge connections need to be unlinked from circuits. */ void connection_about_to_close_connection(connection_t *conn) { tor_assert(conn->marked_for_close); switch (conn->type) { case CONN_TYPE_DIR: connection_dir_about_to_close(TO_DIR_CONN(conn)); break; case CONN_TYPE_OR: connection_or_about_to_close(TO_OR_CONN(conn)); break; case CONN_TYPE_AP: connection_ap_about_to_close(TO_ENTRY_CONN(conn)); break; case CONN_TYPE_EXIT: connection_exit_about_to_close(TO_EDGE_CONN(conn)); break; } } /** Return true iff connection_close_immediate() has been called on this * connection. */ #define CONN_IS_CLOSED(c) \ ((c)->linked ? ((c)->linked_conn_is_closed) : (! SOCKET_OK(c->s))) /** Close the underlying socket for conn, so we don't try to * flush it. Must be used in conjunction with (right before) * connection_mark_for_close(). */ void connection_close_immediate(connection_t *conn) { assert_connection_ok(conn,0); if (CONN_IS_CLOSED(conn)) { log_err(LD_BUG,"Attempt to close already-closed connection."); tor_fragile_assert(); return; } if (conn->outbuf_flushlen) { log_info(LD_NET,"fd %d, type %s, state %s, %d bytes on outbuf.", (int)conn->s, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state), (int)conn->outbuf_flushlen); } connection_unregister_events(conn); if (SOCKET_OK(conn->s)) tor_close_socket(conn->s); conn->s = TOR_INVALID_SOCKET; if (conn->linked) conn->linked_conn_is_closed = 1; if (conn->outbuf) buf_clear(conn->outbuf); conn->outbuf_flushlen = 0; } /** Mark conn to be closed next time we loop through * conn_close_if_marked() in main.c. */ void connection_mark_for_close_(connection_t *conn, int line, const char *file) { assert_connection_ok(conn,0); tor_assert(line); tor_assert(line < 1<<16); /* marked_for_close can only fit a uint16_t. */ tor_assert(file); if (conn->type == CONN_TYPE_OR) { /* * An or_connection should have been closed through one of the channel- * aware functions in connection_or.c. We'll assume this is an error * close and do that, and log a bug warning. */ log_warn(LD_CHANNEL | LD_BUG, "Something tried to close an or_connection_t without going " "through channels at %s:%d", file, line); connection_or_close_for_error(TO_OR_CONN(conn), 0); } else { /* Pass it down to the real function */ connection_mark_for_close_internal_(conn, line, file); } } /** Mark conn to be closed next time we loop through * conn_close_if_marked() in main.c; the _internal version bypasses the * CONN_TYPE_OR checks; this should be called when you either are sure that * if this is an or_connection_t the controlling channel has been notified * (e.g. with connection_or_notify_error()), or you actually are the * connection_or_close_for_error() or connection_or_close_normally function. * For all other cases, use connection_mark_and_flush() instead, which * checks for or_connection_t properly, instead. See below. */ void connection_mark_for_close_internal_(connection_t *conn, int line, const char *file) { assert_connection_ok(conn,0); tor_assert(line); tor_assert(line < 1<<16); /* marked_for_close can only fit a uint16_t. */ tor_assert(file); if (conn->marked_for_close) { log_warn(LD_BUG,"Duplicate call to connection_mark_for_close at %s:%d" " (first at %s:%d)", file, line, conn->marked_for_close_file, conn->marked_for_close); tor_fragile_assert(); return; } if (conn->type == CONN_TYPE_OR) { /* * Bad news if this happens without telling the controlling channel; do * this so we can find things that call this wrongly when the asserts hit. */ log_debug(LD_CHANNEL, "Calling connection_mark_for_close_internal_() on an OR conn " "at %s:%d", file, line); } conn->marked_for_close = line; conn->marked_for_close_file = file; add_connection_to_closeable_list(conn); /* in case we're going to be held-open-til-flushed, reset * the number of seconds since last successful write, so * we get our whole 15 seconds */ conn->timestamp_lastwritten = time(NULL); } /** Find each connection that has hold_open_until_flushed set to * 1 but hasn't written in the past 15 seconds, and set * hold_open_until_flushed to 0. This means it will get cleaned * up in the next loop through close_if_marked() in main.c. */ void connection_expire_held_open(void) { time_t now; smartlist_t *conns = get_connection_array(); now = time(NULL); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { /* If we've been holding the connection open, but we haven't written * for 15 seconds... */ if (conn->hold_open_until_flushed) { tor_assert(conn->marked_for_close); if (now - conn->timestamp_lastwritten >= 15) { int severity; if (conn->type == CONN_TYPE_EXIT || (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER)) severity = LOG_INFO; else severity = LOG_NOTICE; log_fn(severity, LD_NET, "Giving up on marked_for_close conn that's been flushing " "for 15s (fd %d, type %s, state %s).", (int)conn->s, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state)); conn->hold_open_until_flushed = 0; } } } SMARTLIST_FOREACH_END(conn); } #if defined(HAVE_SYS_UN_H) || defined(RUNNING_DOXYGEN) /** Create an AF_UNIX listenaddr struct. * listenaddress provides the path to the Unix socket. * * Eventually listenaddress will also optionally contain user, group, * and file permissions for the new socket. But not yet. XXX * Also, since we do not create the socket here the information doesn't help * here. * * If not NULL readable_address will contain a copy of the path part of * listenaddress. * * The listenaddr struct has to be freed by the caller. */ static struct sockaddr_un * create_unix_sockaddr(const char *listenaddress, char **readable_address, socklen_t *len_out) { struct sockaddr_un *sockaddr = NULL; sockaddr = tor_malloc_zero(sizeof(struct sockaddr_un)); sockaddr->sun_family = AF_UNIX; if (strlcpy(sockaddr->sun_path, listenaddress, sizeof(sockaddr->sun_path)) >= sizeof(sockaddr->sun_path)) { log_warn(LD_CONFIG, "Unix socket path '%s' is too long to fit.", escaped(listenaddress)); tor_free(sockaddr); return NULL; } if (readable_address) *readable_address = tor_strdup(listenaddress); *len_out = sizeof(struct sockaddr_un); return sockaddr; } #else static struct sockaddr * create_unix_sockaddr(const char *listenaddress, char **readable_address, socklen_t *len_out) { (void)listenaddress; (void)readable_address; log_fn(LOG_ERR, LD_BUG, "Unix domain sockets not supported, yet we tried to create one."); *len_out = 0; tor_fragile_assert(); return NULL; } #endif /* HAVE_SYS_UN_H */ /** Warn that an accept or a connect has failed because we're running up * against our ulimit. Rate-limit these warnings so that we don't spam * the log. */ static void warn_too_many_conns(void) { #define WARN_TOO_MANY_CONNS_INTERVAL (6*60*60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CONNS_INTERVAL); char *m; if ((m = rate_limit_log(&last_warned, approx_time()))) { int n_conns = get_n_open_sockets(); log_warn(LD_NET,"Failing because we have %d connections already. Please " "raise your ulimit -n.%s", n_conns, m); tor_free(m); control_event_general_status(LOG_WARN, "TOO_MANY_CONNECTIONS CURRENT=%d", n_conns); } } #ifdef HAVE_SYS_UN_H /** Check whether we should be willing to open an AF_UNIX socket in * path. Return 0 if we should go ahead and -1 if we shouldn't. */ static int check_location_for_unix_socket(const or_options_t *options, const char *path) { int r = -1; char *p = tor_strdup(path); cpd_check_t flags = CPD_CHECK_MODE_ONLY; if (get_parent_directory(p)<0) goto done; if (options->ControlSocketsGroupWritable) flags |= CPD_GROUP_OK; if (check_private_dir(p, flags, options->User) < 0) { char *escpath, *escdir; escpath = esc_for_log(path); escdir = esc_for_log(p); log_warn(LD_GENERAL, "Before Tor can create a control socket in %s, the " "directory %s needs to exist, and to be accessible only by the " "user%s account that is running Tor. (On some Unix systems, " "anybody who can list a socket can connect to it, so Tor is " "being careful.)", escpath, escdir, options->ControlSocketsGroupWritable ? " and group" : ""); tor_free(escpath); tor_free(escdir); goto done; } r = 0; done: tor_free(p); return r; } #endif /** Tell the TCP stack that it shouldn't wait for a long time after * sock has closed before reusing its port. */ static void make_socket_reuseable(tor_socket_t sock) { #ifdef _WIN32 (void) sock; #else int one=1; /* REUSEADDR on normal places means you can rebind to the port * right after somebody else has let it go. But REUSEADDR on win32 * means you can bind to the port _even when somebody else * already has it bound_. So, don't do that on Win32. */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, (socklen_t)sizeof(one)) == -1) { log_warn(LD_NET, "Error setting SO_REUSEADDR flag: %s", tor_socket_strerror(errno)); } #endif } /** Bind a new non-blocking socket listening to the socket described * by listensockaddr. * * address is only used for logging purposes and to add the information * to the conn. */ static connection_t * connection_listener_new(const struct sockaddr *listensockaddr, socklen_t socklen, int type, const char *address, const port_cfg_t *port_cfg) { listener_connection_t *lis_conn; connection_t *conn; tor_socket_t s; /* the socket we're going to make */ or_options_t const *options = get_options(); #if defined(HAVE_PWD_H) && defined(HAVE_SYS_UN_H) struct passwd *pw = NULL; #endif uint16_t usePort = 0, gotPort = 0; int start_reading = 0; static int global_next_session_group = SESSION_GROUP_FIRST_AUTO; tor_addr_t addr; if (get_n_open_sockets() >= get_options()->ConnLimit_-1) { warn_too_many_conns(); return NULL; } if (listensockaddr->sa_family == AF_INET || listensockaddr->sa_family == AF_INET6) { int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER); if (is_tcp) start_reading = 1; tor_addr_from_sockaddr(&addr, listensockaddr, &usePort); log_notice(LD_NET, "Opening %s on %s", conn_type_to_string(type), fmt_addrport(&addr, usePort)); s = tor_open_socket(tor_addr_family(&addr), is_tcp ? SOCK_STREAM : SOCK_DGRAM, is_tcp ? IPPROTO_TCP: IPPROTO_UDP); if (!SOCKET_OK(s)) { log_warn(LD_NET,"Socket creation failed: %s", tor_socket_strerror(tor_socket_errno(-1))); goto err; } make_socket_reuseable(s); #ifdef IPV6_V6ONLY if (listensockaddr->sa_family == AF_INET6) { #ifdef _WIN32 /* In Redmond, this kind of thing passes for standards-conformance. */ DWORD one = 1; #else int one = 1; #endif /* We need to set IPV6_V6ONLY so that this socket can't get used for * IPv4 connections. */ if (setsockopt(s,IPPROTO_IPV6, IPV6_V6ONLY, (void*)&one, sizeof(one))<0) { int e = tor_socket_errno(s); log_warn(LD_NET, "Error setting IPV6_V6ONLY flag: %s", tor_socket_strerror(e)); /* Keep going; probably not harmful. */ } } #endif if (bind(s,listensockaddr,socklen) < 0) { const char *helpfulhint = ""; int e = tor_socket_errno(s); if (ERRNO_IS_EADDRINUSE(e)) helpfulhint = ". Is Tor already running?"; log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort, tor_socket_strerror(e), helpfulhint); tor_close_socket(s); goto err; } if (is_tcp) { if (listen(s,SOMAXCONN) < 0) { log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort, tor_socket_strerror(tor_socket_errno(s))); tor_close_socket(s); goto err; } } if (usePort != 0) { gotPort = usePort; } else { tor_addr_t addr2; struct sockaddr_storage ss; socklen_t ss_len=sizeof(ss); if (getsockname(s, (struct sockaddr*)&ss, &ss_len)<0) { log_warn(LD_NET, "getsockname() couldn't learn address for %s: %s", conn_type_to_string(type), tor_socket_strerror(tor_socket_errno(s))); gotPort = 0; } tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort); } #ifdef HAVE_SYS_UN_H } else if (listensockaddr->sa_family == AF_UNIX) { start_reading = 1; /* For now only control ports can be Unix domain sockets * and listeners at the same time */ tor_assert(type == CONN_TYPE_CONTROL_LISTENER); if (check_location_for_unix_socket(options, address) < 0) goto err; log_notice(LD_NET, "Opening %s on %s", conn_type_to_string(type), address); tor_addr_make_unspec(&addr); if (unlink(address) < 0 && errno != ENOENT) { log_warn(LD_NET, "Could not unlink %s: %s", address, strerror(errno)); goto err; } s = tor_open_socket(AF_UNIX, SOCK_STREAM, 0); if (! SOCKET_OK(s)) { log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno)); goto err; } if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) { log_warn(LD_NET,"Bind to %s failed: %s.", address, tor_socket_strerror(tor_socket_errno(s))); tor_close_socket(s); goto err; } #ifdef HAVE_PWD_H if (options->User) { pw = getpwnam(options->User); if (pw == NULL) { log_warn(LD_NET,"Unable to chown() %s socket: user %s not found.", address, options->User); tor_close_socket(s); goto err; } else if (chown(address, pw->pw_uid, pw->pw_gid) < 0) { log_warn(LD_NET,"Unable to chown() %s socket: %s.", address, strerror(errno)); tor_close_socket(s); goto err; } } #endif if (options->ControlSocketsGroupWritable) { /* We need to use chmod; fchmod doesn't work on sockets on all * platforms. */ if (chmod(address, 0660) < 0) { log_warn(LD_FS,"Unable to make %s group-writable.", address); tor_close_socket(s); goto err; } } if (listen(s,SOMAXCONN) < 0) { log_warn(LD_NET, "Could not listen on %s: %s", address, tor_socket_strerror(tor_socket_errno(s))); tor_close_socket(s); goto err; } #else (void)options; #endif /* HAVE_SYS_UN_H */ } else { log_err(LD_BUG,"Got unexpected address family %d.", listensockaddr->sa_family); tor_assert(0); } if (set_socket_nonblocking(s) == -1) { tor_close_socket(s); goto err; } lis_conn = listener_connection_new(type, listensockaddr->sa_family); conn = TO_CONN(lis_conn); conn->socket_family = listensockaddr->sa_family; conn->s = s; conn->address = tor_strdup(address); conn->port = gotPort; tor_addr_copy(&conn->addr, &addr); if (port_cfg->isolation_flags) { lis_conn->isolation_flags = port_cfg->isolation_flags; if (port_cfg->session_group >= 0) { lis_conn->session_group = port_cfg->session_group; } else { /* This can wrap after around INT_MAX listeners are opened. But I don't * believe that matters, since you would need to open a ridiculous * number of listeners while keeping the early ones open before you ever * hit this. An OR with a dozen ports open, for example, would have to * close and re-open its listeners every second for 4 years nonstop. */ lis_conn->session_group = global_next_session_group--; } } if (type == CONN_TYPE_AP_LISTENER) { lis_conn->socks_ipv4_traffic = port_cfg->ipv4_traffic; lis_conn->socks_ipv6_traffic = port_cfg->ipv6_traffic; lis_conn->socks_prefer_ipv6 = port_cfg->prefer_ipv6; } else { lis_conn->socks_ipv4_traffic = 1; lis_conn->socks_ipv6_traffic = 1; } lis_conn->cache_ipv4_answers = port_cfg->cache_ipv4_answers; lis_conn->cache_ipv6_answers = port_cfg->cache_ipv6_answers; lis_conn->use_cached_ipv4_answers = port_cfg->use_cached_ipv4_answers; lis_conn->use_cached_ipv6_answers = port_cfg->use_cached_ipv6_answers; lis_conn->prefer_ipv6_virtaddr = port_cfg->prefer_ipv6_virtaddr; lis_conn->socks_prefer_no_auth = port_cfg->socks_prefer_no_auth; if (connection_add(conn) < 0) { /* no space, forget it */ log_warn(LD_NET,"connection_add for listener failed. Giving up."); connection_free(conn); goto err; } log_fn(usePort==gotPort ? LOG_DEBUG : LOG_NOTICE, LD_NET, "%s listening on port %u.", conn_type_to_string(type), gotPort); conn->state = LISTENER_STATE_READY; if (start_reading) { connection_start_reading(conn); } else { tor_assert(type == CONN_TYPE_AP_DNS_LISTENER); dnsserv_configure_listener(conn); } return conn; err: return NULL; } /** Do basic sanity checking on a newly received socket. Return 0 * if it looks ok, else return -1. * * Notably, some TCP stacks can erroneously have accept() return successfully * with socklen 0, when the client sends an RST before the accept call (as * nmap does). We want to detect that, and not go on with the connection. */ static int check_sockaddr(const struct sockaddr *sa, int len, int level) { int ok = 1; if (sa->sa_family == AF_INET) { struct sockaddr_in *sin=(struct sockaddr_in*)sa; if (len != sizeof(struct sockaddr_in)) { log_fn(level, LD_NET, "Length of address not as expected: %d vs %d", len,(int)sizeof(struct sockaddr_in)); ok = 0; } if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) { log_fn(level, LD_NET, "Address for new connection has address/port equal to zero."); ok = 0; } } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6=(struct sockaddr_in6*)sa; if (len != sizeof(struct sockaddr_in6)) { log_fn(level, LD_NET, "Length of address not as expected: %d vs %d", len,(int)sizeof(struct sockaddr_in6)); ok = 0; } if (tor_mem_is_zero((void*)sin6->sin6_addr.s6_addr, 16) || sin6->sin6_port == 0) { log_fn(level, LD_NET, "Address for new connection has address/port equal to zero."); ok = 0; } } else { ok = 0; } return ok ? 0 : -1; } /** Check whether the socket family from an accepted socket got is the * same as the one that listener is waiting for. If it isn't, log * a useful message and return -1. Else return 0. * * This is annoying, but can apparently happen on some Darwins. */ static int check_sockaddr_family_match(sa_family_t got, connection_t *listener) { if (got != listener->socket_family) { log_info(LD_BUG, "A listener connection returned a socket with a " "mismatched family. %s for addr_family %d gave us a socket " "with address family %d. Dropping.", conn_type_to_string(listener->type), (int)listener->socket_family, (int)got); return -1; } return 0; } /** The listener connection conn told poll() it wanted to read. * Call accept() on conn-\>s, and add the new connection if necessary. */ static int connection_handle_listener_read(connection_t *conn, int new_type) { tor_socket_t news; /* the new socket */ connection_t *newconn; /* information about the remote peer when connecting to other routers */ struct sockaddr_storage addrbuf; struct sockaddr *remote = (struct sockaddr*)&addrbuf; /* length of the remote address. Must be whatever accept() needs. */ socklen_t remotelen = (socklen_t)sizeof(addrbuf); const or_options_t *options = get_options(); tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in)); memset(&addrbuf, 0, sizeof(addrbuf)); news = tor_accept_socket(conn->s,remote,&remotelen); if (!SOCKET_OK(news)) { /* accept() error */ int e = tor_socket_errno(conn->s); if (ERRNO_IS_ACCEPT_EAGAIN(e)) { return 0; /* he hung up before we could accept(). that's fine. */ } else if (ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e)) { warn_too_many_conns(); return 0; } /* else there was a real error. */ log_warn(LD_NET,"accept() failed: %s. Closing listener.", tor_socket_strerror(e)); connection_mark_for_close(conn); return -1; } log_debug(LD_NET, "Connection accepted on socket %d (child of fd %d).", (int)news,(int)conn->s); make_socket_reuseable(news); if (set_socket_nonblocking(news) == -1) { tor_close_socket(news); return 0; } if (options->ConstrainedSockets) set_constrained_socket_buffers(news, (int)options->ConstrainedSockSize); if (check_sockaddr_family_match(remote->sa_family, conn) < 0) { tor_close_socket(news); return 0; } if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6) { tor_addr_t addr; uint16_t port; if (check_sockaddr(remote, remotelen, LOG_INFO)<0) { log_info(LD_NET, "accept() returned a strange address; closing connection."); tor_close_socket(news); return 0; } tor_addr_from_sockaddr(&addr, remote, &port); /* process entrance policies here, before we even create the connection */ if (new_type == CONN_TYPE_AP) { /* check sockspolicy to see if we should accept it */ if (socks_policy_permits_address(&addr) == 0) { log_notice(LD_APP, "Denying socks connection from untrusted address %s.", fmt_and_decorate_addr(&addr)); tor_close_socket(news); return 0; } } if (new_type == CONN_TYPE_DIR) { /* check dirpolicy to see if we should accept it */ if (dir_policy_permits_address(&addr) == 0) { log_notice(LD_DIRSERV,"Denying dir connection from address %s.", fmt_and_decorate_addr(&addr)); tor_close_socket(news); return 0; } } newconn = connection_new(new_type, conn->socket_family); newconn->s = news; /* remember the remote address */ tor_addr_copy(&newconn->addr, &addr); newconn->port = port; newconn->address = tor_dup_addr(&addr); if (new_type == CONN_TYPE_AP) { TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth = TO_LISTENER_CONN(conn)->socks_prefer_no_auth; } } else if (conn->socket_family == AF_UNIX) { /* For now only control ports can be Unix domain sockets * and listeners at the same time */ tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER); newconn = connection_new(new_type, conn->socket_family); newconn->s = news; /* remember the remote address -- do we have anything sane to put here? */ tor_addr_make_unspec(&newconn->addr); newconn->port = 1; newconn->address = tor_strdup(conn->address); } else { tor_assert(0); }; if (connection_add(newconn) < 0) { /* no space, forget it */ connection_free(newconn); return 0; /* no need to tear down the parent */ } if (connection_init_accepted_conn(newconn, TO_LISTENER_CONN(conn)) < 0) { if (! newconn->marked_for_close) connection_mark_for_close(newconn); return 0; } return 0; } /** Initialize states for newly accepted connection conn. * If conn is an OR, start the TLS handshake. * If conn is a transparent AP, get its original destination * and place it in circuit_wait. */ static int connection_init_accepted_conn(connection_t *conn, const listener_connection_t *listener) { int rv; connection_start_reading(conn); switch (conn->type) { case CONN_TYPE_OR: control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0); rv = connection_tls_start_handshake(TO_OR_CONN(conn), 1); if (rv < 0) { connection_or_close_for_error(TO_OR_CONN(conn), 0); } return rv; break; case CONN_TYPE_AP: TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags; TO_ENTRY_CONN(conn)->session_group = listener->session_group; TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch(); TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type; TO_ENTRY_CONN(conn)->ipv4_traffic_ok = listener->socks_ipv4_traffic; TO_ENTRY_CONN(conn)->ipv6_traffic_ok = listener->socks_ipv6_traffic; TO_ENTRY_CONN(conn)->prefer_ipv6_traffic = listener->socks_prefer_ipv6; TO_ENTRY_CONN(conn)->cache_ipv4_answers = listener->cache_ipv4_answers; TO_ENTRY_CONN(conn)->cache_ipv6_answers = listener->cache_ipv6_answers; TO_ENTRY_CONN(conn)->use_cached_ipv4_answers = listener->use_cached_ipv4_answers; TO_ENTRY_CONN(conn)->use_cached_ipv6_answers = listener->use_cached_ipv6_answers; TO_ENTRY_CONN(conn)->prefer_ipv6_virtaddr = listener->prefer_ipv6_virtaddr; switch (TO_CONN(listener)->type) { case CONN_TYPE_AP_LISTENER: conn->state = AP_CONN_STATE_SOCKS_WAIT; break; case CONN_TYPE_AP_TRANS_LISTENER: TO_ENTRY_CONN(conn)->is_transparent_ap = 1; conn->state = AP_CONN_STATE_CIRCUIT_WAIT; return connection_ap_process_transparent(TO_ENTRY_CONN(conn)); case CONN_TYPE_AP_NATD_LISTENER: TO_ENTRY_CONN(conn)->is_transparent_ap = 1; conn->state = AP_CONN_STATE_NATD_WAIT; break; } break; case CONN_TYPE_DIR: conn->purpose = DIR_PURPOSE_SERVER; conn->state = DIR_CONN_STATE_SERVER_COMMAND_WAIT; break; case CONN_TYPE_CONTROL: conn->state = CONTROL_CONN_STATE_NEEDAUTH; break; } return 0; } /** Take conn, make a nonblocking socket; try to connect to * addr:port (they arrive in *host order*). If fail, return -1 and if * applicable put your best guess about errno into *socket_error. * Else assign s to conn-\>s: if connected return 1, if EAGAIN return 0. * * address is used to make the logs useful. * * On success, add conn to the list of polled connections. */ int connection_connect(connection_t *conn, const char *address, const tor_addr_t *addr, uint16_t port, int *socket_error) { tor_socket_t s; int inprogress = 0; struct sockaddr_storage addrbuf; struct sockaddr *dest_addr; int dest_addr_len; const or_options_t *options = get_options(); int protocol_family; if (get_n_open_sockets() >= get_options()->ConnLimit_-1) { warn_too_many_conns(); *socket_error = SOCK_ERRNO(ENOBUFS); return -1; } if (tor_addr_family(addr) == AF_INET6) protocol_family = PF_INET6; else protocol_family = PF_INET; if (get_options()->DisableNetwork) { /* We should never even try to connect anyplace if DisableNetwork is set. * Warn if we do, and refuse to make the connection. */ static ratelim_t disablenet_violated = RATELIM_INIT(30*60); *socket_error = SOCK_ERRNO(ENETUNREACH); log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG, "Tried to open a socket with DisableNetwork set."); tor_fragile_assert(); return -1; } s = tor_open_socket(protocol_family,SOCK_STREAM,IPPROTO_TCP); if (! SOCKET_OK(s)) { *socket_error = tor_socket_errno(-1); log_warn(LD_NET,"Error creating network socket: %s", tor_socket_strerror(*socket_error)); return -1; } make_socket_reuseable(s); if (!tor_addr_is_loopback(addr)) { const tor_addr_t *ext_addr = NULL; if (protocol_family == AF_INET && !tor_addr_is_null(&options->OutboundBindAddressIPv4_)) ext_addr = &options->OutboundBindAddressIPv4_; else if (protocol_family == AF_INET6 && !tor_addr_is_null(&options->OutboundBindAddressIPv6_)) ext_addr = &options->OutboundBindAddressIPv6_; if (ext_addr) { struct sockaddr_storage ext_addr_sa; socklen_t ext_addr_len = 0; memset(&ext_addr_sa, 0, sizeof(ext_addr_sa)); ext_addr_len = tor_addr_to_sockaddr(ext_addr, 0, (struct sockaddr *) &ext_addr_sa, sizeof(ext_addr_sa)); if (ext_addr_len == 0) { log_warn(LD_NET, "Error converting OutboundBindAddress %s into sockaddr. " "Ignoring.", fmt_and_decorate_addr(ext_addr)); } else { if (bind(s, (struct sockaddr *) &ext_addr_sa, ext_addr_len) < 0) { *socket_error = tor_socket_errno(s); log_warn(LD_NET,"Error binding network socket to %s: %s", fmt_and_decorate_addr(ext_addr), tor_socket_strerror(*socket_error)); tor_close_socket(s); return -1; } } } } if (set_socket_nonblocking(s) == -1) { *socket_error = tor_socket_errno(s); tor_close_socket(s); return -1; } if (options->ConstrainedSockets) set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize); memset(&addrbuf,0,sizeof(addrbuf)); dest_addr = (struct sockaddr*) &addrbuf; dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf)); tor_assert(dest_addr_len > 0); log_debug(LD_NET, "Connecting to %s:%u.", escaped_safe_str_client(address), port); if (connect(s, dest_addr, (socklen_t)dest_addr_len) < 0) { int e = tor_socket_errno(s); if (!ERRNO_IS_CONN_EINPROGRESS(e)) { /* yuck. kill it. */ *socket_error = e; log_info(LD_NET, "connect() to %s:%u failed: %s", escaped_safe_str_client(address), port, tor_socket_strerror(e)); tor_close_socket(s); return -1; } else { inprogress = 1; } } /* it succeeded. we're connected. */ log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET, "Connection to %s:%u %s (sock "TOR_SOCKET_T_FORMAT").", escaped_safe_str_client(address), port, inprogress?"in progress":"established", s); conn->s = s; if (connection_add_connecting(conn) < 0) { /* no space, forget it */ *socket_error = SOCK_ERRNO(ENOBUFS); return -1; } return inprogress ? 0 : 1; } /** Convert state number to string representation for logging purposes. */ static const char * connection_proxy_state_to_string(int state) { static const char *unknown = "???"; static const char *states[] = { "PROXY_NONE", "PROXY_INFANT", "PROXY_HTTPS_WANT_CONNECT_OK", "PROXY_SOCKS4_WANT_CONNECT_OK", "PROXY_SOCKS5_WANT_AUTH_METHOD_NONE", "PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929", "PROXY_SOCKS5_WANT_AUTH_RFC1929_OK", "PROXY_SOCKS5_WANT_CONNECT_OK", "PROXY_CONNECTED", }; if (state < PROXY_NONE || state > PROXY_CONNECTED) return unknown; return states[state]; } /** Write a proxy request of type (socks4, socks5, https) to conn * for conn->addr:conn->port, authenticating with the auth details given * in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies * support authentication. * * Returns -1 if conn->addr is incompatible with the proxy protocol, and * 0 otherwise. * * Use connection_read_proxy_handshake() to complete the handshake. */ int connection_proxy_connect(connection_t *conn, int type) { const or_options_t *options; tor_assert(conn); options = get_options(); switch (type) { case PROXY_CONNECT: { char buf[1024]; char *base64_authenticator=NULL; const char *authenticator = options->HTTPSProxyAuthenticator; /* Send HTTP CONNECT and authentication (if available) in * one request */ if (authenticator) { base64_authenticator = alloc_http_authenticator(authenticator); if (!base64_authenticator) log_warn(LD_OR, "Encoding https authenticator failed"); } if (base64_authenticator) { const char *addrport = fmt_addrport(&conn->addr, conn->port); tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.1\r\n" "Host: %s\r\n" "Proxy-Authorization: Basic %s\r\n\r\n", addrport, addrport, base64_authenticator); tor_free(base64_authenticator); } else { tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.0\r\n\r\n", fmt_addrport(&conn->addr, conn->port)); } connection_write_to_buf(buf, strlen(buf), conn); conn->proxy_state = PROXY_HTTPS_WANT_CONNECT_OK; break; } case PROXY_SOCKS4: { unsigned char buf[9]; uint16_t portn; uint32_t ip4addr; /* Send a SOCKS4 connect request with empty user id */ if (tor_addr_family(&conn->addr) != AF_INET) { log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6"); return -1; } ip4addr = tor_addr_to_ipv4n(&conn->addr); portn = htons(conn->port); buf[0] = 4; /* version */ buf[1] = SOCKS_COMMAND_CONNECT; /* command */ memcpy(buf + 2, &portn, 2); /* port */ memcpy(buf + 4, &ip4addr, 4); /* addr */ buf[8] = 0; /* userid (empty) */ connection_write_to_buf((char *)buf, sizeof(buf), conn); conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK; break; } case PROXY_SOCKS5: { unsigned char buf[4]; /* fields: vers, num methods, method list */ /* Send a SOCKS5 greeting (connect request must wait) */ buf[0] = 5; /* version */ /* number of auth methods */ if (options->Socks5ProxyUsername) { buf[1] = 2; buf[2] = 0x00; /* no authentication */ buf[3] = 0x02; /* rfc1929 Username/Passwd auth */ conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929; } else { buf[1] = 1; buf[2] = 0x00; /* no authentication */ conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_NONE; } connection_write_to_buf((char *)buf, 2 + buf[1], conn); break; } default: log_err(LD_BUG, "Invalid proxy protocol, %d", type); tor_fragile_assert(); return -1; } log_debug(LD_NET, "set state %s", connection_proxy_state_to_string(conn->proxy_state)); return 0; } /** Read conn's inbuf. If the http response from the proxy is all * here, make sure it's good news, then return 1. If it's bad news, * return -1. Else return 0 and hope for better luck next time. */ static int connection_read_https_proxy_response(connection_t *conn) { char *headers; char *reason=NULL; int status_code; time_t date_header; switch (fetch_from_buf_http(conn->inbuf, &headers, MAX_HEADERS_SIZE, NULL, NULL, 10000, 0)) { case -1: /* overflow */ log_warn(LD_PROTOCOL, "Your https proxy sent back an oversized response. Closing."); return -1; case 0: log_info(LD_NET,"https proxy response not all here yet. Waiting."); return 0; /* case 1, fall through */ } if (parse_http_response(headers, &status_code, &date_header, NULL, &reason) < 0) { log_warn(LD_NET, "Unparseable headers from proxy (connecting to '%s'). Closing.", conn->address); tor_free(headers); return -1; } tor_free(headers); if (!reason) reason = tor_strdup("[no reason given]"); if (status_code == 200) { log_info(LD_NET, "HTTPS connect to '%s' successful! (200 %s) Starting TLS.", conn->address, escaped(reason)); tor_free(reason); return 1; } /* else, bad news on the status code */ switch (status_code) { case 403: log_warn(LD_NET, "The https proxy refused to allow connection to %s " "(status code %d, %s). Closing.", conn->address, status_code, escaped(reason)); break; default: log_warn(LD_NET, "The https proxy sent back an unexpected status code %d (%s). " "Closing.", status_code, escaped(reason)); break; } tor_free(reason); return -1; } /** Send SOCKS5 CONNECT command to conn, copying conn->addr * and conn->port into the request. */ static void connection_send_socks5_connect(connection_t *conn) { unsigned char buf[1024]; size_t reqsize = 6; uint16_t port = htons(conn->port); buf[0] = 5; /* version */ buf[1] = SOCKS_COMMAND_CONNECT; /* command */ buf[2] = 0; /* reserved */ if (tor_addr_family(&conn->addr) == AF_INET) { uint32_t addr = tor_addr_to_ipv4n(&conn->addr); buf[3] = 1; reqsize += 4; memcpy(buf + 4, &addr, 4); memcpy(buf + 8, &port, 2); } else { /* AF_INET6 */ buf[3] = 4; reqsize += 16; memcpy(buf + 4, tor_addr_to_in6(&conn->addr), 16); memcpy(buf + 20, &port, 2); } connection_write_to_buf((char *)buf, reqsize, conn); conn->proxy_state = PROXY_SOCKS5_WANT_CONNECT_OK; } /** Wrapper around fetch_from_(buf/evbuffer)_socks_client: see those functions * for documentation of its behavior. */ static int connection_fetch_from_buf_socks_client(connection_t *conn, int state, char **reason) { IF_HAS_BUFFEREVENT(conn, { struct evbuffer *input = bufferevent_get_input(conn->bufev); return fetch_from_evbuffer_socks_client(input, state, reason); }) ELSE_IF_NO_BUFFEREVENT { return fetch_from_buf_socks_client(conn->inbuf, state, reason); } } /** Call this from connection_*_process_inbuf() to advance the proxy * handshake. * * No matter what proxy protocol is used, if this function returns 1, the * handshake is complete, and the data remaining on inbuf may contain the * start of the communication with the requested server. * * Returns 0 if the current buffer contains an incomplete response, and -1 * on error. */ int connection_read_proxy_handshake(connection_t *conn) { int ret = 0; char *reason = NULL; log_debug(LD_NET, "enter state %s", connection_proxy_state_to_string(conn->proxy_state)); switch (conn->proxy_state) { case PROXY_HTTPS_WANT_CONNECT_OK: ret = connection_read_https_proxy_response(conn); if (ret == 1) conn->proxy_state = PROXY_CONNECTED; break; case PROXY_SOCKS4_WANT_CONNECT_OK: ret = connection_fetch_from_buf_socks_client(conn, conn->proxy_state, &reason); if (ret == 1) conn->proxy_state = PROXY_CONNECTED; break; case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE: ret = connection_fetch_from_buf_socks_client(conn, conn->proxy_state, &reason); /* no auth needed, do connect */ if (ret == 1) { connection_send_socks5_connect(conn); ret = 0; } break; case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929: ret = connection_fetch_from_buf_socks_client(conn, conn->proxy_state, &reason); /* send auth if needed, otherwise do connect */ if (ret == 1) { connection_send_socks5_connect(conn); ret = 0; } else if (ret == 2) { unsigned char buf[1024]; size_t reqsize, usize, psize; const char *user, *pass; user = get_options()->Socks5ProxyUsername; pass = get_options()->Socks5ProxyPassword; tor_assert(user && pass); /* XXX len of user and pass must be <= 255 !!! */ usize = strlen(user); psize = strlen(pass); tor_assert(usize <= 255 && psize <= 255); reqsize = 3 + usize + psize; buf[0] = 1; /* negotiation version */ buf[1] = usize; memcpy(buf + 2, user, usize); buf[2 + usize] = psize; memcpy(buf + 3 + usize, pass, psize); connection_write_to_buf((char *)buf, reqsize, conn); conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_RFC1929_OK; ret = 0; } break; case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK: ret = connection_fetch_from_buf_socks_client(conn, conn->proxy_state, &reason); /* send the connect request */ if (ret == 1) { connection_send_socks5_connect(conn); ret = 0; } break; case PROXY_SOCKS5_WANT_CONNECT_OK: ret = connection_fetch_from_buf_socks_client(conn, conn->proxy_state, &reason); if (ret == 1) conn->proxy_state = PROXY_CONNECTED; break; default: log_err(LD_BUG, "Invalid proxy_state for reading, %d", conn->proxy_state); tor_fragile_assert(); ret = -1; break; } log_debug(LD_NET, "leaving state %s", connection_proxy_state_to_string(conn->proxy_state)); if (ret < 0) { if (reason) { log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d (%s)", conn->address, conn->port, escaped(reason)); tor_free(reason); } else { log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d", conn->address, conn->port); } } else if (ret == 1) { log_info(LD_NET, "Proxy Client: connection to %s:%d successful", conn->address, conn->port); } return ret; } /** Given a list of listener connections in old_conns, and list of * port_cfg_t entries in ports, open a new listener for every port in * ports that does not already have a listener in old_conns. * * Remove from old_conns every connection that has a corresponding * entry in ports. Add to new_conns new every connection we * launch. * * If control_listeners_only is true, then we only open control * listeners, and we do not remove any noncontrol listeners from old_conns. * * Return 0 on success, -1 on failure. **/ static int retry_listener_ports(smartlist_t *old_conns, const smartlist_t *ports, smartlist_t *new_conns, int control_listeners_only) { smartlist_t *launch = smartlist_new(); int r = 0; if (control_listeners_only) { SMARTLIST_FOREACH(ports, port_cfg_t *, p, { if (p->type == CONN_TYPE_CONTROL_LISTENER) smartlist_add(launch, p); }); } else { smartlist_add_all(launch, ports); } /* Iterate through old_conns, comparing it to launch: remove from both lists * each pair of elements that corresponds to the same port. */ SMARTLIST_FOREACH_BEGIN(old_conns, connection_t *, conn) { const port_cfg_t *found_port = NULL; /* Okay, so this is a listener. Is it configured? */ SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, wanted) { if (conn->type != wanted->type) continue; if ((conn->socket_family != AF_UNIX && wanted->is_unix_addr) || (conn->socket_family == AF_UNIX && ! wanted->is_unix_addr)) continue; if (wanted->no_listen) continue; /* We don't want to open a listener for this one */ if (wanted->is_unix_addr) { if (conn->socket_family == AF_UNIX && !strcmp(wanted->unix_addr, conn->address)) { found_port = wanted; break; } } else { int port_matches; if (wanted->port == CFG_AUTO_PORT) { port_matches = 1; } else { port_matches = (wanted->port == conn->port); } if (port_matches && tor_addr_eq(&wanted->addr, &conn->addr)) { found_port = wanted; break; } } } SMARTLIST_FOREACH_END(wanted); if (found_port) { /* This listener is already running; we don't need to launch it. */ //log_debug(LD_NET, "Already have %s on %s:%d", // conn_type_to_string(found_port->type), conn->address, conn->port); smartlist_remove(launch, found_port); /* And we can remove the connection from old_conns too. */ SMARTLIST_DEL_CURRENT(old_conns, conn); } } SMARTLIST_FOREACH_END(conn); /* Now open all the listeners that are configured but not opened. */ SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, port) { struct sockaddr *listensockaddr; socklen_t listensocklen = 0; char *address=NULL; connection_t *conn; int real_port = port->port == CFG_AUTO_PORT ? 0 : port->port; tor_assert(real_port <= UINT16_MAX); if (port->no_listen) continue; if (port->is_unix_addr) { listensockaddr = (struct sockaddr *) create_unix_sockaddr(port->unix_addr, &address, &listensocklen); } else { listensockaddr = tor_malloc(sizeof(struct sockaddr_storage)); listensocklen = tor_addr_to_sockaddr(&port->addr, real_port, listensockaddr, sizeof(struct sockaddr_storage)); address = tor_dup_addr(&port->addr); } if (listensockaddr) { conn = connection_listener_new(listensockaddr, listensocklen, port->type, address, port); tor_free(listensockaddr); tor_free(address); } else { conn = NULL; } if (!conn) { r = -1; } else { if (new_conns) smartlist_add(new_conns, conn); } } SMARTLIST_FOREACH_END(port); smartlist_free(launch); return r; } /** Launch listeners for each port you should have open. Only launch * listeners who are not already open, and only close listeners we no longer * want. * * Add all old conns that should be closed to replaced_conns. * Add all new connections to new_conns. * * If close_all_noncontrol is true, then we only open control * listeners, and we close all other listeners. */ int retry_all_listeners(smartlist_t *replaced_conns, smartlist_t *new_conns, int close_all_noncontrol) { smartlist_t *listeners = smartlist_new(); const or_options_t *options = get_options(); int retval = 0; const uint16_t old_or_port = router_get_advertised_or_port(options); const uint16_t old_or_port_ipv6 = router_get_advertised_or_port_by_af(options,AF_INET6); const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0); SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { if (connection_is_listener(conn) && !conn->marked_for_close) smartlist_add(listeners, conn); } SMARTLIST_FOREACH_END(conn); if (retry_listener_ports(listeners, get_configured_ports(), new_conns, close_all_noncontrol) < 0) retval = -1; /* Any members that were still in 'listeners' don't correspond to * any configured port. Kill 'em. */ SMARTLIST_FOREACH_BEGIN(listeners, connection_t *, conn) { log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d", conn_type_to_string(conn->type), conn->address, conn->port); if (replaced_conns) { smartlist_add(replaced_conns, conn); } else { connection_close_immediate(conn); connection_mark_for_close(conn); } } SMARTLIST_FOREACH_END(conn); smartlist_free(listeners); if (old_or_port != router_get_advertised_or_port(options) || old_or_port_ipv6 != router_get_advertised_or_port_by_af(options, AF_INET6) || old_dir_port != router_get_advertised_dir_port(options, 0)) { /* Our chosen ORPort or DirPort is not what it used to be: the * descriptor we had (if any) should be regenerated. (We won't * automatically notice this because of changes in the option, * since the value could be "auto".) */ mark_my_descriptor_dirty("Chosen Or/DirPort changed"); } return retval; } /** Mark every listener of type other than CONTROL_LISTENER to be closed. */ void connection_mark_all_noncontrol_listeners(void) { SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { if (conn->marked_for_close) continue; if (conn->type == CONN_TYPE_CONTROL_LISTENER) continue; if (connection_is_listener(conn)) connection_mark_for_close(conn); } SMARTLIST_FOREACH_END(conn); } /** Mark every external connection not used for controllers for close. */ void connection_mark_all_noncontrol_connections(void) { SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { if (conn->marked_for_close) continue; switch (conn->type) { case CONN_TYPE_CPUWORKER: case CONN_TYPE_CONTROL_LISTENER: case CONN_TYPE_CONTROL: break; case CONN_TYPE_AP: connection_mark_unattached_ap(TO_ENTRY_CONN(conn), END_STREAM_REASON_HIBERNATING); break; default: connection_mark_for_close(conn); break; } } SMARTLIST_FOREACH_END(conn); } /** Return 1 if we should apply rate limiting to conn, and 0 * otherwise. * Right now this just checks if it's an internal IP address or an * internal connection. We also should, but don't, check if the connection * uses pluggable transports, since we should then limit it even if it * comes from an internal IP address. */ static int connection_is_rate_limited(connection_t *conn) { const or_options_t *options = get_options(); if (conn->linked) return 0; /* Internal connection */ else if (! options->CountPrivateBandwidth && (tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */ tor_addr_is_internal(&conn->addr, 0))) return 0; /* Internal address */ else return 1; } #ifdef USE_BUFFEREVENTS static struct bufferevent_rate_limit_group *global_rate_limit = NULL; #else extern int global_read_bucket, global_write_bucket; extern int global_relayed_read_bucket, global_relayed_write_bucket; /** Did either global write bucket run dry last second? If so, * we are likely to run dry again this second, so be stingy with the * tokens we just put in. */ static int write_buckets_empty_last_second = 0; #endif /** How many seconds of no active local circuits will make the * connection revert to the "relayed" bandwidth class? */ #define CLIENT_IDLE_TIME_FOR_PRIORITY 30 #ifndef USE_BUFFEREVENTS /** Return 1 if conn should use tokens from the "relayed" * bandwidth rates, else 0. Currently, only OR conns with bandwidth * class 1, and directory conns that are serving data out, count. */ static int connection_counts_as_relayed_traffic(connection_t *conn, time_t now) { if (conn->type == CONN_TYPE_OR && connection_or_client_used(TO_OR_CONN(conn)) + CLIENT_IDLE_TIME_FOR_PRIORITY < now) return 1; if (conn->type == CONN_TYPE_DIR && DIR_CONN_IS_SERVER(conn)) return 1; return 0; } /** Helper function to decide how many bytes out of global_bucket * we're willing to use for this transaction. base is the size * of a cell on the network; priority says whether we should * write many of them or just a few; and conn_bucket (if * non-negative) provides an upper limit for our answer. */ static ssize_t connection_bucket_round_robin(int base, int priority, ssize_t global_bucket, ssize_t conn_bucket) { ssize_t at_most; ssize_t num_bytes_high = (priority ? 32 : 16) * base; ssize_t num_bytes_low = (priority ? 4 : 2) * base; /* Do a rudimentary round-robin so one circuit can't hog a connection. * Pick at most 32 cells, at least 4 cells if possible, and if we're in * the middle pick 1/8 of the available bandwidth. */ at_most = global_bucket / 8; at_most -= (at_most % base); /* round down */ if (at_most > num_bytes_high) /* 16 KB, or 8 KB for low-priority */ at_most = num_bytes_high; else if (at_most < num_bytes_low) /* 2 KB, or 1 KB for low-priority */ at_most = num_bytes_low; if (at_most > global_bucket) at_most = global_bucket; if (conn_bucket >= 0 && at_most > conn_bucket) at_most = conn_bucket; if (at_most < 0) return 0; return at_most; } /** How many bytes at most can we read onto this connection? */ static ssize_t connection_bucket_read_limit(connection_t *conn, time_t now) { int base = RELAY_PAYLOAD_SIZE; int priority = conn->type != CONN_TYPE_DIR; int conn_bucket = -1; int global_bucket = global_read_bucket; if (connection_speaks_cells(conn)) { or_connection_t *or_conn = TO_OR_CONN(conn); if (conn->state == OR_CONN_STATE_OPEN) conn_bucket = or_conn->read_bucket; base = get_cell_network_size(or_conn->wide_circ_ids); } if (!connection_is_rate_limited(conn)) { /* be willing to read on local conns even if our buckets are empty */ return conn_bucket>=0 ? conn_bucket : 1<<14; } if (connection_counts_as_relayed_traffic(conn, now) && global_relayed_read_bucket <= global_read_bucket) global_bucket = global_relayed_read_bucket; return connection_bucket_round_robin(base, priority, global_bucket, conn_bucket); } /** How many bytes at most can we write onto this connection? */ ssize_t connection_bucket_write_limit(connection_t *conn, time_t now) { int base = RELAY_PAYLOAD_SIZE; int priority = conn->type != CONN_TYPE_DIR; int conn_bucket = (int)conn->outbuf_flushlen; int global_bucket = global_write_bucket; if (!connection_is_rate_limited(conn)) { /* be willing to write to local conns even if our buckets are empty */ return conn->outbuf_flushlen; } if (connection_speaks_cells(conn)) { /* use the per-conn write limit if it's lower, but if it's less * than zero just use zero */ or_connection_t *or_conn = TO_OR_CONN(conn); if (conn->state == OR_CONN_STATE_OPEN) if (or_conn->write_bucket < conn_bucket) conn_bucket = or_conn->write_bucket >= 0 ? or_conn->write_bucket : 0; base = get_cell_network_size(or_conn->wide_circ_ids); } if (connection_counts_as_relayed_traffic(conn, now) && global_relayed_write_bucket <= global_write_bucket) global_bucket = global_relayed_write_bucket; return connection_bucket_round_robin(base, priority, global_bucket, conn_bucket); } #else static ssize_t connection_bucket_read_limit(connection_t *conn, time_t now) { (void) now; return bufferevent_get_max_to_read(conn->bufev); } ssize_t connection_bucket_write_limit(connection_t *conn, time_t now) { (void) now; return bufferevent_get_max_to_write(conn->bufev); } #endif /** Return 1 if the global write buckets are low enough that we * shouldn't send attempt bytes of low-priority directory stuff * out to conn. Else return 0. * Priority is 1 for v1 requests (directories and running-routers), * and 2 for v2 requests (statuses and descriptors). But see FFFF in * directory_handle_command_get() for why we don't use priority 2 yet. * * There are a lot of parameters we could use here: * - global_relayed_write_bucket. Low is bad. * - global_write_bucket. Low is bad. * - bandwidthrate. Low is bad. * - bandwidthburst. Not a big factor? * - attempt. High is bad. * - total bytes queued on outbufs. High is bad. But I'm wary of * using this, since a few slow-flushing queues will pump up the * number without meaning what we meant to mean. What we really * mean is "total directory bytes added to outbufs recently", but * that's harder to quantify and harder to keep track of. */ int global_write_bucket_low(connection_t *conn, size_t attempt, int priority) { #ifdef USE_BUFFEREVENTS ssize_t smaller_bucket = bufferevent_get_max_to_write(conn->bufev); #else int smaller_bucket = global_write_bucket < global_relayed_write_bucket ? global_write_bucket : global_relayed_write_bucket; #endif if (authdir_mode(get_options()) && priority>1) return 0; /* there's always room to answer v2 if we're an auth dir */ if (!connection_is_rate_limited(conn)) return 0; /* local conns don't get limited */ if (smaller_bucket < (int)attempt) return 1; /* not enough space no matter the priority */ #ifndef USE_BUFFEREVENTS if (write_buckets_empty_last_second) return 1; /* we're already hitting our limits, no more please */ #endif if (priority == 1) { /* old-style v1 query */ /* Could we handle *two* of these requests within the next two seconds? */ const or_options_t *options = get_options(); int64_t can_write = (int64_t)smaller_bucket + 2*(options->RelayBandwidthRate ? options->RelayBandwidthRate : options->BandwidthRate); if (can_write < 2*(int64_t)attempt) return 1; } else { /* v2 query */ /* no further constraints yet */ } return 0; } /** Helper: adjusts our bandwidth history and informs the controller as * appropriate, given that we have just read num_read bytes and written * num_written bytes on conn. */ static void record_num_bytes_transferred_impl(connection_t *conn, time_t now, size_t num_read, size_t num_written) { /* Count bytes of answering direct and tunneled directory requests */ if (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER) { if (num_read > 0) rep_hist_note_dir_bytes_read(num_read, now); if (num_written > 0) rep_hist_note_dir_bytes_written(num_written, now); } if (!connection_is_rate_limited(conn)) return; /* local IPs are free */ if (conn->type == CONN_TYPE_OR) rep_hist_note_or_conn_bytes(conn->global_identifier, num_read, num_written, now); if (num_read > 0) { rep_hist_note_bytes_read(num_read, now); } if (num_written > 0) { rep_hist_note_bytes_written(num_written, now); } if (conn->type == CONN_TYPE_EXIT) rep_hist_note_exit_bytes(conn->port, num_written, num_read); } #ifdef USE_BUFFEREVENTS /** Wrapper around fetch_from_(buf/evbuffer)_socks_client: see those functions * for documentation of its behavior. */ static void record_num_bytes_transferred(connection_t *conn, time_t now, size_t num_read, size_t num_written) { /* XXX024 check if this is necessary */ if (num_written >= INT_MAX || num_read >= INT_MAX) { log_err(LD_BUG, "Value out of range. num_read=%lu, num_written=%lu, " "connection type=%s, state=%s", (unsigned long)num_read, (unsigned long)num_written, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state)); if (num_written >= INT_MAX) num_written = 1; if (num_read >= INT_MAX) num_read = 1; tor_fragile_assert(); } record_num_bytes_transferred_impl(conn,now,num_read,num_written); } #endif #ifndef USE_BUFFEREVENTS /** We just read num_read and wrote num_written bytes * onto conn. Decrement buckets appropriately. */ static void connection_buckets_decrement(connection_t *conn, time_t now, size_t num_read, size_t num_written) { if (num_written >= INT_MAX || num_read >= INT_MAX) { log_err(LD_BUG, "Value out of range. num_read=%lu, num_written=%lu, " "connection type=%s, state=%s", (unsigned long)num_read, (unsigned long)num_written, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state)); if (num_written >= INT_MAX) num_written = 1; if (num_read >= INT_MAX) num_read = 1; tor_fragile_assert(); } record_num_bytes_transferred_impl(conn, now, num_read, num_written); if (!connection_is_rate_limited(conn)) return; /* local IPs are free */ if (connection_counts_as_relayed_traffic(conn, now)) { global_relayed_read_bucket -= (int)num_read; global_relayed_write_bucket -= (int)num_written; } global_read_bucket -= (int)num_read; global_write_bucket -= (int)num_written; if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) { TO_OR_CONN(conn)->read_bucket -= (int)num_read; TO_OR_CONN(conn)->write_bucket -= (int)num_written; } } /** If we have exhausted our global buckets, or the buckets for conn, * stop reading. */ static void connection_consider_empty_read_buckets(connection_t *conn) { const char *reason; if (global_read_bucket <= 0) { reason = "global read bucket exhausted. Pausing."; } else if (connection_counts_as_relayed_traffic(conn, approx_time()) && global_relayed_read_bucket <= 0) { reason = "global relayed read bucket exhausted. Pausing."; } else if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN && TO_OR_CONN(conn)->read_bucket <= 0) { reason = "connection read bucket exhausted. Pausing."; } else return; /* all good, no need to stop it */ if (conn->type == CONN_TYPE_CPUWORKER) return; /* Always okay. */ LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason)); conn->read_blocked_on_bw = 1; connection_stop_reading(conn); } /** If we have exhausted our global buckets, or the buckets for conn, * stop writing. */ static void connection_consider_empty_write_buckets(connection_t *conn) { const char *reason; if (global_write_bucket <= 0) { reason = "global write bucket exhausted. Pausing."; } else if (connection_counts_as_relayed_traffic(conn, approx_time()) && global_relayed_write_bucket <= 0) { reason = "global relayed write bucket exhausted. Pausing."; } else if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN && TO_OR_CONN(conn)->write_bucket <= 0) { reason = "connection write bucket exhausted. Pausing."; } else return; /* all good, no need to stop it */ if (conn->type == CONN_TYPE_CPUWORKER) return; /* Always okay. */ LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason)); conn->write_blocked_on_bw = 1; connection_stop_writing(conn); } /** Initialize the global read bucket to options-\>BandwidthBurst. */ void connection_bucket_init(void) { const or_options_t *options = get_options(); /* start it at max traffic */ global_read_bucket = (int)options->BandwidthBurst; global_write_bucket = (int)options->BandwidthBurst; if (options->RelayBandwidthRate) { global_relayed_read_bucket = (int)options->RelayBandwidthBurst; global_relayed_write_bucket = (int)options->RelayBandwidthBurst; } else { global_relayed_read_bucket = (int)options->BandwidthBurst; global_relayed_write_bucket = (int)options->BandwidthBurst; } } /** Refill a single bucket called name with bandwidth rate per * second rate and bandwidth burst burst, assuming that * milliseconds_elapsed milliseconds have passed since the last * call. */ static void connection_bucket_refill_helper(int *bucket, int rate, int burst, int milliseconds_elapsed, const char *name) { int starting_bucket = *bucket; if (starting_bucket < burst && milliseconds_elapsed > 0) { int64_t incr = (((int64_t)rate) * milliseconds_elapsed) / 1000; if ((burst - starting_bucket) < incr) { *bucket = burst; /* We would overflow the bucket; just set it to * the maximum. */ } else { *bucket += (int)incr; if (*bucket > burst || *bucket < starting_bucket) { /* If we overflow the burst, or underflow our starting bucket, * cap the bucket value to burst. */ /* XXXX this might be redundant now, but it doesn't show up * in profiles. Remove it after analysis. */ *bucket = burst; } } log_debug(LD_NET,"%s now %d.", name, *bucket); } } /** Time has passed; increment buckets appropriately. */ void connection_bucket_refill(int milliseconds_elapsed, time_t now) { const or_options_t *options = get_options(); smartlist_t *conns = get_connection_array(); int bandwidthrate, bandwidthburst, relayrate, relayburst; bandwidthrate = (int)options->BandwidthRate; bandwidthburst = (int)options->BandwidthBurst; if (options->RelayBandwidthRate) { relayrate = (int)options->RelayBandwidthRate; relayburst = (int)options->RelayBandwidthBurst; } else { relayrate = bandwidthrate; relayburst = bandwidthburst; } tor_assert(milliseconds_elapsed >= 0); write_buckets_empty_last_second = global_relayed_write_bucket <= 0 || global_write_bucket <= 0; /* refill the global buckets */ connection_bucket_refill_helper(&global_read_bucket, bandwidthrate, bandwidthburst, milliseconds_elapsed, "global_read_bucket"); connection_bucket_refill_helper(&global_write_bucket, bandwidthrate, bandwidthburst, milliseconds_elapsed, "global_write_bucket"); connection_bucket_refill_helper(&global_relayed_read_bucket, relayrate, relayburst, milliseconds_elapsed, "global_relayed_read_bucket"); connection_bucket_refill_helper(&global_relayed_write_bucket, relayrate, relayburst, milliseconds_elapsed, "global_relayed_write_bucket"); /* refill the per-connection buckets */ SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { if (connection_speaks_cells(conn)) { or_connection_t *or_conn = TO_OR_CONN(conn); int orbandwidthrate = or_conn->bandwidthrate; int orbandwidthburst = or_conn->bandwidthburst; if (connection_bucket_should_increase(or_conn->read_bucket, or_conn)) { connection_bucket_refill_helper(&or_conn->read_bucket, orbandwidthrate, orbandwidthburst, milliseconds_elapsed, "or_conn->read_bucket"); } if (connection_bucket_should_increase(or_conn->write_bucket, or_conn)) { connection_bucket_refill_helper(&or_conn->write_bucket, orbandwidthrate, orbandwidthburst, milliseconds_elapsed, "or_conn->write_bucket"); } } if (conn->read_blocked_on_bw == 1 /* marked to turn reading back on now */ && global_read_bucket > 0 /* and we're allowed to read */ && (!connection_counts_as_relayed_traffic(conn, now) || global_relayed_read_bucket > 0) /* even if we're relayed traffic */ && (!connection_speaks_cells(conn) || conn->state != OR_CONN_STATE_OPEN || TO_OR_CONN(conn)->read_bucket > 0)) { /* and either a non-cell conn or a cell conn with non-empty bucket */ LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET, "waking up conn (fd %d) for read", (int)conn->s)); conn->read_blocked_on_bw = 0; connection_start_reading(conn); } if (conn->write_blocked_on_bw == 1 && global_write_bucket > 0 /* and we're allowed to write */ && (!connection_counts_as_relayed_traffic(conn, now) || global_relayed_write_bucket > 0) /* even if it's relayed traffic */ && (!connection_speaks_cells(conn) || conn->state != OR_CONN_STATE_OPEN || TO_OR_CONN(conn)->write_bucket > 0)) { LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET, "waking up conn (fd %d) for write", (int)conn->s)); conn->write_blocked_on_bw = 0; connection_start_writing(conn); } } SMARTLIST_FOREACH_END(conn); } /** Is the bucket for connection conn low enough that we * should add another pile of tokens to it? */ static int connection_bucket_should_increase(int bucket, or_connection_t *conn) { tor_assert(conn); if (conn->base_.state != OR_CONN_STATE_OPEN) return 0; /* only open connections play the rate limiting game */ if (bucket >= conn->bandwidthburst) return 0; return 1; } #else static void connection_buckets_decrement(connection_t *conn, time_t now, size_t num_read, size_t num_written) { (void) conn; (void) now; (void) num_read; (void) num_written; /* Libevent does this for us. */ } void connection_bucket_refill(int seconds_elapsed, time_t now) { (void) seconds_elapsed; (void) now; /* Libevent does this for us. */ } void connection_bucket_init(void) { const or_options_t *options = get_options(); const struct timeval *tick = tor_libevent_get_one_tick_timeout(); struct ev_token_bucket_cfg *bucket_cfg; uint64_t rate, burst; if (options->RelayBandwidthRate) { rate = options->RelayBandwidthRate; burst = options->RelayBandwidthBurst; } else { rate = options->BandwidthRate; burst = options->BandwidthBurst; } /* This can't overflow, since TokenBucketRefillInterval <= 1000, * and rate started out less than INT32_MAX. */ rate = (rate * options->TokenBucketRefillInterval) / 1000; bucket_cfg = ev_token_bucket_cfg_new((uint32_t)rate, (uint32_t)burst, (uint32_t)rate, (uint32_t)burst, tick); if (!global_rate_limit) { global_rate_limit = bufferevent_rate_limit_group_new(tor_libevent_get_base(), bucket_cfg); } else { bufferevent_rate_limit_group_set_cfg(global_rate_limit, bucket_cfg); } ev_token_bucket_cfg_free(bucket_cfg); } void connection_get_rate_limit_totals(uint64_t *read_out, uint64_t *written_out) { if (global_rate_limit == NULL) { *read_out = *written_out = 0; } else { bufferevent_rate_limit_group_get_totals( global_rate_limit, read_out, written_out); } } /** Perform whatever operations are needed on conn to enable * rate-limiting. */ void connection_enable_rate_limiting(connection_t *conn) { if (conn->bufev) { if (!global_rate_limit) connection_bucket_init(); tor_add_bufferevent_to_rate_limit_group(conn->bufev, global_rate_limit); } } static void connection_consider_empty_write_buckets(connection_t *conn) { (void) conn; } static void connection_consider_empty_read_buckets(connection_t *conn) { (void) conn; } #endif /** Read bytes from conn-\>s and process them. * * It calls connection_read_to_buf() to bring in any new bytes, * and then calls connection_process_inbuf() to process them. * * Mark the connection and return -1 if you want to close it, else * return 0. */ static int connection_handle_read_impl(connection_t *conn) { ssize_t max_to_read=-1, try_to_read; size_t before, n_read = 0; int socket_error = 0; if (conn->marked_for_close) return 0; /* do nothing */ conn->timestamp_lastread = approx_time(); switch (conn->type) { case CONN_TYPE_OR_LISTENER: return connection_handle_listener_read(conn, CONN_TYPE_OR); case CONN_TYPE_AP_LISTENER: case CONN_TYPE_AP_TRANS_LISTENER: case CONN_TYPE_AP_NATD_LISTENER: return connection_handle_listener_read(conn, CONN_TYPE_AP); case CONN_TYPE_DIR_LISTENER: return connection_handle_listener_read(conn, CONN_TYPE_DIR); case CONN_TYPE_CONTROL_LISTENER: return connection_handle_listener_read(conn, CONN_TYPE_CONTROL); case CONN_TYPE_AP_DNS_LISTENER: /* This should never happen; eventdns.c handles the reads here. */ tor_fragile_assert(); return 0; } loop_again: try_to_read = max_to_read; tor_assert(!conn->marked_for_close); before = buf_datalen(conn->inbuf); if (connection_read_to_buf(conn, &max_to_read, &socket_error) < 0) { /* There's a read error; kill the connection.*/ if (conn->type == CONN_TYPE_OR) { connection_or_notify_error(TO_OR_CONN(conn), socket_error != 0 ? errno_to_orconn_end_reason(socket_error) : END_OR_CONN_REASON_CONNRESET, socket_error != 0 ? tor_socket_strerror(socket_error) : "(unknown, errno was 0)"); } if (CONN_IS_EDGE(conn)) { edge_connection_t *edge_conn = TO_EDGE_CONN(conn); connection_edge_end_errno(edge_conn); if (conn->type == CONN_TYPE_AP && TO_ENTRY_CONN(conn)->socks_request) { /* broken, don't send a socks reply back */ TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; } } connection_close_immediate(conn); /* Don't flush; connection is dead. */ /* * This can bypass normal channel checking since we did * connection_or_notify_error() above. */ connection_mark_for_close_internal(conn); return -1; } n_read += buf_datalen(conn->inbuf) - before; if (CONN_IS_EDGE(conn) && try_to_read != max_to_read) { /* instruct it not to try to package partial cells. */ if (connection_process_inbuf(conn, 0) < 0) { return -1; } if (!conn->marked_for_close && connection_is_reading(conn) && !conn->inbuf_reached_eof && max_to_read > 0) goto loop_again; /* try reading again, in case more is here now */ } /* one last try, packaging partial cells and all. */ if (!conn->marked_for_close && connection_process_inbuf(conn, 1) < 0) { return -1; } if (conn->linked_conn) { /* The other side's handle_write() will never actually get called, so * we need to invoke the appropriate callbacks ourself. */ connection_t *linked = conn->linked_conn; if (n_read) { /* Probably a no-op, since linked conns typically don't count for * bandwidth rate limiting. But do it anyway so we can keep stats * accurately. Note that since we read the bytes from conn, and * we're writing the bytes onto the linked connection, we count * these as written bytes. */ connection_buckets_decrement(linked, approx_time(), 0, n_read); if (connection_flushed_some(linked) < 0) connection_mark_for_close(linked); if (!connection_wants_to_flush(linked)) connection_finished_flushing(linked); } if (!buf_datalen(linked->outbuf) && conn->active_on_link) connection_stop_reading_from_linked_conn(conn); } /* If we hit the EOF, call connection_reached_eof(). */ if (!conn->marked_for_close && conn->inbuf_reached_eof && connection_reached_eof(conn) < 0) { return -1; } return 0; } /* DOCDOC connection_handle_read */ int connection_handle_read(connection_t *conn) { int res; tor_gettimeofday_cache_clear(); res = connection_handle_read_impl(conn); return res; } /** Pull in new bytes from conn-\>s or conn-\>linked_conn onto conn-\>inbuf, * either directly or via TLS. Reduce the token buckets by the number of bytes * read. * * If *max_to_read is -1, then decide it ourselves, else go with the * value passed to us. When returning, if it's changed, subtract the * number of bytes we read from *max_to_read. * * Return -1 if we want to break conn, else return 0. */ static int connection_read_to_buf(connection_t *conn, ssize_t *max_to_read, int *socket_error) { int result; ssize_t at_most = *max_to_read; size_t slack_in_buf, more_to_read; size_t n_read = 0, n_written = 0; if (at_most == -1) { /* we need to initialize it */ /* how many bytes are we allowed to read? */ at_most = connection_bucket_read_limit(conn, approx_time()); } slack_in_buf = buf_slack(conn->inbuf); again: if ((size_t)at_most > slack_in_buf && slack_in_buf >= 1024) { more_to_read = at_most - slack_in_buf; at_most = slack_in_buf; } else { more_to_read = 0; } if (connection_speaks_cells(conn) && conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) { int pending; or_connection_t *or_conn = TO_OR_CONN(conn); size_t initial_size; if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { /* continue handshaking even if global token bucket is empty */ return connection_tls_continue_handshake(or_conn); } log_debug(LD_NET, "%d: starting, inbuf_datalen %ld (%d pending in tls object)." " at_most %ld.", (int)conn->s,(long)buf_datalen(conn->inbuf), tor_tls_get_pending_bytes(or_conn->tls), (long)at_most); initial_size = buf_datalen(conn->inbuf); /* else open, or closing */ result = read_to_buf_tls(or_conn->tls, at_most, conn->inbuf); if (TOR_TLS_IS_ERROR(result) || result == TOR_TLS_CLOSE) or_conn->tls_error = result; else or_conn->tls_error = 0; switch (result) { case TOR_TLS_CLOSE: case TOR_TLS_ERROR_IO: log_debug(LD_NET,"TLS connection closed %son read. Closing. " "(Nickname %s, address %s)", result == TOR_TLS_CLOSE ? "cleanly " : "", or_conn->nickname ? or_conn->nickname : "not set", conn->address); return result; CASE_TOR_TLS_ERROR_ANY_NONIO: log_debug(LD_NET,"tls error [%s]. breaking (nickname %s, address %s).", tor_tls_err_to_string(result), or_conn->nickname ? or_conn->nickname : "not set", conn->address); return result; case TOR_TLS_WANTWRITE: connection_start_writing(conn); return 0; case TOR_TLS_WANTREAD: if (conn->in_connection_handle_write) { /* We've been invoked from connection_handle_write, because we're * waiting for a TLS renegotiation, the renegotiation started, and * SSL_read returned WANTWRITE. But now SSL_read is saying WANTREAD * again. Stop waiting for write events now, or else we'll * busy-loop until data arrives for us to read. */ connection_stop_writing(conn); if (!connection_is_reading(conn)) connection_start_reading(conn); } /* we're already reading, one hopes */ result = 0; break; case TOR_TLS_DONE: /* no data read, so nothing to process */ result = 0; break; /* so we call bucket_decrement below */ default: break; } pending = tor_tls_get_pending_bytes(or_conn->tls); if (pending) { /* If we have any pending bytes, we read them now. This *can* * take us over our read allotment, but really we shouldn't be * believing that SSL bytes are the same as TCP bytes anyway. */ int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf); if (r2<0) { log_warn(LD_BUG, "apparently, reading pending bytes can fail."); return -1; } } result = (int)(buf_datalen(conn->inbuf)-initial_size); tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written); log_debug(LD_GENERAL, "After TLS read of %d: %ld read, %ld written", result, (long)n_read, (long)n_written); } else if (conn->linked) { if (conn->linked_conn) { result = move_buf_to_buf(conn->inbuf, conn->linked_conn->outbuf, &conn->linked_conn->outbuf_flushlen); } else { result = 0; } //log_notice(LD_GENERAL, "Moved %d bytes on an internal link!", result); /* If the other side has disappeared, or if it's been marked for close and * we flushed its outbuf, then we should set our inbuf_reached_eof. */ if (!conn->linked_conn || (conn->linked_conn->marked_for_close && buf_datalen(conn->linked_conn->outbuf) == 0)) conn->inbuf_reached_eof = 1; n_read = (size_t) result; } else { /* !connection_speaks_cells, !conn->linked_conn. */ int reached_eof = 0; CONN_LOG_PROTECT(conn, result = read_to_buf(conn->s, at_most, conn->inbuf, &reached_eof, socket_error)); if (reached_eof) conn->inbuf_reached_eof = 1; // log_fn(LOG_DEBUG,"read_to_buf returned %d.",read_result); if (result < 0) return -1; n_read = (size_t) result; } if (n_read > 0) { /* change *max_to_read */ *max_to_read = at_most - n_read; /* Update edge_conn->n_read */ if (conn->type == CONN_TYPE_AP) { edge_connection_t *edge_conn = TO_EDGE_CONN(conn); /* Check for overflow: */ if (PREDICT_LIKELY(UINT32_MAX - edge_conn->n_read > n_read)) edge_conn->n_read += (int)n_read; else edge_conn->n_read = UINT32_MAX; } } connection_buckets_decrement(conn, approx_time(), n_read, n_written); if (more_to_read && result == at_most) { slack_in_buf = buf_slack(conn->inbuf); at_most = more_to_read; goto again; } /* Call even if result is 0, since the global read bucket may * have reached 0 on a different conn, and this guy needs to * know to stop reading. */ connection_consider_empty_read_buckets(conn); if (n_written > 0 && connection_is_writing(conn)) connection_consider_empty_write_buckets(conn); return 0; } #ifdef USE_BUFFEREVENTS /* XXXX These generic versions could be simplified by making them type-specific */ /** Callback: Invoked whenever bytes are added to or drained from an input * evbuffer. Used to track the number of bytes read. */ static void evbuffer_inbuf_callback(struct evbuffer *buf, const struct evbuffer_cb_info *info, void *arg) { connection_t *conn = arg; (void) buf; /* XXXX These need to get real counts on the non-nested TLS case. - NM */ if (info->n_added) { time_t now = approx_time(); conn->timestamp_lastread = now; record_num_bytes_transferred(conn, now, info->n_added, 0); connection_consider_empty_read_buckets(conn); if (conn->type == CONN_TYPE_AP) { edge_connection_t *edge_conn = TO_EDGE_CONN(conn); /*XXXX024 check for overflow*/ edge_conn->n_read += (int)info->n_added; } } } /** Callback: Invoked whenever bytes are added to or drained from an output * evbuffer. Used to track the number of bytes written. */ static void evbuffer_outbuf_callback(struct evbuffer *buf, const struct evbuffer_cb_info *info, void *arg) { connection_t *conn = arg; (void)buf; if (info->n_deleted) { time_t now = approx_time(); conn->timestamp_lastwritten = now; record_num_bytes_transferred(conn, now, 0, info->n_deleted); connection_consider_empty_write_buckets(conn); if (conn->type == CONN_TYPE_AP) { edge_connection_t *edge_conn = TO_EDGE_CONN(conn); /*XXXX024 check for overflow*/ edge_conn->n_written += (int)info->n_deleted; } } } /** Callback: invoked whenever a bufferevent has read data. */ void connection_handle_read_cb(struct bufferevent *bufev, void *arg) { connection_t *conn = arg; (void) bufev; if (!conn->marked_for_close) { if (connection_process_inbuf(conn, 1)<0) /* XXXX Always 1? */ if (!conn->marked_for_close) connection_mark_for_close(conn); } } /** Callback: invoked whenever a bufferevent has written data. */ void connection_handle_write_cb(struct bufferevent *bufev, void *arg) { connection_t *conn = arg; struct evbuffer *output; if (connection_flushed_some(conn)<0) { if (!conn->marked_for_close) connection_mark_for_close(conn); return; } output = bufferevent_get_output(bufev); if (!evbuffer_get_length(output)) { connection_finished_flushing(conn); if (conn->marked_for_close && conn->hold_open_until_flushed) { conn->hold_open_until_flushed = 0; if (conn->linked) { /* send eof */ bufferevent_flush(conn->bufev, EV_WRITE, BEV_FINISHED); } } } } /** Callback: invoked whenever a bufferevent has had an event (like a * connection, or an eof, or an error) occur. */ void connection_handle_event_cb(struct bufferevent *bufev, short event, void *arg) { connection_t *conn = arg; (void) bufev; if (conn->marked_for_close) return; if (event & BEV_EVENT_CONNECTED) { tor_assert(connection_state_is_connecting(conn)); if (connection_finished_connecting(conn)<0) return; } if (event & BEV_EVENT_EOF) { if (!conn->marked_for_close) { conn->inbuf_reached_eof = 1; if (connection_reached_eof(conn)<0) return; } } if (event & BEV_EVENT_ERROR) { int socket_error = evutil_socket_geterror(conn->s); if (conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_CONNECTING) { connection_or_connect_failed(TO_OR_CONN(conn), errno_to_orconn_end_reason(socket_error), tor_socket_strerror(socket_error)); } else if (CONN_IS_EDGE(conn)) { edge_connection_t *edge_conn = TO_EDGE_CONN(conn); if (!edge_conn->edge_has_sent_end) connection_edge_end_errno(edge_conn); if (conn->type == CONN_TYPE_AP && TO_ENTRY_CONN(conn)->socks_request) { /* broken, don't send a socks reply back */ TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; } } connection_close_immediate(conn); /* Connection is dead. */ if (!conn->marked_for_close) connection_mark_for_close(conn); } } /** Set up the generic callbacks for the bufferevent on conn. */ void connection_configure_bufferevent_callbacks(connection_t *conn) { struct bufferevent *bufev; struct evbuffer *input, *output; tor_assert(conn->bufev); bufev = conn->bufev; bufferevent_setcb(bufev, connection_handle_read_cb, connection_handle_write_cb, connection_handle_event_cb, conn); /* Set a fairly high write low-watermark so that we get the write callback called whenever data is written to bring us under 128K. Leave the high-watermark at 0. */ bufferevent_setwatermark(bufev, EV_WRITE, 128*1024, 0); input = bufferevent_get_input(bufev); output = bufferevent_get_output(bufev); evbuffer_add_cb(input, evbuffer_inbuf_callback, conn); evbuffer_add_cb(output, evbuffer_outbuf_callback, conn); } #endif /** A pass-through to fetch_from_buf. */ int connection_fetch_from_buf(char *string, size_t len, connection_t *conn) { IF_HAS_BUFFEREVENT(conn, { /* XXX overflow -seb */ return (int)bufferevent_read(conn->bufev, string, len); }) ELSE_IF_NO_BUFFEREVENT { return fetch_from_buf(string, len, conn->inbuf); } } /** As fetch_from_buf_line(), but read from a connection's input buffer. */ int connection_fetch_from_buf_line(connection_t *conn, char *data, size_t *data_len) { IF_HAS_BUFFEREVENT(conn, { int r; size_t eol_len=0; struct evbuffer *input = bufferevent_get_input(conn->bufev); struct evbuffer_ptr ptr = evbuffer_search_eol(input, NULL, &eol_len, EVBUFFER_EOL_LF); if (ptr.pos == -1) return 0; /* No EOL found. */ if ((size_t)ptr.pos+eol_len >= *data_len) { return -1; /* Too long */ } *data_len = ptr.pos+eol_len; r = evbuffer_remove(input, data, ptr.pos+eol_len); tor_assert(r >= 0); data[ptr.pos+eol_len] = '\0'; return 1; }) ELSE_IF_NO_BUFFEREVENT { return fetch_from_buf_line(conn->inbuf, data, data_len); } } /** As fetch_from_buf_http, but fetches from a conncetion's input buffer_t or * its bufferevent as appropriate. */ int connection_fetch_from_buf_http(connection_t *conn, char **headers_out, size_t max_headerlen, char **body_out, size_t *body_used, size_t max_bodylen, int force_complete) { IF_HAS_BUFFEREVENT(conn, { struct evbuffer *input = bufferevent_get_input(conn->bufev); return fetch_from_evbuffer_http(input, headers_out, max_headerlen, body_out, body_used, max_bodylen, force_complete); }) ELSE_IF_NO_BUFFEREVENT { return fetch_from_buf_http(conn->inbuf, headers_out, max_headerlen, body_out, body_used, max_bodylen, force_complete); } } /** Return conn-\>outbuf_flushlen: how many bytes conn wants to flush * from its outbuf. */ int connection_wants_to_flush(connection_t *conn) { return conn->outbuf_flushlen > 0; } /** Are there too many bytes on edge connection conn's outbuf to * send back a relay-level sendme yet? Return 1 if so, 0 if not. Used by * connection_edge_consider_sending_sendme(). */ int connection_outbuf_too_full(connection_t *conn) { return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE); } /** Try to flush more bytes onto conn-\>s. * * This function gets called either from conn_write() in main.c * when poll() has declared that conn wants to write, or below * from connection_write_to_buf() when an entire TLS record is ready. * * Update conn-\>timestamp_lastwritten to now, and call flush_buf * or flush_buf_tls appropriately. If it succeeds and there are no more * more bytes on conn-\>outbuf, then call connection_finished_flushing * on it too. * * If force, then write as many bytes as possible, ignoring bandwidth * limits. (Used for flushing messages to controller connections on fatal * errors.) * * Mark the connection and return -1 if you want to close it, else * return 0. */ static int connection_handle_write_impl(connection_t *conn, int force) { int e; socklen_t len=(socklen_t)sizeof(e); int result; ssize_t max_to_write; time_t now = approx_time(); size_t n_read = 0, n_written = 0; int dont_stop_writing = 0; tor_assert(!connection_is_listener(conn)); if (conn->marked_for_close || !SOCKET_OK(conn->s)) return 0; /* do nothing */ if (conn->in_flushed_some) { log_warn(LD_BUG, "called recursively from inside conn->in_flushed_some"); return 0; } conn->timestamp_lastwritten = now; /* Sometimes, "writable" means "connected". */ if (connection_state_is_connecting(conn)) { if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { log_warn(LD_BUG, "getsockopt() syscall failed"); if (CONN_IS_EDGE(conn)) connection_edge_end_errno(TO_EDGE_CONN(conn)); connection_mark_for_close(conn); return -1; } if (e) { /* some sort of error, but maybe just inprogress still */ if (!ERRNO_IS_CONN_EINPROGRESS(e)) { log_info(LD_NET,"in-progress connect failed. Removing. (%s)", tor_socket_strerror(e)); if (CONN_IS_EDGE(conn)) connection_edge_end_errno(TO_EDGE_CONN(conn)); if (conn->type == CONN_TYPE_OR) connection_or_notify_error(TO_OR_CONN(conn), errno_to_orconn_end_reason(e), tor_socket_strerror(e)); connection_close_immediate(conn); /* * This can bypass normal channel checking since we did * connection_or_notify_error() above. */ connection_mark_for_close_internal(conn); return -1; } else { return 0; /* no change, see if next time is better */ } } /* The connection is successful. */ if (connection_finished_connecting(conn)<0) return -1; } max_to_write = force ? (ssize_t)conn->outbuf_flushlen : connection_bucket_write_limit(conn, now); if (connection_speaks_cells(conn) && conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) { or_connection_t *or_conn = TO_OR_CONN(conn); size_t initial_size; if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { connection_stop_writing(conn); if (connection_tls_continue_handshake(or_conn) < 0) { /* Don't flush; connection is dead. */ connection_or_notify_error(or_conn, END_OR_CONN_REASON_MISC, "TLS error in connection_tls_" "continue_handshake()"); connection_close_immediate(conn); /* * This can bypass normal channel checking since we did * connection_or_notify_error() above. */ connection_mark_for_close_internal(conn); return -1; } return 0; } else if (conn->state == OR_CONN_STATE_TLS_SERVER_RENEGOTIATING) { return connection_handle_read(conn); } /* else open, or closing */ initial_size = buf_datalen(conn->outbuf); result = flush_buf_tls(or_conn->tls, conn->outbuf, max_to_write, &conn->outbuf_flushlen); /* If we just flushed the last bytes, tell the channel on the * or_conn to check if it needs to geoip_change_dirreq_state() */ /* XXXX move this to flushed_some or finished_flushing -NM */ if (buf_datalen(conn->outbuf) == 0 && or_conn->chan) channel_notify_flushed(TLS_CHAN_TO_BASE(or_conn->chan)); switch (result) { CASE_TOR_TLS_ERROR_ANY: case TOR_TLS_CLOSE: log_info(LD_NET, result != TOR_TLS_CLOSE ? "tls error. breaking.":"TLS connection closed on flush"); /* Don't flush; connection is dead. */ connection_or_notify_error(or_conn, END_OR_CONN_REASON_MISC, result != TOR_TLS_CLOSE ? "TLS error in during flush" : "TLS closed during flush"); connection_close_immediate(conn); /* * This can bypass normal channel checking since we did * connection_or_notify_error() above. */ connection_mark_for_close_internal(conn); return -1; case TOR_TLS_WANTWRITE: log_debug(LD_NET,"wanted write."); /* we're already writing */ dont_stop_writing = 1; break; case TOR_TLS_WANTREAD: /* Make sure to avoid a loop if the receive buckets are empty. */ log_debug(LD_NET,"wanted read."); if (!connection_is_reading(conn)) { connection_stop_writing(conn); conn->write_blocked_on_bw = 1; /* we'll start reading again when we get more tokens in our * read bucket; then we'll start writing again too. */ } /* else no problem, we're already reading */ return 0; /* case TOR_TLS_DONE: * for TOR_TLS_DONE, fall through to check if the flushlen * is empty, so we can stop writing. */ } tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written); log_debug(LD_GENERAL, "After TLS write of %d: %ld read, %ld written", result, (long)n_read, (long)n_written); /* So we notice bytes were written even on error */ /* XXXX024 This cast is safe since we can never write INT_MAX bytes in a * single set of TLS operations. But it looks kinda ugly. If we refactor * the *_buf_tls functions, we should make them return ssize_t or size_t * or something. */ result = (int)(initial_size-buf_datalen(conn->outbuf)); } else { CONN_LOG_PROTECT(conn, result = flush_buf(conn->s, conn->outbuf, max_to_write, &conn->outbuf_flushlen)); if (result < 0) { if (CONN_IS_EDGE(conn)) connection_edge_end_errno(TO_EDGE_CONN(conn)); if (conn->type == CONN_TYPE_AP) { /* writing failed; we couldn't send a SOCKS reply if we wanted to */ TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; } connection_close_immediate(conn); /* Don't flush; connection is dead. */ connection_mark_for_close(conn); return -1; } n_written = (size_t) result; } if (n_written && conn->type == CONN_TYPE_AP) { edge_connection_t *edge_conn = TO_EDGE_CONN(conn); /* Check for overflow: */ if (PREDICT_LIKELY(UINT32_MAX - edge_conn->n_written > n_written)) edge_conn->n_written += (int)n_written; else edge_conn->n_written = UINT32_MAX; } connection_buckets_decrement(conn, approx_time(), n_read, n_written); if (result > 0) { /* If we wrote any bytes from our buffer, then call the appropriate * functions. */ if (connection_flushed_some(conn) < 0) { if (connection_speaks_cells(conn)) { connection_or_notify_error(TO_OR_CONN(conn), END_OR_CONN_REASON_MISC, "Got error back from " "connection_flushed_some()"); } /* * This can bypass normal channel checking since we did * connection_or_notify_error() above. */ connection_mark_for_close_internal(conn); } } if (!connection_wants_to_flush(conn) && !dont_stop_writing) { /* it's done flushing */ if (connection_finished_flushing(conn) < 0) { /* already marked */ return -1; } return 0; } /* Call even if result is 0, since the global write bucket may * have reached 0 on a different conn, and this guy needs to * know to stop writing. */ connection_consider_empty_write_buckets(conn); if (n_read > 0 && connection_is_reading(conn)) connection_consider_empty_read_buckets(conn); return 0; } /* DOCDOC connection_handle_write */ int connection_handle_write(connection_t *conn, int force) { int res; tor_gettimeofday_cache_clear(); conn->in_connection_handle_write = 1; res = connection_handle_write_impl(conn, force); conn->in_connection_handle_write = 0; return res; } /** * Try to flush data that's waiting for a write on conn. Return * -1 on failure, 0 on success. * * Don't use this function for regular writing; the buffers/bufferevents * system should be good enough at scheduling writes there. Instead, this * function is for cases when we're about to exit or something and we want * to report it right away. */ int connection_flush(connection_t *conn) { IF_HAS_BUFFEREVENT(conn, { int r = bufferevent_flush(conn->bufev, EV_WRITE, BEV_FLUSH); return (r < 0) ? -1 : 0; }); return connection_handle_write(conn, 1); } /** Append len bytes of string onto conn's * outbuf, and ask it to start writing. * * If zlib is nonzero, this is a directory connection that should get * its contents compressed or decompressed as they're written. If zlib is * negative, this is the last data to be compressed, and the connection's zlib * state should be flushed. * * If it's a local control connection and a 64k chunk is ready, try to flush * it all, so we don't end up with many megabytes of controller info queued at * once. */ void connection_write_to_buf_impl_(const char *string, size_t len, connection_t *conn, int zlib) { /* XXXX This function really needs to return -1 on failure. */ int r; size_t old_datalen; if (!len && !(zlib<0)) return; /* if it's marked for close, only allow write if we mean to flush it */ if (conn->marked_for_close && !conn->hold_open_until_flushed) return; IF_HAS_BUFFEREVENT(conn, { if (zlib) { int done = zlib < 0; r = write_to_evbuffer_zlib(bufferevent_get_output(conn->bufev), TO_DIR_CONN(conn)->zlib_state, string, len, done); } else { r = bufferevent_write(conn->bufev, string, len); } if (r < 0) { /* XXXX mark for close? */ log_warn(LD_NET, "bufferevent_write failed! That shouldn't happen."); } return; }); old_datalen = buf_datalen(conn->outbuf); if (zlib) { dir_connection_t *dir_conn = TO_DIR_CONN(conn); int done = zlib < 0; CONN_LOG_PROTECT(conn, r = write_to_buf_zlib(conn->outbuf, dir_conn->zlib_state, string, len, done)); } else { CONN_LOG_PROTECT(conn, r = write_to_buf(string, len, conn->outbuf)); } if (r < 0) { if (CONN_IS_EDGE(conn)) { /* if it failed, it means we have our package/delivery windows set wrong compared to our max outbuf size. close the whole circuit. */ log_warn(LD_NET, "write_to_buf failed. Closing circuit (fd %d).", (int)conn->s); circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)), END_CIRC_REASON_INTERNAL); } else { log_warn(LD_NET, "write_to_buf failed. Closing connection (fd %d).", (int)conn->s); connection_mark_for_close(conn); } return; } /* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING * state, we don't want to try to write it right away, since * conn->write_event won't be set yet. Otherwise, write data from * this conn as the socket is available. */ if (conn->write_event) { connection_start_writing(conn); } if (zlib) { conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen; } else { conn->outbuf_flushlen += len; /* Should we try flushing the outbuf now? */ if (conn->in_flushed_some) { /* Don't flush the outbuf when the reason we're writing more stuff is * _because_ we flushed the outbuf. That's unfair. */ return; } if (conn->type == CONN_TYPE_CONTROL && !connection_is_rate_limited(conn) && conn->outbuf_flushlen-len < 1<<16 && conn->outbuf_flushlen >= 1<<16) { /* just try to flush all of it */ } else return; /* no need to try flushing */ if (connection_handle_write(conn, 0) < 0) { if (!conn->marked_for_close) { /* this connection is broken. remove it. */ log_warn(LD_BUG, "unhandled error on write for " "conn (type %d, fd %d); removing", conn->type, (int)conn->s); tor_fragile_assert(); /* do a close-immediate here, so we don't try to flush */ connection_close_immediate(conn); } return; } } } /** Return a connection with given type, address, port, and purpose; * or NULL if no such connection exists. */ connection_t * connection_get_by_type_addr_port_purpose(int type, const tor_addr_t *addr, uint16_t port, int purpose) { smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->type == type && tor_addr_eq(&conn->addr, addr) && conn->port == port && conn->purpose == purpose && !conn->marked_for_close) return conn; }); return NULL; } /** Return the stream with id id if it is not already marked for * close. */ connection_t * connection_get_by_global_id(uint64_t id) { smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->global_identifier == id) return conn; }); return NULL; } /** Return a connection of type type that is not marked for close. */ connection_t * connection_get_by_type(int type) { smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->type == type && !conn->marked_for_close) return conn; }); return NULL; } /** Return a connection of type type that is in state state, * and that is not marked for close. */ connection_t * connection_get_by_type_state(int type, int state) { smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->type == type && conn->state == state && !conn->marked_for_close) return conn; }); return NULL; } /** Return a connection of type type that has rendquery equal * to rendquery, and that is not marked for close. If state * is non-zero, conn must be of that state too. */ connection_t * connection_get_by_type_state_rendquery(int type, int state, const char *rendquery) { smartlist_t *conns = get_connection_array(); tor_assert(type == CONN_TYPE_DIR || type == CONN_TYPE_AP || type == CONN_TYPE_EXIT); tor_assert(rendquery); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { if (conn->type == type && !conn->marked_for_close && (!state || state == conn->state)) { if (type == CONN_TYPE_DIR && TO_DIR_CONN(conn)->rend_data && !rend_cmp_service_ids(rendquery, TO_DIR_CONN(conn)->rend_data->onion_address)) return conn; else if (CONN_IS_EDGE(conn) && TO_EDGE_CONN(conn)->rend_data && !rend_cmp_service_ids(rendquery, TO_EDGE_CONN(conn)->rend_data->onion_address)) return conn; } } SMARTLIST_FOREACH_END(conn); return NULL; } /** Return a directory connection (if any one exists) that is fetching * the item described by state/resource */ dir_connection_t * connection_dir_get_by_purpose_and_resource(int purpose, const char *resource) { smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { dir_connection_t *dirconn; if (conn->type != CONN_TYPE_DIR || conn->marked_for_close || conn->purpose != purpose) continue; dirconn = TO_DIR_CONN(conn); if (dirconn->requested_resource == NULL) { if (resource == NULL) return dirconn; } else if (resource) { if (0 == strcmp(resource, dirconn->requested_resource)) return dirconn; } } SMARTLIST_FOREACH_END(conn); return NULL; } /** Return an open, non-marked connection of a given type and purpose, or NULL * if no such connection exists. */ connection_t * connection_get_by_type_purpose(int type, int purpose) { smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH(conns, connection_t *, conn, { if (conn->type == type && !conn->marked_for_close && (purpose == conn->purpose)) return conn; }); return NULL; } /** Return 1 if conn is a listener conn, else return 0. */ int connection_is_listener(connection_t *conn) { if (conn->type == CONN_TYPE_OR_LISTENER || conn->type == CONN_TYPE_AP_LISTENER || conn->type == CONN_TYPE_AP_TRANS_LISTENER || conn->type == CONN_TYPE_AP_DNS_LISTENER || conn->type == CONN_TYPE_AP_NATD_LISTENER || conn->type == CONN_TYPE_DIR_LISTENER || conn->type == CONN_TYPE_CONTROL_LISTENER) return 1; return 0; } /** Return 1 if conn is in state "open" and is not marked * for close, else return 0. */ int connection_state_is_open(connection_t *conn) { tor_assert(conn); if (conn->marked_for_close) return 0; if ((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) || (conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) || (conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN) || (conn->type == CONN_TYPE_CONTROL && conn->state == CONTROL_CONN_STATE_OPEN)) return 1; return 0; } /** Return 1 if conn is in 'connecting' state, else return 0. */ int connection_state_is_connecting(connection_t *conn) { tor_assert(conn); if (conn->marked_for_close) return 0; switch (conn->type) { case CONN_TYPE_OR: return conn->state == OR_CONN_STATE_CONNECTING; case CONN_TYPE_EXIT: return conn->state == EXIT_CONN_STATE_CONNECTING; case CONN_TYPE_DIR: return conn->state == DIR_CONN_STATE_CONNECTING; } return 0; } /** Allocates a base64'ed authenticator for use in http or https * auth, based on the input string authenticator. Returns it * if success, else returns NULL. */ char * alloc_http_authenticator(const char *authenticator) { /* an authenticator in Basic authentication * is just the string "username:password" */ const size_t authenticator_length = strlen(authenticator); /* The base64_encode function needs a minimum buffer length * of 66 bytes. */ const size_t base64_authenticator_length = (authenticator_length/48+1)*66; char *base64_authenticator = tor_malloc(base64_authenticator_length); if (base64_encode(base64_authenticator, base64_authenticator_length, authenticator, authenticator_length) < 0) { tor_free(base64_authenticator); /* free and set to null */ } else { int i = 0, j = 0; ssize_t len = strlen(base64_authenticator); /* remove all newline occurrences within the string */ for (i=0; i < len; ++i) { if ('\n' != base64_authenticator[i]) { base64_authenticator[j] = base64_authenticator[i]; ++j; } } base64_authenticator[j]='\0'; } return base64_authenticator; } /** Given a socket handle, check whether the local address (sockname) of the * socket is one that we've connected from before. If so, double-check * whether our address has changed and we need to generate keys. If we do, * call init_keys(). */ static void client_check_address_changed(tor_socket_t sock) { struct sockaddr_storage out_sockaddr; socklen_t out_addr_len = (socklen_t) sizeof(out_sockaddr); tor_addr_t out_addr, iface_addr; tor_addr_t **last_interface_ip_ptr; sa_family_t family; if (!outgoing_addrs) outgoing_addrs = smartlist_new(); if (getsockname(sock, (struct sockaddr*)&out_sockaddr, &out_addr_len)<0) { int e = tor_socket_errno(sock); log_warn(LD_NET, "getsockname() to check for address change failed: %s", tor_socket_strerror(e)); return; } tor_addr_from_sockaddr(&out_addr, (struct sockaddr*)&out_sockaddr, NULL); family = tor_addr_family(&out_addr); if (family == AF_INET) last_interface_ip_ptr = &last_interface_ipv4; else if (family == AF_INET6) last_interface_ip_ptr = &last_interface_ipv6; else return; if (! *last_interface_ip_ptr) { tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t)); if (get_interface_address6(LOG_INFO, family, a)==0) { *last_interface_ip_ptr = a; } else { tor_free(a); } } /* If we've used this address previously, we're okay. */ SMARTLIST_FOREACH(outgoing_addrs, const tor_addr_t *, a_ptr, if (tor_addr_eq(a_ptr, &out_addr)) return; ); /* Uh-oh. We haven't connected from this address before. Has the interface * address changed? */ if (get_interface_address6(LOG_INFO, family, &iface_addr)<0) return; if (tor_addr_eq(&iface_addr, *last_interface_ip_ptr)) { /* Nope, it hasn't changed. Add this address to the list. */ smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t))); } else { /* The interface changed. We're a client, so we need to regenerate our * keys. First, reset the state. */ log_notice(LD_NET, "Our IP address has changed. Rotating keys..."); tor_addr_copy(*last_interface_ip_ptr, &iface_addr); SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t*, a_ptr, tor_free(a_ptr)); smartlist_clear(outgoing_addrs); smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t))); /* Okay, now change our keys. */ ip_address_changed(1); } } /** Some systems have limited system buffers for recv and xmit on * sockets allocated in a virtual server or similar environment. For a Tor * server this can produce the "Error creating network socket: No buffer * space available" error once all available TCP buffer space is consumed. * This method will attempt to constrain the buffers allocated for the socket * to the desired size to stay below system TCP buffer limits. */ static void set_constrained_socket_buffers(tor_socket_t sock, int size) { void *sz = (void*)&size; socklen_t sz_sz = (socklen_t) sizeof(size); if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, sz, sz_sz) < 0) { int e = tor_socket_errno(sock); log_warn(LD_NET, "setsockopt() to constrain send " "buffer to %d bytes failed: %s", size, tor_socket_strerror(e)); } if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, sz, sz_sz) < 0) { int e = tor_socket_errno(sock); log_warn(LD_NET, "setsockopt() to constrain recv " "buffer to %d bytes failed: %s", size, tor_socket_strerror(e)); } } /** Process new bytes that have arrived on conn-\>inbuf. * * This function just passes conn to the connection-specific * connection_*_process_inbuf() function. It also passes in * package_partial if wanted. */ static int connection_process_inbuf(connection_t *conn, int package_partial) { tor_assert(conn); switch (conn->type) { case CONN_TYPE_OR: return connection_or_process_inbuf(TO_OR_CONN(conn)); case CONN_TYPE_EXIT: case CONN_TYPE_AP: return connection_edge_process_inbuf(TO_EDGE_CONN(conn), package_partial); case CONN_TYPE_DIR: return connection_dir_process_inbuf(TO_DIR_CONN(conn)); case CONN_TYPE_CPUWORKER: return connection_cpu_process_inbuf(conn); case CONN_TYPE_CONTROL: return connection_control_process_inbuf(TO_CONTROL_CONN(conn)); default: log_err(LD_BUG,"got unexpected conn type %d.", conn->type); tor_fragile_assert(); return -1; } } /** Called whenever we've written data on a connection. */ static int connection_flushed_some(connection_t *conn) { int r = 0; tor_assert(!conn->in_flushed_some); conn->in_flushed_some = 1; if (conn->type == CONN_TYPE_DIR && conn->state == DIR_CONN_STATE_SERVER_WRITING) { r = connection_dirserv_flushed_some(TO_DIR_CONN(conn)); } else if (conn->type == CONN_TYPE_OR) { r = connection_or_flushed_some(TO_OR_CONN(conn)); } else if (CONN_IS_EDGE(conn)) { r = connection_edge_flushed_some(TO_EDGE_CONN(conn)); } conn->in_flushed_some = 0; return r; } /** We just finished flushing bytes to the appropriately low network layer, * and there are no more bytes remaining in conn-\>outbuf, conn-\>bev, or * conn-\>tls to be flushed. * * This function just passes conn to the connection-specific * connection_*_finished_flushing() function. */ static int connection_finished_flushing(connection_t *conn) { tor_assert(conn); /* If the connection is closed, don't try to do anything more here. */ if (CONN_IS_CLOSED(conn)) return 0; // log_fn(LOG_DEBUG,"entered. Socket %u.", conn->s); IF_HAS_NO_BUFFEREVENT(conn) connection_stop_writing(conn); switch (conn->type) { case CONN_TYPE_OR: return connection_or_finished_flushing(TO_OR_CONN(conn)); case CONN_TYPE_AP: case CONN_TYPE_EXIT: return connection_edge_finished_flushing(TO_EDGE_CONN(conn)); case CONN_TYPE_DIR: return connection_dir_finished_flushing(TO_DIR_CONN(conn)); case CONN_TYPE_CPUWORKER: return connection_cpu_finished_flushing(conn); case CONN_TYPE_CONTROL: return connection_control_finished_flushing(TO_CONTROL_CONN(conn)); default: log_err(LD_BUG,"got unexpected conn type %d.", conn->type); tor_fragile_assert(); return -1; } } /** Called when our attempt to connect() to another server has just * succeeded. * * This function just passes conn to the connection-specific * connection_*_finished_connecting() function. */ static int connection_finished_connecting(connection_t *conn) { tor_assert(conn); if (!server_mode(get_options())) { /* See whether getsockname() says our address changed. We need to do this * now that the connection has finished, because getsockname() on Windows * won't work until then. */ client_check_address_changed(conn->s); } switch (conn->type) { case CONN_TYPE_OR: return connection_or_finished_connecting(TO_OR_CONN(conn)); case CONN_TYPE_EXIT: return connection_edge_finished_connecting(TO_EDGE_CONN(conn)); case CONN_TYPE_DIR: return connection_dir_finished_connecting(TO_DIR_CONN(conn)); default: log_err(LD_BUG,"got unexpected conn type %d.", conn->type); tor_fragile_assert(); return -1; } } /** Callback: invoked when a connection reaches an EOF event. */ static int connection_reached_eof(connection_t *conn) { switch (conn->type) { case CONN_TYPE_OR: return connection_or_reached_eof(TO_OR_CONN(conn)); case CONN_TYPE_AP: case CONN_TYPE_EXIT: return connection_edge_reached_eof(TO_EDGE_CONN(conn)); case CONN_TYPE_DIR: return connection_dir_reached_eof(TO_DIR_CONN(conn)); case CONN_TYPE_CPUWORKER: return connection_cpu_reached_eof(conn); case CONN_TYPE_CONTROL: return connection_control_reached_eof(TO_CONTROL_CONN(conn)); default: log_err(LD_BUG,"got unexpected conn type %d.", conn->type); tor_fragile_assert(); return -1; } } /** Log how many bytes are used by buffers of different kinds and sizes. */ void connection_dump_buffer_mem_stats(int severity) { uint64_t used_by_type[CONN_TYPE_MAX_+1]; uint64_t alloc_by_type[CONN_TYPE_MAX_+1]; int n_conns_by_type[CONN_TYPE_MAX_+1]; uint64_t total_alloc = 0; uint64_t total_used = 0; int i; smartlist_t *conns = get_connection_array(); memset(used_by_type, 0, sizeof(used_by_type)); memset(alloc_by_type, 0, sizeof(alloc_by_type)); memset(n_conns_by_type, 0, sizeof(n_conns_by_type)); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, c) { int tp = c->type; ++n_conns_by_type[tp]; if (c->inbuf) { used_by_type[tp] += buf_datalen(c->inbuf); alloc_by_type[tp] += buf_allocation(c->inbuf); } if (c->outbuf) { used_by_type[tp] += buf_datalen(c->outbuf); alloc_by_type[tp] += buf_allocation(c->outbuf); } } SMARTLIST_FOREACH_END(c); for (i=0; i <= CONN_TYPE_MAX_; ++i) { total_used += used_by_type[i]; total_alloc += alloc_by_type[i]; } tor_log(severity, LD_GENERAL, "In buffers for %d connections: "U64_FORMAT" used/"U64_FORMAT" allocated", smartlist_len(conns), U64_PRINTF_ARG(total_used), U64_PRINTF_ARG(total_alloc)); for (i=CONN_TYPE_MIN_; i <= CONN_TYPE_MAX_; ++i) { if (!n_conns_by_type[i]) continue; tor_log(severity, LD_GENERAL, " For %d %s connections: "U64_FORMAT" used/"U64_FORMAT" allocated", n_conns_by_type[i], conn_type_to_string(i), U64_PRINTF_ARG(used_by_type[i]), U64_PRINTF_ARG(alloc_by_type[i])); } } /** Verify that connection conn has all of its invariants * correct. Trigger an assert if anything is invalid. */ void assert_connection_ok(connection_t *conn, time_t now) { (void) now; /* XXXX unused. */ tor_assert(conn); tor_assert(conn->type >= CONN_TYPE_MIN_); tor_assert(conn->type <= CONN_TYPE_MAX_); #ifdef USE_BUFFEREVENTS if (conn->bufev) { tor_assert(conn->read_event == NULL); tor_assert(conn->write_event == NULL); tor_assert(conn->inbuf == NULL); tor_assert(conn->outbuf == NULL); } #endif switch (conn->type) { case CONN_TYPE_OR: tor_assert(conn->magic == OR_CONNECTION_MAGIC); break; case CONN_TYPE_AP: tor_assert(conn->magic == ENTRY_CONNECTION_MAGIC); break; case CONN_TYPE_EXIT: tor_assert(conn->magic == EDGE_CONNECTION_MAGIC); break; case CONN_TYPE_DIR: tor_assert(conn->magic == DIR_CONNECTION_MAGIC); break; case CONN_TYPE_CONTROL: tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC); break; CASE_ANY_LISTENER_TYPE: tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC); break; default: tor_assert(conn->magic == BASE_CONNECTION_MAGIC); break; } if (conn->linked_conn) { tor_assert(conn->linked_conn->linked_conn == conn); tor_assert(conn->linked); } if (conn->linked) tor_assert(!SOCKET_OK(conn->s)); if (conn->outbuf_flushlen > 0) { /* With optimistic data, we may have queued data in * EXIT_CONN_STATE_RESOLVING while the conn is not yet marked to writing. * */ tor_assert((conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_RESOLVING) || connection_is_writing(conn) || conn->write_blocked_on_bw || (CONN_IS_EDGE(conn) && TO_EDGE_CONN(conn)->edge_blocked_on_circ)); } if (conn->hold_open_until_flushed) tor_assert(conn->marked_for_close); /* XXXX check: read_blocked_on_bw, write_blocked_on_bw, s, conn_array_index, * marked_for_close. */ /* buffers */ if (conn->inbuf) assert_buf_ok(conn->inbuf); if (conn->outbuf) assert_buf_ok(conn->outbuf); if (conn->type == CONN_TYPE_OR) { or_connection_t *or_conn = TO_OR_CONN(conn); if (conn->state == OR_CONN_STATE_OPEN) { /* tor_assert(conn->bandwidth > 0); */ /* the above isn't necessarily true: if we just did a TLS * handshake but we didn't recognize the other peer, or it * gave a bad cert/etc, then we won't have assigned bandwidth, * yet it will be open. -RD */ // tor_assert(conn->read_bucket >= 0); } // tor_assert(conn->addr && conn->port); tor_assert(conn->address); if (conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) tor_assert(or_conn->tls); } if (CONN_IS_EDGE(conn)) { /* XXX unchecked: package window, deliver window. */ if (conn->type == CONN_TYPE_AP) { entry_connection_t *entry_conn = TO_ENTRY_CONN(conn); if (entry_conn->chosen_exit_optional || entry_conn->chosen_exit_retries) tor_assert(entry_conn->chosen_exit_name); tor_assert(entry_conn->socks_request); if (conn->state == AP_CONN_STATE_OPEN) { tor_assert(entry_conn->socks_request->has_finished); if (!conn->marked_for_close) { tor_assert(ENTRY_TO_EDGE_CONN(entry_conn)->cpath_layer); assert_cpath_layer_ok(ENTRY_TO_EDGE_CONN(entry_conn)->cpath_layer); } } } if (conn->type == CONN_TYPE_EXIT) { tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT || conn->purpose == EXIT_PURPOSE_RESOLVE); } } else if (conn->type == CONN_TYPE_DIR) { } else { /* Purpose is only used for dir and exit types currently */ tor_assert(!conn->purpose); } switch (conn->type) { CASE_ANY_LISTENER_TYPE: tor_assert(conn->state == LISTENER_STATE_READY); break; case CONN_TYPE_OR: tor_assert(conn->state >= OR_CONN_STATE_MIN_); tor_assert(conn->state <= OR_CONN_STATE_MAX_); break; case CONN_TYPE_EXIT: tor_assert(conn->state >= EXIT_CONN_STATE_MIN_); tor_assert(conn->state <= EXIT_CONN_STATE_MAX_); tor_assert(conn->purpose >= EXIT_PURPOSE_MIN_); tor_assert(conn->purpose <= EXIT_PURPOSE_MAX_); break; case CONN_TYPE_AP: tor_assert(conn->state >= AP_CONN_STATE_MIN_); tor_assert(conn->state <= AP_CONN_STATE_MAX_); tor_assert(TO_ENTRY_CONN(conn)->socks_request); break; case CONN_TYPE_DIR: tor_assert(conn->state >= DIR_CONN_STATE_MIN_); tor_assert(conn->state <= DIR_CONN_STATE_MAX_); tor_assert(conn->purpose >= DIR_PURPOSE_MIN_); tor_assert(conn->purpose <= DIR_PURPOSE_MAX_); break; case CONN_TYPE_CPUWORKER: tor_assert(conn->state >= CPUWORKER_STATE_MIN_); tor_assert(conn->state <= CPUWORKER_STATE_MAX_); break; case CONN_TYPE_CONTROL: tor_assert(conn->state >= CONTROL_CONN_STATE_MIN_); tor_assert(conn->state <= CONTROL_CONN_STATE_MAX_); break; default: tor_assert(0); } } /** Fills addr and port with the details of the global * proxy server we are using. * conn contains the connection we are using the proxy for. * * Return 0 on success, -1 on failure. */ int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, const connection_t *conn) { const or_options_t *options = get_options(); if (options->HTTPSProxy) { tor_addr_copy(addr, &options->HTTPSProxyAddr); *port = options->HTTPSProxyPort; *proxy_type = PROXY_CONNECT; return 0; } else if (options->Socks4Proxy) { tor_addr_copy(addr, &options->Socks4ProxyAddr); *port = options->Socks4ProxyPort; *proxy_type = PROXY_SOCKS4; return 0; } else if (options->Socks5Proxy) { tor_addr_copy(addr, &options->Socks5ProxyAddr); *port = options->Socks5ProxyPort; *proxy_type = PROXY_SOCKS5; return 0; } else if (options->ClientTransportPlugin || options->Bridges) { const transport_t *transport = NULL; int r; r = find_transport_by_bridge_addrport(&conn->addr, conn->port, &transport); if (r<0) return -1; if (transport) { /* transport found */ tor_addr_copy(addr, &transport->addr); *port = transport->port; *proxy_type = transport->socks_version; return 0; } } *proxy_type = PROXY_NONE; return 0; } /** Returns the global proxy type used by tor. */ static int get_proxy_type(void) { const or_options_t *options = get_options(); if (options->HTTPSProxy) return PROXY_CONNECT; else if (options->Socks4Proxy) return PROXY_SOCKS4; else if (options->Socks5Proxy) return PROXY_SOCKS5; else if (options->ClientTransportPlugin) return PROXY_PLUGGABLE; else return PROXY_NONE; } /** Log a failed connection to a proxy server. * conn is the connection we use the proxy server for. */ void log_failed_proxy_connection(connection_t *conn) { tor_addr_t proxy_addr; uint16_t proxy_port; int proxy_type; if (get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, conn) != 0) return; /* if we have no proxy set up, leave this function. */ log_warn(LD_NET, "The connection to the %s proxy server at %s just failed. " "Make sure that the proxy server is up and running.", proxy_type_to_string(get_proxy_type()), fmt_addrport(&proxy_addr, proxy_port)); } /** Return string representation of proxy_type. */ static const char * proxy_type_to_string(int proxy_type) { switch (proxy_type) { case PROXY_CONNECT: return "HTTP"; case PROXY_SOCKS4: return "SOCKS4"; case PROXY_SOCKS5: return "SOCKS5"; case PROXY_PLUGGABLE: return "pluggable transports SOCKS"; case PROXY_NONE: return "NULL"; default: tor_assert(0); } return NULL; /*Unreached*/ } /** Call connection_free_() on every connection in our array, and release all * storage held by connection.c. This is used by cpuworkers and dnsworkers * when they fork, so they don't keep resources held open (especially * sockets). * * Don't do the checks in connection_free(), because they will * fail. */ void connection_free_all(void) { smartlist_t *conns = get_connection_array(); /* We don't want to log any messages to controllers. */ SMARTLIST_FOREACH(conns, connection_t *, conn, if (conn->type == CONN_TYPE_CONTROL) TO_CONTROL_CONN(conn)->event_mask = 0); control_update_global_event_mask(); /* Unlink everything from the identity map. */ connection_or_clear_identity_map(); /* Clear out our list of broken connections */ clear_broken_connection_map(0); SMARTLIST_FOREACH(conns, connection_t *, conn, connection_free_(conn)); if (outgoing_addrs) { SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t *, addr, tor_free(addr)); smartlist_free(outgoing_addrs); outgoing_addrs = NULL; } tor_free(last_interface_ipv4); tor_free(last_interface_ipv6); #ifdef USE_BUFFEREVENTS if (global_rate_limit) bufferevent_rate_limit_group_free(global_rate_limit); #endif } tor-0.2.4.20/src/or/channel.h0000644000175000017500000004147312255745673012503 00000000000000/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file channel.h * \brief Header file for channel.c **/ #ifndef TOR_CHANNEL_H #define TOR_CHANNEL_H #include "or.h" #include "tor_queue.h" #include "circuitmux.h" /* Channel handler function pointer typedefs */ typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *); typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *); typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *); struct cell_queue_entry_s; TOR_SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue; typedef struct chan_cell_queue chan_cell_queue_t; /* * Channel struct; see the channel_t typedef in or.h. A channel is an * abstract interface for the OR-to-OR connection, similar to connection_or_t, * but without the strong coupling to the underlying TLS implementation. They * are constructed by calling a protocol-specific function to open a channel * to a particular node, and once constructed support the abstract operations * defined below. */ struct channel_s { /* Magic number for type-checking cast macros */ uint32_t magic; /* Current channel state */ channel_state_t state; /* Globally unique ID number for a channel over the lifetime of a Tor * process. */ uint64_t global_identifier; /* Should we expect to see this channel in the channel lists? */ unsigned char registered:1; /** has this channel ever been open? */ unsigned int has_been_open:1; /** Why did we close? */ enum { CHANNEL_NOT_CLOSING = 0, CHANNEL_CLOSE_REQUESTED, CHANNEL_CLOSE_FROM_BELOW, CHANNEL_CLOSE_FOR_ERROR } reason_for_closing; /* Timestamps for both cell channels and listeners */ time_t timestamp_created; /* Channel created */ time_t timestamp_active; /* Any activity */ /* Methods implemented by the lower layer */ /* Free a channel */ void (*free)(channel_t *); /* Close an open channel */ void (*close)(channel_t *); /* Describe the transport subclass for this channel */ const char * (*describe_transport)(channel_t *); /* Optional method to dump transport-specific statistics on the channel */ void (*dumpstats)(channel_t *, int); /* Registered handlers for incoming cells */ channel_cell_handler_fn_ptr cell_handler; channel_var_cell_handler_fn_ptr var_cell_handler; /* Methods implemented by the lower layer */ /* * Ask the underlying transport what the remote endpoint address is, in * a tor_addr_t. This is optional and subclasses may leave this NULL. * If they implement it, they should write the address out to the * provided tor_addr_t *, and return 1 if successful or 0 if no address * available. */ int (*get_remote_addr)(channel_t *, tor_addr_t *); #define GRD_FLAG_ORIGINAL 1 #define GRD_FLAG_ADDR_ONLY 2 /* * Get a text description of the remote endpoint; canonicalized if the flag * GRD_FLAG_ORIGINAL is not set, or the one we originally connected * to/received from if it is. If GRD_FLAG_ADDR_ONLY is set, we return only * the original address. */ const char * (*get_remote_descr)(channel_t *, int); /* Check if the lower layer has queued writes */ int (*has_queued_writes)(channel_t *); /* * If the second param is zero, ask the lower layer if this is * 'canonical', for a transport-specific definition of canonical; if * it is 1, ask if the answer to the preceding query is safe to rely * on. */ int (*is_canonical)(channel_t *, int); /* Check if this channel matches a specified extend_info_t */ int (*matches_extend_info)(channel_t *, extend_info_t *); /* Check if this channel matches a target address when extending */ int (*matches_target)(channel_t *, const tor_addr_t *); /* Write a cell to an open channel */ int (*write_cell)(channel_t *, cell_t *); /* Write a packed cell to an open channel */ int (*write_packed_cell)(channel_t *, packed_cell_t *); /* Write a variable-length cell to an open channel */ int (*write_var_cell)(channel_t *, var_cell_t *); /* * Hash of the public RSA key for the other side's identity key, or * zeroes if the other side hasn't shown us a valid identity key. */ char identity_digest[DIGEST_LEN]; /* Nickname of the OR on the other side, or NULL if none. */ char *nickname; /* * Linked list of channels with the same identity digest, for the * digest->channel map */ TOR_LIST_ENTRY(channel_s) next_with_same_id; /* List of incoming cells to handle */ chan_cell_queue_t incoming_queue; /* List of queued outgoing cells */ chan_cell_queue_t outgoing_queue; /* Circuit mux for circuits sending on this channel */ circuitmux_t *cmux; /* Circuit ID generation stuff for use by circuitbuild.c */ /* * When we send CREATE cells along this connection, which half of the * space should we use? */ ENUM_BF(circ_id_type_t) circ_id_type:2; /** DOCDOC*/ unsigned wide_circ_ids:1; /* * Which circ_id do we try to use next on this connection? This is * always in the range 0..1<<15-1. */ circid_t next_circ_id; /* For how many circuits are we n_chan? What about p_chan? */ unsigned int num_n_circuits, num_p_circuits; /* * True iff this channel shouldn't get any new circs attached to it, * because the connection is too old, or because there's a better one. * More generally, this flag is used to note an unhealthy connection; * for example, if a bad connection fails we shouldn't assume that the * router itself has a problem. */ unsigned int is_bad_for_new_circs:1; /** True iff we have decided that the other end of this connection * is a client. Channels with this flag set should never be used * to satisfy an EXTEND request. */ unsigned int is_client:1; /** Set if the channel was initiated remotely (came from a listener) */ unsigned int is_incoming:1; /** Set by lower layer if this is local; i.e., everything it communicates * with for this channel returns true for is_local_addr(). This is used * to decide whether to declare reachability when we receive something on * this channel in circuitbuild.c */ unsigned int is_local:1; /** Channel timestamps for cell channels */ time_t timestamp_client; /* Client used this, according to relay.c */ time_t timestamp_drained; /* Output queue empty */ time_t timestamp_recv; /* Cell received from lower layer */ time_t timestamp_xmit; /* Cell sent to lower layer */ /* Timestamp for relay.c */ time_t timestamp_last_added_nonpadding; /** Unique ID for measuring direct network status requests;vtunneled ones * come over a circuit_t, which has a dirreq_id field as well, but is a * distinct namespace. */ uint64_t dirreq_id; /** Channel counters for cell channels */ uint64_t n_cells_recved; uint64_t n_cells_xmitted; }; struct channel_listener_s { /* Current channel listener state */ channel_listener_state_t state; /* Globally unique ID number for a channel over the lifetime of a Tor * process. */ uint64_t global_identifier; /* Should we expect to see this channel in the channel lists? */ unsigned char registered:1; /** Why did we close? */ enum { CHANNEL_LISTENER_NOT_CLOSING = 0, CHANNEL_LISTENER_CLOSE_REQUESTED, CHANNEL_LISTENER_CLOSE_FROM_BELOW, CHANNEL_LISTENER_CLOSE_FOR_ERROR } reason_for_closing; /* Timestamps for both cell channels and listeners */ time_t timestamp_created; /* Channel created */ time_t timestamp_active; /* Any activity */ /* Methods implemented by the lower layer */ /* Free a channel */ void (*free)(channel_listener_t *); /* Close an open channel */ void (*close)(channel_listener_t *); /* Describe the transport subclass for this channel */ const char * (*describe_transport)(channel_listener_t *); /* Optional method to dump transport-specific statistics on the channel */ void (*dumpstats)(channel_listener_t *, int); /* Registered listen handler to call on incoming connection */ channel_listener_fn_ptr listener; /* List of pending incoming connections */ smartlist_t *incoming_list; /* Timestamps for listeners */ time_t timestamp_accepted; /* Counters for listeners */ uint64_t n_accepted; }; /* Channel state manipulations */ int channel_state_is_valid(channel_state_t state); int channel_listener_state_is_valid(channel_listener_state_t state); int channel_state_can_transition(channel_state_t from, channel_state_t to); int channel_listener_state_can_transition(channel_listener_state_t from, channel_listener_state_t to); const char * channel_state_to_string(channel_state_t state); const char * channel_listener_state_to_string(channel_listener_state_t state); /* Abstract channel operations */ void channel_mark_for_close(channel_t *chan); void channel_write_cell(channel_t *chan, cell_t *cell); void channel_write_packed_cell(channel_t *chan, packed_cell_t *cell); void channel_write_var_cell(channel_t *chan, var_cell_t *cell); void channel_listener_mark_for_close(channel_listener_t *chan_l); /* Channel callback registrations */ /* Listener callback */ channel_listener_fn_ptr channel_listener_get_listener_fn(channel_listener_t *chan); void channel_listener_set_listener_fn(channel_listener_t *chan, channel_listener_fn_ptr listener); /* Incoming cell callbacks */ channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan); channel_var_cell_handler_fn_ptr channel_get_var_cell_handler(channel_t *chan); void channel_set_cell_handlers(channel_t *chan, channel_cell_handler_fn_ptr cell_handler, channel_var_cell_handler_fn_ptr var_cell_handler); /* Clean up closed channels and channel listeners periodically; these are * called from run_scheduled_events() in main.c. */ void channel_run_cleanup(void); void channel_listener_run_cleanup(void); /* Close all channels and deallocate everything */ void channel_free_all(void); /* Dump some statistics in the log */ void channel_dumpstats(int severity); void channel_listener_dumpstats(int severity); /* Set the cmux policy on all active channels */ void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol); #ifdef TOR_CHANNEL_INTERNAL_ /* Channel operations for subclasses and internal use only */ /* Initialize a newly allocated channel - do this first in subclass * constructors. */ void channel_init(channel_t *chan); void channel_init_listener(channel_listener_t *chan); /* Channel registration/unregistration */ void channel_register(channel_t *chan); void channel_unregister(channel_t *chan); /* Channel listener registration/unregistration */ void channel_listener_register(channel_listener_t *chan_l); void channel_listener_unregister(channel_listener_t *chan_l); /* Close from below */ void channel_close_from_lower_layer(channel_t *chan); void channel_close_for_error(channel_t *chan); void channel_closed(channel_t *chan); void channel_listener_close_from_lower_layer(channel_listener_t *chan_l); void channel_listener_close_for_error(channel_listener_t *chan_l); void channel_listener_closed(channel_listener_t *chan_l); /* Free a channel */ void channel_free(channel_t *chan); void channel_listener_free(channel_listener_t *chan_l); /* State/metadata setters */ void channel_change_state(channel_t *chan, channel_state_t to_state); void channel_clear_identity_digest(channel_t *chan); void channel_clear_remote_end(channel_t *chan); void channel_mark_local(channel_t *chan); void channel_mark_incoming(channel_t *chan); void channel_mark_outgoing(channel_t *chan); void channel_set_identity_digest(channel_t *chan, const char *identity_digest); void channel_set_remote_end(channel_t *chan, const char *identity_digest, const char *nickname); void channel_listener_change_state(channel_listener_t *chan_l, channel_listener_state_t to_state); /* Timestamp updates */ void channel_timestamp_created(channel_t *chan); void channel_timestamp_active(channel_t *chan); void channel_timestamp_drained(channel_t *chan); void channel_timestamp_recv(channel_t *chan); void channel_timestamp_xmit(channel_t *chan); void channel_listener_timestamp_created(channel_listener_t *chan_l); void channel_listener_timestamp_active(channel_listener_t *chan_l); void channel_listener_timestamp_accepted(channel_listener_t *chan_l); /* Incoming channel handling */ void channel_listener_process_incoming(channel_listener_t *listener); void channel_listener_queue_incoming(channel_listener_t *listener, channel_t *incoming); /* Incoming cell handling */ void channel_process_cells(channel_t *chan); void channel_queue_cell(channel_t *chan, cell_t *cell); void channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell); /* Outgoing cell handling */ void channel_flush_cells(channel_t *chan); /* Request from lower layer for more cells if available */ ssize_t channel_flush_some_cells(channel_t *chan, ssize_t num_cells); /* Query if data available on this channel */ int channel_more_to_flush(channel_t *chan); /* Notify flushed outgoing for dirreq handling */ void channel_notify_flushed(channel_t *chan); /* Handle stuff we need to do on open like notifying circuits */ void channel_do_open_actions(channel_t *chan); #endif /* Helper functions to perform operations on channels */ int channel_send_destroy(circid_t circ_id, channel_t *chan, int reason); /* * Outside abstract interfaces that should eventually get turned into * something transport/address format independent. */ channel_t * channel_connect(const tor_addr_t *addr, uint16_t port, const char *id_digest); channel_t * channel_get_for_extend(const char *digest, const tor_addr_t *target_addr, const char **msg_out, int *launch_out); /* Ask which of two channels is better for circuit-extension purposes */ int channel_is_better(time_t now, channel_t *a, channel_t *b, int forgive_new_connections); /** Channel lookups */ channel_t * channel_find_by_global_id(uint64_t global_identifier); channel_t * channel_find_by_remote_digest(const char *identity_digest); /** For things returned by channel_find_by_remote_digest(), walk the list. */ channel_t * channel_next_with_digest(channel_t *chan); /* * Metadata queries/updates */ const char * channel_describe_transport(channel_t *chan); void channel_dump_statistics(channel_t *chan, int severity); void channel_dump_transport_statistics(channel_t *chan, int severity); const char * channel_get_actual_remote_descr(channel_t *chan); const char * channel_get_actual_remote_address(channel_t *chan); int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out); const char * channel_get_canonical_remote_descr(channel_t *chan); int channel_has_queued_writes(channel_t *chan); int channel_is_bad_for_new_circs(channel_t *chan); void channel_mark_bad_for_new_circs(channel_t *chan); int channel_is_canonical(channel_t *chan); int channel_is_canonical_is_reliable(channel_t *chan); int channel_is_client(channel_t *chan); int channel_is_local(channel_t *chan); int channel_is_incoming(channel_t *chan); int channel_is_outgoing(channel_t *chan); void channel_mark_client(channel_t *chan); int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info); int channel_matches_target_addr_for_extend(channel_t *chan, const tor_addr_t *target); unsigned int channel_num_circuits(channel_t *chan); void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd, int consider_identity); void channel_timestamp_client(channel_t *chan); const char * channel_listener_describe_transport(channel_listener_t *chan_l); void channel_listener_dump_statistics(channel_listener_t *chan_l, int severity); void channel_listener_dump_transport_statistics(channel_listener_t *chan_l, int severity); /* Timestamp queries */ time_t channel_when_created(channel_t *chan); time_t channel_when_last_active(channel_t *chan); time_t channel_when_last_client(channel_t *chan); time_t channel_when_last_drained(channel_t *chan); time_t channel_when_last_recv(channel_t *chan); time_t channel_when_last_xmit(channel_t *chan); time_t channel_listener_when_created(channel_listener_t *chan_l); time_t channel_listener_when_last_active(channel_listener_t *chan_l); time_t channel_listener_when_last_accepted(channel_listener_t *chan_l); /* Counter queries */ uint64_t channel_count_recved(channel_t *chan); uint64_t channel_count_xmitted(channel_t *chan); uint64_t channel_listener_count_accepted(channel_listener_t *chan_l); #endif tor-0.2.4.20/src/or/eventdns_tor.h0000644000175000017500000000074112166112777013570 00000000000000/* Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_EVENTDNS_TOR_H #define TOR_EVENTDNS_TOR_H #include "orconfig.h" #define DNS_USE_OPENSSL_FOR_ID #ifndef HAVE_UINT typedef unsigned int uint; #endif #ifndef HAVE_U_CHAR typedef unsigned char u_char; #endif #ifdef _WIN32 #define inline __inline #endif #include "torint.h" /* These are for debugging possible memory leaks. */ #include "util.h" #include "compat.h" #endif tor-0.2.4.20/src/or/dns.h0000644000175000017500000000166712166112777011652 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file dns.h * \brief Header file for dns.c. **/ #ifndef TOR_DNS_H #define TOR_DNS_H int dns_init(void); int has_dns_init_failed(void); void dns_free_all(void); uint32_t dns_clip_ttl(uint32_t ttl); int dns_reset(void); void connection_dns_remove(edge_connection_t *conn); void assert_connection_edge_not_dns_pending(edge_connection_t *conn); void assert_all_pending_dns_resolves_ok(void); void dns_cancel_pending_resolve(const char *question); int dns_resolve(edge_connection_t *exitconn); void dns_launch_correctness_checks(void); int dns_seems_to_be_broken(void); int dns_seems_to_be_broken_for_ipv6(void); void dns_reset_correctness_checks(void); void dump_dns_mem_usage(int severity); #endif tor-0.2.4.20/src/or/routerset.c0000644000175000017500000003527712166112777013121 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "or.h" #include "geoip.h" #include "nodelist.h" #include "policies.h" #include "router.h" #include "routerparse.h" #include "routerset.h" /** A routerset specifies constraints on a set of possible routerinfos, based * on their names, identities, or addresses. It is optimized for determining * whether a router is a member or not, in O(1+P) time, where P is the number * of address policy constraints. */ struct routerset_t { /** A list of strings for the elements of the policy. Each string is either * a nickname, a hexadecimal identity fingerprint, or an address policy. A * router belongs to the set if its nickname OR its identity OR its address * matches an entry here. */ smartlist_t *list; /** A map from lowercase nicknames of routers in the set to (void*)1 */ strmap_t *names; /** A map from identity digests routers in the set to (void*)1 */ digestmap_t *digests; /** An address policy for routers in the set. For implementation reasons, * a router belongs to the set if it is _rejected_ by this policy. */ smartlist_t *policies; /** A human-readable description of what this routerset is for. Used in * log messages. */ char *description; /** A list of the country codes in this set. */ smartlist_t *country_names; /** Total number of countries we knew about when we built countries.*/ int n_countries; /** Bit array mapping the return value of geoip_get_country() to 1 iff the * country is a member of this routerset. Note that we MUST call * routerset_refresh_countries() whenever the geoip country list is * reloaded. */ bitarray_t *countries; }; /** Return a new empty routerset. */ routerset_t * routerset_new(void) { routerset_t *result = tor_malloc_zero(sizeof(routerset_t)); result->list = smartlist_new(); result->names = strmap_new(); result->digests = digestmap_new(); result->policies = smartlist_new(); result->country_names = smartlist_new(); return result; } /** If c is a country code in the form {cc}, return a newly allocated * string holding the "cc" part. Else, return NULL. */ static char * routerset_get_countryname(const char *c) { char *country; if (strlen(c) < 4 || c[0] !='{' || c[3] !='}') return NULL; country = tor_strndup(c+1, 2); tor_strlower(country); return country; } /** Update the routerset's countries bitarray_t. Called whenever * the GeoIP IPv4 database is reloaded. */ void routerset_refresh_countries(routerset_t *target) { int cc; bitarray_free(target->countries); if (!geoip_is_loaded(AF_INET)) { target->countries = NULL; target->n_countries = 0; return; } target->n_countries = geoip_get_n_countries(); target->countries = bitarray_init_zero(target->n_countries); SMARTLIST_FOREACH_BEGIN(target->country_names, const char *, country) { cc = geoip_get_country(country); if (cc >= 0) { tor_assert(cc < target->n_countries); bitarray_set(target->countries, cc); } else { log_warn(LD_CONFIG, "Country code '%s' is not recognized.", country); } } SMARTLIST_FOREACH_END(country); } /** Parse the string s to create a set of routerset entries, and add * them to target. In log messages, refer to the string as * description. Return 0 on success, -1 on failure. * * Three kinds of elements are allowed in routersets: nicknames, IP address * patterns, and fingerprints. They may be surrounded by optional space, and * must be separated by commas. */ int routerset_parse(routerset_t *target, const char *s, const char *description) { int r = 0; int added_countries = 0; char *countryname; smartlist_t *list = smartlist_new(); smartlist_split_string(list, s, ",", SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(list, char *, nick) { addr_policy_t *p; if (is_legal_hexdigest(nick)) { char d[DIGEST_LEN]; if (*nick == '$') ++nick; log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description); base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN); digestmap_set(target->digests, d, (void*)1); } else if (is_legal_nickname(nick)) { log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description); strmap_set_lc(target->names, nick, (void*)1); } else if ((countryname = routerset_get_countryname(nick)) != NULL) { log_debug(LD_CONFIG, "Adding country %s to %s", nick, description); smartlist_add(target->country_names, countryname); added_countries = 1; } else if ((strchr(nick,'.') || strchr(nick, '*')) && (p = router_parse_addr_policy_item_from_string( nick, ADDR_POLICY_REJECT))) { log_debug(LD_CONFIG, "Adding address %s to %s", nick, description); smartlist_add(target->policies, p); } else { log_warn(LD_CONFIG, "Entry '%s' in %s is malformed.", nick, description); r = -1; tor_free(nick); SMARTLIST_DEL_CURRENT(list, nick); } } SMARTLIST_FOREACH_END(nick); policy_expand_unspec(&target->policies); smartlist_add_all(target->list, list); smartlist_free(list); if (added_countries) routerset_refresh_countries(target); return r; } /** Add all members of the set source to target. */ void routerset_union(routerset_t *target, const routerset_t *source) { char *s; tor_assert(target); if (!source || !source->list) return; s = routerset_to_string(source); routerset_parse(target, s, "other routerset"); tor_free(s); } /** Return true iff set lists only nicknames and digests, and includes * no IP ranges or countries. */ int routerset_is_list(const routerset_t *set) { return smartlist_len(set->country_names) == 0 && smartlist_len(set->policies) == 0; } /** Return true iff we need a GeoIP IP-to-country database to make sense of * set. */ int routerset_needs_geoip(const routerset_t *set) { return set && smartlist_len(set->country_names); } /** Return true iff there are no entries in set. */ int routerset_is_empty(const routerset_t *set) { return !set || smartlist_len(set->list) == 0; } /** Helper. Return true iff set contains a router based on the other * provided fields. Return higher values for more specific subentries: a * single router is more specific than an address range of routers, which is * more specific in turn than a country code. * * (If country is -1, then we take the country * from addr.) */ static int routerset_contains(const routerset_t *set, const tor_addr_t *addr, uint16_t orport, const char *nickname, const char *id_digest, country_t country) { if (!set || !set->list) return 0; if (nickname && strmap_get_lc(set->names, nickname)) return 4; if (id_digest && digestmap_get(set->digests, id_digest)) return 4; if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies) == ADDR_POLICY_REJECTED) return 3; if (set->countries) { if (country < 0 && addr) country = geoip_get_country_by_addr(addr); if (country >= 0 && country < set->n_countries && bitarray_is_set(set->countries, country)) return 2; } return 0; } /** If *setp includes at least one country code, or if * only_some_cc_set is 0, add the ?? and A1 country codes to * *setp, creating it as needed. Return true iff *setp changed. */ int routerset_add_unknown_ccs(routerset_t **setp, int only_if_some_cc_set) { routerset_t *set; int add_unknown, add_a1; if (only_if_some_cc_set) { if (!*setp || smartlist_len((*setp)->country_names) == 0) return 0; } if (!*setp) *setp = routerset_new(); set = *setp; add_unknown = ! smartlist_contains_string_case(set->country_names, "??") && geoip_get_country("??") >= 0; add_a1 = ! smartlist_contains_string_case(set->country_names, "a1") && geoip_get_country("A1") >= 0; if (add_unknown) { smartlist_add(set->country_names, tor_strdup("??")); smartlist_add(set->list, tor_strdup("{??}")); } if (add_a1) { smartlist_add(set->country_names, tor_strdup("a1")); smartlist_add(set->list, tor_strdup("{a1}")); } if (add_unknown || add_a1) { routerset_refresh_countries(set); return 1; } return 0; } /** Return true iff we can tell that ei is a member of set. */ int routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei) { return routerset_contains(set, &ei->addr, ei->port, ei->nickname, ei->identity_digest, -1 /*country*/); } /** Return true iff ri is in set. If country is -1, we * look up the country. */ int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri, country_t country) { tor_addr_t addr; tor_addr_from_ipv4h(&addr, ri->addr); return routerset_contains(set, &addr, ri->or_port, ri->nickname, ri->cache_info.identity_digest, country); } /** Return true iff rs is in set. If country is -1, we * look up the country. */ int routerset_contains_routerstatus(const routerset_t *set, const routerstatus_t *rs, country_t country) { tor_addr_t addr; tor_addr_from_ipv4h(&addr, rs->addr); return routerset_contains(set, &addr, rs->or_port, rs->nickname, rs->identity_digest, country); } /** Return true iff node is in set. */ int routerset_contains_node(const routerset_t *set, const node_t *node) { if (node->rs) return routerset_contains_routerstatus(set, node->rs, node->country); else if (node->ri) return routerset_contains_router(set, node->ri, node->country); else return 0; } /** Add every known node_t that is a member of routerset to * out, but never add any that are part of excludeset. * If running_only, only add the running ones. */ void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset, const routerset_t *excludeset, int running_only) { tor_assert(out); if (!routerset || !routerset->list) return; if (routerset_is_list(routerset)) { /* No routers are specified by type; all are given by name or digest. * we can do a lookup in O(len(routerset)). */ SMARTLIST_FOREACH(routerset->list, const char *, name, { const node_t *node = node_get_by_nickname(name, 1); if (node) { if (!running_only || node->is_running) if (!routerset_contains_node(excludeset, node)) smartlist_add(out, (void*)node); } }); } else { /* We need to iterate over the routerlist to get all the ones of the * right kind. */ smartlist_t *nodes = nodelist_get_list(); SMARTLIST_FOREACH(nodes, const node_t *, node, { if (running_only && !node->is_running) continue; if (routerset_contains_node(routerset, node) && !routerset_contains_node(excludeset, node)) smartlist_add(out, (void*)node); }); } } #if 0 /** Add to target every node_t from source except: * * 1) Don't add it if include is non-empty and the relay isn't in * include; and * 2) Don't add it if exclude is non-empty and the relay is * excluded in a more specific fashion by exclude. * 3) If running_only, don't add non-running routers. */ void routersets_get_node_disjunction(smartlist_t *target, const smartlist_t *source, const routerset_t *include, const routerset_t *exclude, int running_only) { SMARTLIST_FOREACH(source, const node_t *, node, { int include_result; if (running_only && !node->is_running) continue; if (!routerset_is_empty(include)) include_result = routerset_contains_node(include, node); else include_result = 1; if (include_result) { int exclude_result = routerset_contains_node(exclude, node); if (include_result >= exclude_result) smartlist_add(target, (void*)node); } }); } #endif /** Remove every node_t from lst that is in routerset. */ void routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset) { tor_assert(lst); if (!routerset) return; SMARTLIST_FOREACH(lst, const node_t *, node, { if (routerset_contains_node(routerset, node)) { //log_debug(LD_DIR, "Subtracting %s",r->nickname); SMARTLIST_DEL_CURRENT(lst, node); } }); } /** Return a new string that when parsed by routerset_parse_string() will * yield set. */ char * routerset_to_string(const routerset_t *set) { if (!set || !set->list) return tor_strdup(""); return smartlist_join_strings(set->list, ",", 0, NULL); } /** Helper: return true iff old and new are both NULL, or both non-NULL * equal routersets. */ int routerset_equal(const routerset_t *old, const routerset_t *new) { if (routerset_is_empty(old) && routerset_is_empty(new)) { /* Two empty sets are equal */ return 1; } else if (routerset_is_empty(old) || routerset_is_empty(new)) { /* An empty set is equal to nothing else. */ return 0; } tor_assert(old != NULL); tor_assert(new != NULL); if (smartlist_len(old->list) != smartlist_len(new->list)) return 0; SMARTLIST_FOREACH(old->list, const char *, cp1, { const char *cp2 = smartlist_get(new->list, cp1_sl_idx); if (strcmp(cp1, cp2)) return 0; }); return 1; } /** Free all storage held in routerset. */ void routerset_free(routerset_t *routerset) { if (!routerset) return; SMARTLIST_FOREACH(routerset->list, char *, cp, tor_free(cp)); smartlist_free(routerset->list); SMARTLIST_FOREACH(routerset->policies, addr_policy_t *, p, addr_policy_free(p)); smartlist_free(routerset->policies); SMARTLIST_FOREACH(routerset->country_names, char *, cp, tor_free(cp)); smartlist_free(routerset->country_names); strmap_free(routerset->names, NULL); digestmap_free(routerset->digests, NULL); bitarray_free(routerset->countries); tor_free(routerset); } tor-0.2.4.20/src/or/transports.h0000644000175000017500000000714512255745673013310 00000000000000/* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file transports.h * \brief Headers for transports.c **/ #ifndef TOR_TRANSPORTS_H #define TOR_TRANSPORTS_H /** Represents a pluggable transport used by a bridge. */ typedef struct transport_t { /** SOCKS version: One of PROXY_SOCKS4, PROXY_SOCKS5. */ int socks_version; /** Name of pluggable transport protocol */ char *name; /** The IP address where the transport bound and is waiting for * connections. */ tor_addr_t addr; /** Port of proxy */ uint16_t port; /** Boolean: We are re-parsing our transport list, and we are going to remove * this one if we don't find it in the list of configured transports. */ unsigned marked_for_removal : 1; } transport_t; void mark_transport_list(void); void sweep_transport_list(void); int transport_add_from_config(const tor_addr_t *addr, uint16_t port, const char *name, int socks_ver); void transport_free(transport_t *transport); transport_t *transport_get_by_name(const char *name); void pt_kickstart_proxy(const smartlist_t *transport_list, char **proxy_argv, int is_server); #define pt_kickstart_client_proxy(tl, pa) \ pt_kickstart_proxy(tl, pa, 0) #define pt_kickstart_server_proxy(tl, pa) \ pt_kickstart_proxy(tl, pa, 1) void pt_configure_remaining_proxies(void); int pt_proxies_configuration_pending(void); char *pt_get_extra_info_descriptor_string(void); void pt_free_all(void); void pt_prepare_proxy_list_for_config_read(void); void sweep_proxy_list(void); smartlist_t *get_transport_proxy_ports(void); #ifdef PT_PRIVATE /** State of the managed proxy configuration protocol. */ enum pt_proto_state { PT_PROTO_INFANT, /* was just born */ PT_PROTO_LAUNCHED, /* was just launched */ PT_PROTO_ACCEPTING_METHODS, /* accepting methods */ PT_PROTO_CONFIGURED, /* configured successfully */ PT_PROTO_COMPLETED, /* configure and registered its transports */ PT_PROTO_BROKEN, /* broke during the protocol */ PT_PROTO_FAILED_LAUNCH /* failed while launching */ }; /** Structure containing information of a managed proxy. */ typedef struct { enum pt_proto_state conf_state; /* the current configuration state */ char **argv; /* the cli arguments of this proxy */ int conf_protocol; /* the configuration protocol version used */ int is_server; /* is it a server proxy? */ /* A pointer to the process handle of this managed proxy. */ process_handle_t *process_handle; int pid; /* The Process ID this managed proxy is using. */ /** Boolean: We are re-parsing our config, and we are going to * remove this managed proxy if we don't find it any transport * plugins that use it. */ unsigned int marked_for_removal : 1; /** Boolean: We got a SIGHUP while this proxy was running. We use * this flag to signify that this proxy might need to be restarted * so that it can listen for other transports according to the new * torrc. */ unsigned int got_hup : 1; /* transports to-be-launched by this proxy */ smartlist_t *transports_to_launch; /* The 'transports' list contains all the transports this proxy has launched. */ smartlist_t *transports; } managed_proxy_t; int parse_cmethod_line(const char *line, managed_proxy_t *mp); int parse_smethod_line(const char *line, managed_proxy_t *mp); int parse_version(const char *line, managed_proxy_t *mp); void parse_env_error(const char *line); void handle_proxy_line(const char *line, managed_proxy_t *mp); #endif #endif tor-0.2.4.20/src/or/directory.h0000644000175000017500000001314512255745673013072 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file directory.h * \brief Header file for directory.c. **/ #ifndef TOR_DIRECTORY_H #define TOR_DIRECTORY_H int directories_have_accepted_server_descriptor(void); void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, dirinfo_type_t type, const char *payload, size_t payload_len, size_t extrainfo_len); void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose, const char *resource, int pds_flags); void directory_get_from_all_authorities(uint8_t dir_purpose, uint8_t router_purpose, const char *resource); /** Enumeration of ways to connect to a directory server */ typedef enum { /** Default: connect over a one-hop Tor circuit but fall back to direct * connection */ DIRIND_ONEHOP=0, /** Connect over a multi-hop anonymizing Tor circuit */ DIRIND_ANONYMOUS=1, /** Conncet to the DirPort directly */ DIRIND_DIRECT_CONN, /** Connect over a multi-hop anonymizing Tor circuit to our dirport */ DIRIND_ANON_DIRPORT, } dir_indirection_t; void directory_initiate_command_routerstatus(const routerstatus_t *status, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since); void directory_initiate_command_routerstatus_rend(const routerstatus_t *status, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since, const rend_data_t *rend_query); int parse_http_response(const char *headers, int *code, time_t *date, compress_method_t *compression, char **response); int connection_dir_is_encrypted(dir_connection_t *conn); int connection_dir_reached_eof(dir_connection_t *conn); int connection_dir_process_inbuf(dir_connection_t *conn); int connection_dir_finished_flushing(dir_connection_t *conn); int connection_dir_finished_connecting(dir_connection_t *conn); void connection_dir_about_to_close(dir_connection_t *dir_conn); void directory_initiate_command(const char *address, const tor_addr_t *addr, uint16_t or_port, uint16_t dir_port, const char *digest, uint8_t dir_purpose, uint8_t router_purpose, dir_indirection_t indirection, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since); #define DSR_HEX (1<<0) #define DSR_BASE64 (1<<1) #define DSR_DIGEST256 (1<<2) #define DSR_SORT_UNIQ (1<<3) int dir_split_resource_into_fingerprints(const char *resource, smartlist_t *fp_out, int *compressed_out, int flags); int dir_split_resource_into_fingerprint_pairs(const char *res, smartlist_t *pairs_out); char *directory_dump_request_log(void); void note_request(const char *key, size_t bytes); int router_supports_extrainfo(const char *identity_digest, int is_authority); time_t download_status_increment_failure(download_status_t *dls, int status_code, const char *item, int server, time_t now); /** Increment the failure count of the download_status_t dls, with * the optional status code sc. */ #define download_status_failed(dls, sc) \ download_status_increment_failure((dls), (sc), NULL, \ get_options()->DirPort_set, time(NULL)) void download_status_reset(download_status_t *dls); static int download_status_is_ready(download_status_t *dls, time_t now, int max_failures); /** Return true iff, as of now, the resource tracked by dls is * ready to get its download reattempted. */ static INLINE int download_status_is_ready(download_status_t *dls, time_t now, int max_failures) { return (dls->n_download_failures <= max_failures && dls->next_attempt_at <= now); } static void download_status_mark_impossible(download_status_t *dl); /** Mark dl as never downloadable. */ static INLINE void download_status_mark_impossible(download_status_t *dl) { dl->n_download_failures = IMPOSSIBLE_TO_DOWNLOAD; } int download_status_get_n_failures(const download_status_t *dls); #endif tor-0.2.4.20/src/or/dnsserv.c0000644000175000017500000003112512166112777012535 00000000000000/* Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file dnsserv.c \brief Implements client-side DNS proxy server code. Note: * this is the DNS Server code, not the Server DNS code. Confused? This code * runs on client-side, and acts as a DNS server. The code in dns.c, on the * other hand, runs on Tor servers, and acts as a DNS client. **/ #include "or.h" #include "dnsserv.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "control.h" #include "main.h" #include "policies.h" #ifdef HAVE_EVENT2_DNS_H #include #include /* XXXX this implies we want an improved evdns */ #include #else #include "eventdns.h" #endif /** Helper function: called by evdns whenever the client sends a request to our * DNSPort. We need to eventually answer the request req. */ static void evdns_server_callback(struct evdns_server_request *req, void *data_) { const listener_connection_t *listener = data_; entry_connection_t *entry_conn; edge_connection_t *conn; int i = 0; struct evdns_server_question *q = NULL; struct sockaddr_storage addr; struct sockaddr *sa; int addrlen; tor_addr_t tor_addr; uint16_t port; int err = DNS_ERR_NONE; char *q_name; tor_assert(req); log_info(LD_APP, "Got a new DNS request!"); req->flags |= 0x80; /* set RA */ /* First, check whether the requesting address matches our SOCKSPolicy. */ if ((addrlen = evdns_server_request_get_requesting_addr(req, (struct sockaddr*)&addr, (socklen_t)sizeof(addr))) < 0) { log_warn(LD_APP, "Couldn't get requesting address."); evdns_server_request_respond(req, DNS_ERR_SERVERFAILED); return; } (void) addrlen; sa = (struct sockaddr*) &addr; if (tor_addr_from_sockaddr(&tor_addr, sa, &port)<0) { log_warn(LD_APP, "Requesting address wasn't recognized."); evdns_server_request_respond(req, DNS_ERR_SERVERFAILED); return; } if (!socks_policy_permits_address(&tor_addr)) { log_warn(LD_APP, "Rejecting DNS request from disallowed IP."); evdns_server_request_respond(req, DNS_ERR_REFUSED); return; } /* Now, let's find the first actual question of a type we can answer in this * DNS request. It makes us a little noncompliant to act like this; we * should fix that eventually if it turns out to make a difference for * anybody. */ if (req->nquestions == 0) { log_info(LD_APP, "No questions in DNS request; sending back nil reply."); evdns_server_request_respond(req, 0); return; } if (req->nquestions > 1) { log_info(LD_APP, "Got a DNS request with more than one question; I only " "handle one question at a time for now. Skipping the extras."); } for (i = 0; i < req->nquestions; ++i) { if (req->questions[i]->dns_question_class != EVDNS_CLASS_INET) continue; switch (req->questions[i]->type) { case EVDNS_TYPE_A: case EVDNS_TYPE_AAAA: case EVDNS_TYPE_PTR: q = req->questions[i]; default: break; } } if (!q) { log_info(LD_APP, "None of the questions we got were ones we're willing " "to support. Sending NOTIMPL."); evdns_server_request_respond(req, DNS_ERR_NOTIMPL); return; } if (q->type != EVDNS_TYPE_A && q->type != EVDNS_TYPE_AAAA) { tor_assert(q->type == EVDNS_TYPE_PTR); } /* Make sure the name isn't too long: This should be impossible, I think. */ if (err == DNS_ERR_NONE && strlen(q->name) > MAX_SOCKS_ADDR_LEN-1) err = DNS_ERR_FORMAT; if (err != DNS_ERR_NONE) { /* We got an error? Then send back an answer immediately; we're done. */ evdns_server_request_respond(req, err); return; } /* Make a new dummy AP connection, and attach the request to it. */ entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET); conn = ENTRY_TO_EDGE_CONN(entry_conn); TO_CONN(conn)->state = AP_CONN_STATE_RESOLVE_WAIT; conn->is_dns_request = 1; tor_addr_copy(&TO_CONN(conn)->addr, &tor_addr); TO_CONN(conn)->port = port; TO_CONN(conn)->address = tor_dup_addr(&tor_addr); if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA) entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE; else entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; strlcpy(entry_conn->socks_request->address, q->name, sizeof(entry_conn->socks_request->address)); entry_conn->socks_request->listener_type = listener->base_.type; entry_conn->dns_server_request = req; entry_conn->isolation_flags = listener->isolation_flags; entry_conn->session_group = listener->session_group; entry_conn->nym_epoch = get_signewnym_epoch(); if (connection_add(ENTRY_TO_CONN(entry_conn)) < 0) { log_warn(LD_APP, "Couldn't register dummy connection for DNS request"); evdns_server_request_respond(req, DNS_ERR_SERVERFAILED); connection_free(ENTRY_TO_CONN(entry_conn)); return; } control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0); /* Now, unless a controller asked us to leave streams unattached, * throw the connection over to get rewritten (which will * answer it immediately if it's in the cache, or completely bogus, or * automapped), and then attached to a circuit. */ log_info(LD_APP, "Passing request for %s to rewrite_and_attach.", escaped_safe_str_client(q->name)); q_name = tor_strdup(q->name); /* q could be freed in rewrite_and_attach */ connection_ap_rewrite_and_attach_if_allowed(entry_conn, NULL, NULL); /* Now, the connection is marked if it was bad. */ log_info(LD_APP, "Passed request for %s to rewrite_and_attach_if_allowed.", escaped_safe_str_client(q_name)); tor_free(q_name); } /** Helper function: called whenever the client sends a resolve request to our * controller. We need to eventually answer the request req. * Returns 0 if the controller will be getting (or has gotten) an event in * response; -1 if we couldn't launch the request. */ int dnsserv_launch_request(const char *name, int reverse, control_connection_t *control_conn) { entry_connection_t *entry_conn; edge_connection_t *conn; char *q_name; /* Make a new dummy AP connection, and attach the request to it. */ entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET); conn = ENTRY_TO_EDGE_CONN(entry_conn); conn->base_.state = AP_CONN_STATE_RESOLVE_WAIT; tor_addr_copy(&TO_CONN(conn)->addr, &control_conn->base_.addr); #ifdef AF_UNIX /* * The control connection can be AF_UNIX and if so tor_dup_addr will * unhelpfully say ""; say "(Tor_internal)" * instead. */ if (control_conn->base_.socket_family == AF_UNIX) { TO_CONN(conn)->port = 0; TO_CONN(conn)->address = tor_strdup("(Tor_internal)"); } else { TO_CONN(conn)->port = control_conn->base_.port; TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr); } #else TO_CONN(conn)->port = control_conn->base_.port; TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr); #endif if (reverse) entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; else entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE; conn->is_dns_request = 1; strlcpy(entry_conn->socks_request->address, name, sizeof(entry_conn->socks_request->address)); entry_conn->socks_request->listener_type = CONN_TYPE_CONTROL_LISTENER; entry_conn->original_dest_address = tor_strdup(name); entry_conn->session_group = SESSION_GROUP_CONTROL_RESOLVE; entry_conn->nym_epoch = get_signewnym_epoch(); entry_conn->isolation_flags = ISO_DEFAULT; if (connection_add(TO_CONN(conn))<0) { log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request"); connection_free(TO_CONN(conn)); return -1; } control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0); /* Now, unless a controller asked us to leave streams unattached, * throw the connection over to get rewritten (which will * answer it immediately if it's in the cache, or completely bogus, or * automapped), and then attached to a circuit. */ log_info(LD_APP, "Passing request for %s to rewrite_and_attach.", escaped_safe_str_client(name)); q_name = tor_strdup(name); /* q could be freed in rewrite_and_attach */ connection_ap_rewrite_and_attach_if_allowed(entry_conn, NULL, NULL); /* Now, the connection is marked if it was bad. */ log_info(LD_APP, "Passed request for %s to rewrite_and_attach_if_allowed.", escaped_safe_str_client(q_name)); tor_free(q_name); return 0; } /** If there is a pending request on conn that's waiting for an answer, * send back an error and free the request. */ void dnsserv_reject_request(entry_connection_t *conn) { if (conn->dns_server_request) { evdns_server_request_respond(conn->dns_server_request, DNS_ERR_SERVERFAILED); conn->dns_server_request = NULL; } } /** Look up the original name that corresponds to 'addr' in req. We use this * to preserve case in order to facilitate people using 0x20-hacks to avoid * DNS poisoning. */ static const char * evdns_get_orig_address(const struct evdns_server_request *req, int rtype, const char *addr) { int i, type; switch (rtype) { case RESOLVED_TYPE_IPV4: type = EVDNS_TYPE_A; break; case RESOLVED_TYPE_HOSTNAME: type = EVDNS_TYPE_PTR; break; case RESOLVED_TYPE_IPV6: type = EVDNS_TYPE_AAAA; break; default: tor_fragile_assert(); return addr; } for (i = 0; i < req->nquestions; ++i) { const struct evdns_server_question *q = req->questions[i]; if (q->type == type && !strcasecmp(q->name, addr)) return q->name; } return addr; } /** Tell the dns request waiting for an answer on conn that we have an * answer of type answer_type (RESOLVE_TYPE_IPV4/IPV6/ERR), of length * answer_len, in answer, with TTL ttl. Doesn't do * any caching; that's handled elsewhere. */ void dnsserv_resolved(entry_connection_t *conn, int answer_type, size_t answer_len, const char *answer, int ttl) { struct evdns_server_request *req = conn->dns_server_request; const char *name; int err = DNS_ERR_NONE; if (!req) return; name = evdns_get_orig_address(req, answer_type, conn->socks_request->address); /* XXXX Re-do; this is dumb. */ if (ttl < 60) ttl = 60; /* The evdns interface is: add a bunch of reply items (corresponding to one * or more of the questions in the request); then, call * evdns_server_request_respond. */ if (answer_type == RESOLVED_TYPE_IPV6) { evdns_server_request_add_aaaa_reply(req, name, 1, answer, ttl); } else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4 && conn->socks_request->command == SOCKS_COMMAND_RESOLVE) { evdns_server_request_add_a_reply(req, name, 1, answer, ttl); } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256 && conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR) { char *ans = tor_strndup(answer, answer_len); evdns_server_request_add_ptr_reply(req, NULL, name, ans, ttl); tor_free(ans); } else if (answer_type == RESOLVED_TYPE_ERROR) { err = DNS_ERR_NOTEXIST; } else { /* answer_type == RESOLVED_TYPE_ERROR_TRANSIENT */ err = DNS_ERR_SERVERFAILED; } evdns_server_request_respond(req, err); conn->dns_server_request = NULL; } /** Set up the evdns server port for the UDP socket on conn, which * must be an AP_DNS_LISTENER */ void dnsserv_configure_listener(connection_t *conn) { listener_connection_t *listener_conn; tor_assert(conn); tor_assert(SOCKET_OK(conn->s)); tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER); listener_conn = TO_LISTENER_CONN(conn); listener_conn->dns_server_port = tor_evdns_add_server_port(conn->s, 0, evdns_server_callback, listener_conn); } /** Free the evdns server port for conn, which must be an * AP_DNS_LISTENER. */ void dnsserv_close_listener(connection_t *conn) { listener_connection_t *listener_conn; tor_assert(conn); tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER); listener_conn = TO_LISTENER_CONN(conn); if (listener_conn->dns_server_port) { evdns_close_server_port(listener_conn->dns_server_port); listener_conn->dns_server_port = NULL; } } tor-0.2.4.20/src/or/circuitbuild.c0000644000175000017500000037447312255745673013561 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file circuitbuild.c * \brief The actual details of building circuits. **/ #include "or.h" #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuitstats.h" #include "circuituse.h" #include "command.h" #include "config.h" #include "confparse.h" #include "connection.h" #include "connection_edge.h" #include "connection_or.h" #include "control.h" #include "directory.h" #include "entrynodes.h" #include "main.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "onion.h" #include "onion_tap.h" #include "onion_fast.h" #include "policies.h" #include "transports.h" #include "relay.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" #include "routerset.h" #include "crypto.h" #include "connection_edge.h" #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif /********* START VARIABLES **********/ /** A global list of all circuits at this hop. */ extern circuit_t *global_circuitlist; /********* END VARIABLES ************/ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port, const char *id_digest); static int circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell, int relayed); static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit); static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); static int onion_extend_cpath(origin_circuit_t *circ); static int count_acceptable_nodes(smartlist_t *routers); static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static int entry_guard_inc_circ_attempt_count(entry_guard_t *guard); static void pathbias_count_build_success(origin_circuit_t *circ); static void pathbias_count_successful_close(origin_circuit_t *circ); static void pathbias_count_collapse(origin_circuit_t *circ); static void pathbias_count_use_failed(origin_circuit_t *circ); static void pathbias_measure_use_rate(entry_guard_t *guard); static void pathbias_measure_close_rate(entry_guard_t *guard); static void pathbias_scale_use_rates(entry_guard_t *guard); /** This function tries to get a channel to the specified endpoint, * and then calls command_setup_channel() to give it the right * callbacks. */ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port, const char *id_digest) { channel_t *chan; chan = channel_connect(addr, port, id_digest); if (chan) command_setup_channel(chan); return chan; } /** Iterate over values of circ_id, starting from conn-\>next_circ_id, * and with the high bit specified by conn-\>circ_id_type, until we get * a circ_id that is not in use by any other circuit on that conn. * * Return it, or 0 if can't get a unique circ_id. */ static circid_t get_unique_circ_id_by_chan(channel_t *chan) { circid_t test_circ_id; circid_t attempts=0; circid_t high_bit, max_range; tor_assert(chan); if (chan->circ_id_type == CIRC_ID_TYPE_NEITHER) { log_warn(LD_BUG, "Trying to pick a circuit ID for a connection from " "a client with no identity."); return 0; } max_range = (chan->wide_circ_ids) ? (1u<<31) : (1u<<15); high_bit = (chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ? max_range : 0; do { /* Sequentially iterate over test_circ_id=1...max_range until we find a * circID such that (high_bit|test_circ_id) is not already used. */ test_circ_id = chan->next_circ_id++; if (test_circ_id == 0 || test_circ_id >= max_range) { test_circ_id = 1; chan->next_circ_id = 2; } if (++attempts > max_range) { /* Make sure we don't loop forever if all circ_id's are used. This * matters because it's an external DoS opportunity. */ log_warn(LD_CIRC,"No unused circ IDs. Failing."); return 0; } test_circ_id |= high_bit; } while (circuit_id_in_use_on_channel(test_circ_id, chan)); return test_circ_id; } /** If verbose is false, allocate and return a comma-separated list of * the currently built elements of circ. If verbose is true, also * list information about link status in a more verbose format using spaces. * If verbose_names is false, give nicknames for Named routers and hex * digests for others; if verbose_names is true, use $DIGEST=Name style * names. */ static char * circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names) { crypt_path_t *hop; smartlist_t *elements; const char *states[] = {"closed", "waiting for keys", "open"}; char *s; elements = smartlist_new(); if (verbose) { const char *nickname = build_state_get_exit_nickname(circ->build_state); smartlist_add_asprintf(elements, "%s%s circ (length %d%s%s):", circ->build_state->is_internal ? "internal" : "exit", circ->build_state->need_uptime ? " (high-uptime)" : "", circ->build_state->desired_path_len, circ->base_.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ", circ->base_.state == CIRCUIT_STATE_OPEN ? "" : (nickname?nickname:"*unnamed*")); } hop = circ->cpath; do { char *elt; const char *id; const node_t *node; if (!hop) break; if (!verbose && hop->state != CPATH_STATE_OPEN) break; if (!hop->extend_info) break; id = hop->extend_info->identity_digest; if (verbose_names) { elt = tor_malloc(MAX_VERBOSE_NICKNAME_LEN+1); if ((node = node_get_by_id(id))) { node_get_verbose_nickname(node, elt); } else if (is_legal_nickname(hop->extend_info->nickname)) { elt[0] = '$'; base16_encode(elt+1, HEX_DIGEST_LEN+1, id, DIGEST_LEN); elt[HEX_DIGEST_LEN+1]= '~'; strlcpy(elt+HEX_DIGEST_LEN+2, hop->extend_info->nickname, MAX_NICKNAME_LEN+1); } else { elt[0] = '$'; base16_encode(elt+1, HEX_DIGEST_LEN+1, id, DIGEST_LEN); } } else { /* ! verbose_names */ node = node_get_by_id(id); if (node && node_is_named(node)) { elt = tor_strdup(node_get_nickname(node)); } else { elt = tor_malloc(HEX_DIGEST_LEN+2); elt[0] = '$'; base16_encode(elt+1, HEX_DIGEST_LEN+1, id, DIGEST_LEN); } } tor_assert(elt); if (verbose) { tor_assert(hop->state <= 2); smartlist_add_asprintf(elements,"%s(%s)",elt,states[hop->state]); tor_free(elt); } else { smartlist_add(elements, elt); } hop = hop->next; } while (hop != circ->cpath); s = smartlist_join_strings(elements, verbose?" ":",", 0, NULL); SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp)); smartlist_free(elements); return s; } /** If verbose is false, allocate and return a comma-separated * list of the currently built elements of circ. If * verbose is true, also list information about link status in * a more verbose format using spaces. */ char * circuit_list_path(origin_circuit_t *circ, int verbose) { return circuit_list_path_impl(circ, verbose, 0); } /** Allocate and return a comma-separated list of the currently built elements * of circ, giving each as a verbose nickname. */ char * circuit_list_path_for_controller(origin_circuit_t *circ) { return circuit_list_path_impl(circ, 0, 1); } /** Log, at severity severity, the nicknames of each router in * circ's cpath. Also log the length of the cpath, and the intended * exit point. */ void circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ) { char *s = circuit_list_path(circ,1); tor_log(severity,domain,"%s",s); tor_free(s); } /** Tell the rep(utation)hist(ory) module about the status of the links * in circ. Hops that have become OPEN are marked as successfully * extended; the _first_ hop that isn't open (if any) is marked as * unable to extend. */ /* XXXX Someday we should learn from OR circuits too. */ void circuit_rep_hist_note_result(origin_circuit_t *circ) { crypt_path_t *hop; const char *prev_digest = NULL; hop = circ->cpath; if (!hop) /* circuit hasn't started building yet. */ return; if (server_mode(get_options())) { const routerinfo_t *me = router_get_my_routerinfo(); if (!me) return; prev_digest = me->cache_info.identity_digest; } do { const node_t *node = node_get_by_id(hop->extend_info->identity_digest); if (node) { /* Why do we check this? We know the identity. -NM XXXX */ if (prev_digest) { if (hop->state == CPATH_STATE_OPEN) rep_hist_note_extend_succeeded(prev_digest, node->identity); else { rep_hist_note_extend_failed(prev_digest, node->identity); break; } } prev_digest = node->identity; } else { prev_digest = NULL; } hop=hop->next; } while (hop!=circ->cpath); } /** Pick all the entries in our cpath. Stop and return 0 when we're * happy, or return -1 if an error occurs. */ static int onion_populate_cpath(origin_circuit_t *circ) { int r; again: r = onion_extend_cpath(circ); if (r < 0) { log_info(LD_CIRC,"Generating cpath hop failed."); return -1; } if (r == 0) goto again; return 0; /* if r == 1 */ } /** Create and return a new origin circuit. Initialize its purpose and * build-state based on our arguments. The flags argument is a * bitfield of CIRCLAUNCH_* flags. */ origin_circuit_t * origin_circuit_init(uint8_t purpose, int flags) { /* sets circ->p_circ_id and circ->p_chan */ origin_circuit_t *circ = origin_circuit_new(); circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_CHAN_WAIT); circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); circ->build_state->onehop_tunnel = ((flags & CIRCLAUNCH_ONEHOP_TUNNEL) ? 1 : 0); circ->build_state->need_uptime = ((flags & CIRCLAUNCH_NEED_UPTIME) ? 1 : 0); circ->build_state->need_capacity = ((flags & CIRCLAUNCH_NEED_CAPACITY) ? 1 : 0); circ->build_state->is_internal = ((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0); circ->base_.purpose = purpose; return circ; } /** Build a new circuit for purpose. If exit * is defined, then use that as your exit router, else choose a suitable * exit node. * * Also launch a connection to the first OR in the chosen path, if * it's not open already. */ origin_circuit_t * circuit_establish_circuit(uint8_t purpose, extend_info_t *exit, int flags) { origin_circuit_t *circ; int err_reason = 0; circ = origin_circuit_init(purpose, flags); if (onion_pick_cpath_exit(circ, exit) < 0 || onion_populate_cpath(circ) < 0) { circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH); return NULL; } control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED, 0); if ((err_reason = circuit_handle_first_hop(circ)) < 0) { circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); return NULL; } return circ; } /** Start establishing the first hop of our circuit. Figure out what * OR we should connect to, and if necessary start the connection to * it. If we're already connected, then send the 'create' cell. * Return 0 for ok, -reason if circ should be marked-for-close. */ int circuit_handle_first_hop(origin_circuit_t *circ) { crypt_path_t *firsthop; channel_t *n_chan; int err_reason = 0; const char *msg = NULL; int should_launch = 0; firsthop = onion_next_hop_in_cpath(circ->cpath); tor_assert(firsthop); tor_assert(firsthop->extend_info); /* now see if we're already connected to the first OR in 'route' */ log_debug(LD_CIRC,"Looking for firsthop '%s'", fmt_addrport(&firsthop->extend_info->addr, firsthop->extend_info->port)); n_chan = channel_get_for_extend(firsthop->extend_info->identity_digest, &firsthop->extend_info->addr, &msg, &should_launch); if (!n_chan) { /* not currently connected in a useful way. */ log_info(LD_CIRC, "Next router is %s: %s", safe_str_client(extend_info_describe(firsthop->extend_info)), msg?msg:"???"); circ->base_.n_hop = extend_info_dup(firsthop->extend_info); if (should_launch) { if (circ->build_state->onehop_tunnel) control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0); n_chan = channel_connect_for_circuit( &firsthop->extend_info->addr, firsthop->extend_info->port, firsthop->extend_info->identity_digest); if (!n_chan) { /* connect failed, forget the whole thing */ log_info(LD_CIRC,"connect to firsthop failed. Closing."); return -END_CIRC_REASON_CONNECTFAILED; } } log_debug(LD_CIRC,"connecting in progress (or finished). Good."); /* return success. The onion/circuit/etc will be taken care of * automatically (may already have been) whenever n_chan reaches * OR_CONN_STATE_OPEN. */ return 0; } else { /* it's already open. use it. */ tor_assert(!circ->base_.n_hop); circ->base_.n_chan = n_chan; log_debug(LD_CIRC,"Conn open. Delivering first onion skin."); if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) { log_info(LD_CIRC,"circuit_send_next_onion_skin failed."); return err_reason; } } return 0; } /** Find any circuits that are waiting on or_conn to become * open and get them to send their create cells forward. * * Status is 1 if connect succeeded, or 0 if connect failed. */ void circuit_n_chan_done(channel_t *chan, int status) { smartlist_t *pending_circs; int err_reason = 0; tor_assert(chan); log_debug(LD_CIRC,"chan to %s/%s, status=%d", chan->nickname ? chan->nickname : "NULL", channel_get_canonical_remote_descr(chan), status); pending_circs = smartlist_new(); circuit_get_all_pending_on_channel(pending_circs, chan); SMARTLIST_FOREACH_BEGIN(pending_circs, circuit_t *, circ) { /* These checks are redundant wrt get_all_pending_on_or_conn, but I'm * leaving them in in case it's possible for the status of a circuit to * change as we're going down the list. */ if (circ->marked_for_close || circ->n_chan || !circ->n_hop || circ->state != CIRCUIT_STATE_CHAN_WAIT) continue; if (tor_digest_is_zero(circ->n_hop->identity_digest)) { /* Look at addr/port. This is an unkeyed connection. */ if (!channel_matches_extend_info(chan, circ->n_hop)) continue; } else { /* We expected a key. See if it's the right one. */ if (tor_memneq(chan->identity_digest, circ->n_hop->identity_digest, DIGEST_LEN)) continue; } if (!status) { /* chan failed; close circ */ log_info(LD_CIRC,"Channel failed; closing circ."); circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED); continue; } log_debug(LD_CIRC, "Found circ, sending create cell."); /* circuit_deliver_create_cell will set n_circ_id and add us to * chan_circuid_circuit_map, so we don't need to call * set_circid_chan here. */ circ->n_chan = chan; extend_info_free(circ->n_hop); circ->n_hop = NULL; if (CIRCUIT_IS_ORIGIN(circ)) { if ((err_reason = circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ))) < 0) { log_info(LD_CIRC, "send_next_onion_skin failed; circuit marked for closing."); circuit_mark_for_close(circ, -err_reason); continue; /* XXX could this be bad, eg if next_onion_skin failed because conn * died? */ } } else { /* pull the create cell out of circ->n_chan_create_cell, and send it */ tor_assert(circ->n_chan_create_cell); if (circuit_deliver_create_cell(circ, circ->n_chan_create_cell, 1)<0) { circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); continue; } tor_free(circ->n_chan_create_cell); circuit_set_state(circ, CIRCUIT_STATE_OPEN); } } SMARTLIST_FOREACH_END(circ); smartlist_free(pending_circs); } /** Find a new circid that isn't currently in use on the circ->n_chan * for the outgoing * circuit circ, and deliver the cell create_cell to this * circuit. If relayed is true, this is a create cell somebody * gave us via an EXTEND cell, so we shouldn't worry if we don't understand * it. Return -1 if we failed to find a suitable circid, else return 0. */ static int circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell, int relayed) { cell_t cell; circid_t id; int r; tor_assert(circ); tor_assert(circ->n_chan); tor_assert(create_cell); tor_assert(create_cell->cell_type == CELL_CREATE || create_cell->cell_type == CELL_CREATE_FAST || create_cell->cell_type == CELL_CREATE2); id = get_unique_circ_id_by_chan(circ->n_chan); if (!id) { log_warn(LD_CIRC,"failed to get unique circID."); return -1; } log_debug(LD_CIRC,"Chosen circID %u.", (unsigned)id); circuit_set_n_circid_chan(circ, id, circ->n_chan); memset(&cell, 0, sizeof(cell_t)); r = relayed ? create_cell_format_relayed(&cell, create_cell) : create_cell_format(&cell, create_cell); if (r < 0) { log_warn(LD_CIRC,"Couldn't format create cell"); return -1; } cell.circ_id = circ->n_circ_id; append_cell_to_circuit_queue(circ, circ->n_chan, &cell, CELL_DIRECTION_OUT, 0); if (CIRCUIT_IS_ORIGIN(circ)) { /* Update began timestamp for circuits starting their first hop */ if (TO_ORIGIN_CIRCUIT(circ)->cpath->state == CPATH_STATE_CLOSED) { if (circ->n_chan->state != CHANNEL_STATE_OPEN) { log_warn(LD_CIRC, "Got first hop for a circuit without an opened channel. " "State: %s.", channel_state_to_string(circ->n_chan->state)); tor_fragile_assert(); } tor_gettimeofday(&circ->timestamp_began); } /* mark it so it gets better rate limiting treatment. */ channel_timestamp_client(circ->n_chan); } return 0; } /** We've decided to start our reachability testing. If all * is set, log this to the user. Return 1 if we did, or 0 if * we chose not to log anything. */ int inform_testing_reachability(void) { char dirbuf[128]; const routerinfo_t *me = router_get_my_routerinfo(); if (!me) return 0; control_event_server_status(LOG_NOTICE, "CHECKING_REACHABILITY ORADDRESS=%s:%d", me->address, me->or_port); if (me->dir_port) { tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d", me->address, me->dir_port); control_event_server_status(LOG_NOTICE, "CHECKING_REACHABILITY DIRADDRESS=%s:%d", me->address, me->dir_port); } log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... " "(this may take up to %d minutes -- look for log " "messages indicating success)", me->address, me->or_port, me->dir_port ? dirbuf : "", me->dir_port ? "are" : "is", TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60); return 1; } /** Return true iff we should send a create_fast cell to start building a given * circuit */ static INLINE int should_use_create_fast_for_circuit(origin_circuit_t *circ) { const or_options_t *options = get_options(); tor_assert(circ->cpath); tor_assert(circ->cpath->extend_info); if (!circ->cpath->extend_info->onion_key) return 1; /* our hand is forced: only a create_fast will work. */ if (!options->FastFirstHopPK) return 0; /* we prefer to avoid create_fast */ if (public_server_mode(options)) { /* We're a server, and we know an onion key. We can choose. * Prefer to blend our circuit into the other circuits we are * creating on behalf of others. */ return 0; } return 1; } /** Return true if circ is the type of circuit we want to count * timeouts from. In particular, we want it to have not completed yet * (already completing indicates we cannibalized it), and we want it to * have exactly three hops. */ int circuit_timeout_want_to_count_circ(origin_circuit_t *circ) { return !circ->has_opened && circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN; } #ifdef CURVE25519_ENABLED /** Return true if the ntor handshake is enabled in the configuration, or if * it's been set to "auto" in the configuration and it's enabled in the * consensus. */ static int circuits_can_use_ntor(void) { const or_options_t *options = get_options(); if (options->UseNTorHandshake != -1) return options->UseNTorHandshake; return networkstatus_get_param(NULL, "UseNTorHandshake", 0, 0, 1); } #endif /** Decide whether to use a TAP or ntor handshake for connecting to ei * directly, and set *cell_type_out and *handshake_type_out * accordingly. */ static void circuit_pick_create_handshake(uint8_t *cell_type_out, uint16_t *handshake_type_out, const extend_info_t *ei) { #ifdef CURVE25519_ENABLED if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key, CURVE25519_PUBKEY_LEN) && circuits_can_use_ntor()) { *cell_type_out = CELL_CREATE2; *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; return; } #else (void) ei; #endif *cell_type_out = CELL_CREATE; *handshake_type_out = ONION_HANDSHAKE_TYPE_TAP; } /** Decide whether to use a TAP or ntor handshake for connecting to ei * directly, and set *handshake_type_out accordingly. Decide whether, * in extending through node to do so, we should use an EXTEND2 or an * EXTEND cell to do so, and set *cell_type_out and * *create_cell_type_out accordingly. */ static void circuit_pick_extend_handshake(uint8_t *cell_type_out, uint8_t *create_cell_type_out, uint16_t *handshake_type_out, const node_t *node_prev, const extend_info_t *ei) { uint8_t t; circuit_pick_create_handshake(&t, handshake_type_out, ei); /* XXXX024 The check for whether the node has a curve25519 key is a bad * proxy for whether it can do extend2 cells; once a version that * handles extend2 cells is out, remove it. */ if (node_prev && *handshake_type_out != ONION_HANDSHAKE_TYPE_TAP && (node_has_curve25519_onion_key(node_prev) || (node_prev->rs && node_prev->rs->version_supports_extend2_cells))) { *cell_type_out = RELAY_COMMAND_EXTEND2; *create_cell_type_out = CELL_CREATE2; } else { *cell_type_out = RELAY_COMMAND_EXTEND; *create_cell_type_out = CELL_CREATE; } } /** This is the backbone function for building circuits. * * If circ's first hop is closed, then we need to build a create * cell and send it forward. * * Otherwise, we need to build a relay extend cell and send it * forward. * * Return -reason if we want to tear down circ, else return 0. */ int circuit_send_next_onion_skin(origin_circuit_t *circ) { crypt_path_t *hop; const node_t *node; tor_assert(circ); if (circ->cpath->state == CPATH_STATE_CLOSED) { /* This is the first hop. */ create_cell_t cc; int fast; int len; log_debug(LD_CIRC,"First skin; sending create cell."); memset(&cc, 0, sizeof(cc)); if (circ->build_state->onehop_tunnel) control_event_bootstrap(BOOTSTRAP_STATUS_ONEHOP_CREATE, 0); else control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0); node = node_get_by_id(circ->base_.n_chan->identity_digest); fast = should_use_create_fast_for_circuit(circ); if (!fast) { /* We are an OR and we know the right onion key: we should * send a create cell. */ circuit_pick_create_handshake(&cc.cell_type, &cc.handshake_type, circ->cpath->extend_info); note_request("cell: create", 1); } else { /* We are not an OR, and we're building the first hop of a circuit to a * new OR: we can be speedy and use CREATE_FAST to save an RSA operation * and a DH operation. */ cc.cell_type = CELL_CREATE_FAST; cc.handshake_type = ONION_HANDSHAKE_TYPE_FAST; note_request("cell: create fast", 1); } len = onion_skin_create(cc.handshake_type, circ->cpath->extend_info, &circ->cpath->handshake_state, cc.onionskin); if (len < 0) { log_warn(LD_CIRC,"onion_skin_create (first hop) failed."); return - END_CIRC_REASON_INTERNAL; } cc.handshake_len = len; if (circuit_deliver_create_cell(TO_CIRCUIT(circ), &cc, 0) < 0) return - END_CIRC_REASON_RESOURCELIMIT; circ->cpath->state = CPATH_STATE_AWAITING_KEYS; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'", fast ? "CREATE_FAST" : "CREATE", node ? node_describe(node) : ""); } else { extend_cell_t ec; int len; tor_assert(circ->cpath->state == CPATH_STATE_OPEN); tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING); log_debug(LD_CIRC,"starting to send subsequent skin."); hop = onion_next_hop_in_cpath(circ->cpath); memset(&ec, 0, sizeof(ec)); if (!hop) { /* done building the circuit. whew. */ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); if (circuit_timeout_want_to_count_circ(circ)) { struct timeval end; long timediff; tor_gettimeofday(&end); timediff = tv_mdiff(&circ->base_.timestamp_began, &end); /* * If the circuit build time is much greater than we would have cut * it off at, we probably had a suspend event along this codepath, * and we should discard the value. */ if (timediff < 0 || timediff > 2*circ_times.close_ms+1000) { log_notice(LD_CIRC, "Strange value for circuit build time: %ldmsec. " "Assuming clock jump. Purpose %d (%s)", timediff, circ->base_.purpose, circuit_purpose_to_string(circ->base_.purpose)); } else if (!circuit_build_times_disabled()) { /* Only count circuit times if the network is live */ if (circuit_build_times_network_check_live(&circ_times)) { circuit_build_times_add_time(&circ_times, (build_time_t)timediff); circuit_build_times_set_timeout(&circ_times); } if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { circuit_build_times_network_circ_success(&circ_times); } } } log_info(LD_CIRC,"circuit built!"); circuit_reset_failure_count(0); if (circ->build_state->onehop_tunnel || circ->has_opened) { control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0); } pathbias_count_build_success(circ); circuit_rep_hist_note_result(circ); circuit_has_opened(circ); /* do other actions as necessary */ if (!can_complete_circuit && !circ->build_state->onehop_tunnel) { const or_options_t *options = get_options(); can_complete_circuit=1; /* FFFF Log a count of known routers here */ log_notice(LD_GENERAL, "Tor has successfully opened a circuit. " "Looks like client functionality is working."); control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0); control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED"); clear_broken_connection_map(1); if (server_mode(options) && !check_whether_orport_reachable()) { inform_testing_reachability(); consider_testing_reachability(1, 1); } } /* We're done with measurement circuits here. Just close them */ if (circ->base_.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); } return 0; } if (tor_addr_family(&hop->extend_info->addr) != AF_INET) { log_warn(LD_BUG, "Trying to extend to a non-IPv4 address."); return - END_CIRC_REASON_INTERNAL; } { const node_t *prev_node; prev_node = node_get_by_id(hop->prev->extend_info->identity_digest); circuit_pick_extend_handshake(&ec.cell_type, &ec.create_cell.cell_type, &ec.create_cell.handshake_type, prev_node, hop->extend_info); } tor_addr_copy(&ec.orport_ipv4.addr, &hop->extend_info->addr); ec.orport_ipv4.port = hop->extend_info->port; tor_addr_make_unspec(&ec.orport_ipv6.addr); memcpy(ec.node_id, hop->extend_info->identity_digest, DIGEST_LEN); len = onion_skin_create(ec.create_cell.handshake_type, hop->extend_info, &hop->handshake_state, ec.create_cell.onionskin); if (len < 0) { log_warn(LD_CIRC,"onion_skin_create failed."); return - END_CIRC_REASON_INTERNAL; } ec.create_cell.handshake_len = len; log_info(LD_CIRC,"Sending extend relay cell."); note_request("cell: extend", 1); { uint8_t command = 0; uint16_t payload_len=0; uint8_t payload[RELAY_PAYLOAD_SIZE]; if (extend_cell_format(&command, &payload_len, payload, &ec)<0) { log_warn(LD_CIRC,"Couldn't format extend cell"); return -END_CIRC_REASON_INTERNAL; } /* send it to hop->prev, because it will transfer * it to a create cell and then send to hop */ if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), command, (char*)payload, payload_len, hop->prev) < 0) return 0; /* circuit is closed */ } hop->state = CPATH_STATE_AWAITING_KEYS; } return 0; } /** Our clock just jumped by seconds_elapsed. Assume * something has also gone wrong with our network: notify the user, * and abandon all not-yet-used circuits. */ void circuit_note_clock_jumped(int seconds_elapsed) { int severity = server_mode(get_options()) ? LOG_WARN : LOG_NOTICE; tor_log(severity, LD_GENERAL, "Your system clock just jumped %d seconds %s; " "assuming established circuits no longer work.", seconds_elapsed >=0 ? seconds_elapsed : -seconds_elapsed, seconds_elapsed >=0 ? "forward" : "backward"); control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME=%d", seconds_elapsed); can_complete_circuit=0; /* so it'll log when it works again */ control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s", "CLOCK_JUMPED"); circuit_mark_all_unused_circs(); circuit_mark_all_dirty_circs_as_unusable(); } /** Take the 'extend' cell, pull out addr/port plus the onion * skin and identity digest for the next hop. If we're already connected, * pass the onion skin to the next hop using a create cell; otherwise * launch a new OR connection, and circ will notice when the * connection succeeds or fails. * * Return -1 if we want to warn and tear down the circuit, else return 0. */ int circuit_extend(cell_t *cell, circuit_t *circ) { channel_t *n_chan; relay_header_t rh; extend_cell_t ec; const char *msg = NULL; int should_launch = 0; if (circ->n_chan) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "n_chan already set. Bug/attack. Closing."); return -1; } if (circ->n_hop) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "conn to next hop already launched. Bug/attack. Closing."); return -1; } if (!server_mode(get_options())) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Got an extend cell, but running as a client. Closing."); return -1; } relay_header_unpack(&rh, cell->payload); if (extend_cell_parse(&ec, rh.command, cell->payload+RELAY_HEADER_SIZE, rh.length) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Can't parse extend cell. Closing circuit."); return -1; } if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Client asked me to extend to zero destination port or addr."); return -1; } if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) && !get_options()->ExtendAllowPrivateAddresses) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Client asked me to extend to a private address"); return -1; } /* Check if they asked us for 0000..0000. We support using * an empty fingerprint for the first hop (e.g. for a bridge relay), * but we don't want to let people send us extend cells for empty * fingerprints -- a) because it opens the user up to a mitm attack, * and b) because it lets an attacker force the relay to hold open a * new TLS connection for each extend request. */ if (tor_digest_is_zero((const char*)ec.node_id)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Client asked me to extend without specifying an id_digest."); return -1; } /* Next, check if we're being asked to connect to the hop that the * extend cell came from. There isn't any reason for that, and it can * assist circular-path attacks. */ if (tor_memeq(ec.node_id, TO_OR_CIRCUIT(circ)->p_chan->identity_digest, DIGEST_LEN)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Client asked me to extend back to the previous hop."); return -1; } n_chan = channel_get_for_extend((const char*)ec.node_id, &ec.orport_ipv4.addr, &msg, &should_launch); if (!n_chan) { log_debug(LD_CIRC|LD_OR,"Next router (%s): %s", fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port), msg?msg:"????"); circ->n_hop = extend_info_new(NULL /*nickname*/, (const char*)ec.node_id, NULL /*onion_key*/, NULL /*curve25519_key*/, &ec.orport_ipv4.addr, ec.orport_ipv4.port); circ->n_chan_create_cell = tor_memdup(&ec.create_cell, sizeof(ec.create_cell)); circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT); if (should_launch) { /* we should try to open a connection */ n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr, ec.orport_ipv4.port, (const char*)ec.node_id); if (!n_chan) { log_info(LD_CIRC,"Launching n_chan failed. Closing circuit."); circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED); return 0; } log_debug(LD_CIRC,"connecting in progress (or finished). Good."); } /* return success. The onion/circuit/etc will be taken care of * automatically (may already have been) whenever n_chan reaches * OR_CONN_STATE_OPEN. */ return 0; } tor_assert(!circ->n_hop); /* Connection is already established. */ circ->n_chan = n_chan; log_debug(LD_CIRC, "n_chan is %s", channel_get_canonical_remote_descr(n_chan)); if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0) return -1; return 0; } /** Initialize cpath-\>{f|b}_{crypto|digest} from the key material in * key_data. key_data must contain CPATH_KEY_MATERIAL bytes, which are * used as follows: * - 20 to initialize f_digest * - 20 to initialize b_digest * - 16 to key f_crypto * - 16 to key b_crypto * * (If 'reverse' is true, then f_XX and b_XX are swapped.) */ int circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data, int reverse) { crypto_digest_t *tmp_digest; crypto_cipher_t *tmp_crypto; tor_assert(cpath); tor_assert(key_data); tor_assert(!(cpath->f_crypto || cpath->b_crypto || cpath->f_digest || cpath->b_digest)); cpath->f_digest = crypto_digest_new(); crypto_digest_add_bytes(cpath->f_digest, key_data, DIGEST_LEN); cpath->b_digest = crypto_digest_new(); crypto_digest_add_bytes(cpath->b_digest, key_data+DIGEST_LEN, DIGEST_LEN); if (!(cpath->f_crypto = crypto_cipher_new(key_data+(2*DIGEST_LEN)))) { log_warn(LD_BUG,"Forward cipher initialization failed."); return -1; } if (!(cpath->b_crypto = crypto_cipher_new(key_data+(2*DIGEST_LEN)+CIPHER_KEY_LEN))) { log_warn(LD_BUG,"Backward cipher initialization failed."); return -1; } if (reverse) { tmp_digest = cpath->f_digest; cpath->f_digest = cpath->b_digest; cpath->b_digest = tmp_digest; tmp_crypto = cpath->f_crypto; cpath->f_crypto = cpath->b_crypto; cpath->b_crypto = tmp_crypto; } return 0; } /** The minimum number of circuit attempts before we start * thinking about warning about path bias and dropping guards */ static int pathbias_get_min_circs(const or_options_t *options) { #define DFLT_PATH_BIAS_MIN_CIRC 150 if (options->PathBiasCircThreshold >= 5) return options->PathBiasCircThreshold; else return networkstatus_get_param(NULL, "pb_mincircs", DFLT_PATH_BIAS_MIN_CIRC, 5, INT32_MAX); } /** The circuit success rate below which we issue a notice */ static double pathbias_get_notice_rate(const or_options_t *options) { #define DFLT_PATH_BIAS_NOTICE_PCT 70 if (options->PathBiasNoticeRate >= 0.0) return options->PathBiasNoticeRate; else return networkstatus_get_param(NULL, "pb_noticepct", DFLT_PATH_BIAS_NOTICE_PCT, 0, 100)/100.0; } /* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ /** The circuit success rate below which we issue a warn */ static double pathbias_get_warn_rate(const or_options_t *options) { #define DFLT_PATH_BIAS_WARN_PCT 50 if (options->PathBiasWarnRate >= 0.0) return options->PathBiasWarnRate; else return networkstatus_get_param(NULL, "pb_warnpct", DFLT_PATH_BIAS_WARN_PCT, 0, 100)/100.0; } /* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ /** * The extreme rate is the rate at which we would drop the guard, * if pb_dropguard is also set. Otherwise we just warn. */ double pathbias_get_extreme_rate(const or_options_t *options) { #define DFLT_PATH_BIAS_EXTREME_PCT 30 if (options->PathBiasExtremeRate >= 0.0) return options->PathBiasExtremeRate; else return networkstatus_get_param(NULL, "pb_extremepct", DFLT_PATH_BIAS_EXTREME_PCT, 0, 100)/100.0; } /* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ /** * If 1, we actually disable use of guards that fall below * the extreme_pct. */ int pathbias_get_dropguards(const or_options_t *options) { #define DFLT_PATH_BIAS_DROP_GUARDS 0 if (options->PathBiasDropGuards >= 0) return options->PathBiasDropGuards; else return networkstatus_get_param(NULL, "pb_dropguards", DFLT_PATH_BIAS_DROP_GUARDS, 0, 1); } /** * This is the number of circuits at which we scale our * counts by mult_factor/scale_factor. Note, this count is * not exact, as we only perform the scaling in the event * of no integer truncation. */ static int pathbias_get_scale_threshold(const or_options_t *options) { #define DFLT_PATH_BIAS_SCALE_THRESHOLD 300 if (options->PathBiasScaleThreshold >= 10) return options->PathBiasScaleThreshold; else return networkstatus_get_param(NULL, "pb_scalecircs", DFLT_PATH_BIAS_SCALE_THRESHOLD, 10, INT32_MAX); } /** * Compute the path bias scaling ratio from the consensus * parameters pb_multfactor/pb_scalefactor. * * Returns a value in (0, 1.0] which we multiply our pathbias * counts with to scale them down. */ static double pathbias_get_scale_ratio(const or_options_t *options) { /* * The scale factor is the denominator for our scaling * of circuit counts for our path bias window. * * Note that our use of doubles for the path bias state * file means that powers of 2 work best here. */ int denominator = networkstatus_get_param(NULL, "pb_scalefactor", 2, 2, INT32_MAX); (void) options; /** * The mult factor is the numerator for our scaling * of circuit counts for our path bias window. It * allows us to scale by fractions. */ return networkstatus_get_param(NULL, "pb_multfactor", 1, 1, denominator)/((double)denominator); } /** The minimum number of circuit usage attempts before we start * thinking about warning about path use bias and dropping guards */ static int pathbias_get_min_use(const or_options_t *options) { #define DFLT_PATH_BIAS_MIN_USE 20 if (options->PathBiasUseThreshold >= 3) return options->PathBiasUseThreshold; else return networkstatus_get_param(NULL, "pb_minuse", DFLT_PATH_BIAS_MIN_USE, 3, INT32_MAX); } /** The circuit use success rate below which we issue a notice */ static double pathbias_get_notice_use_rate(const or_options_t *options) { #define DFLT_PATH_BIAS_NOTICE_USE_PCT 80 if (options->PathBiasNoticeUseRate >= 0.0) return options->PathBiasNoticeUseRate; else return networkstatus_get_param(NULL, "pb_noticeusepct", DFLT_PATH_BIAS_NOTICE_USE_PCT, 0, 100)/100.0; } /** * The extreme use rate is the rate at which we would drop the guard, * if pb_dropguard is also set. Otherwise we just warn. */ double pathbias_get_extreme_use_rate(const or_options_t *options) { #define DFLT_PATH_BIAS_EXTREME_USE_PCT 60 if (options->PathBiasExtremeUseRate >= 0.0) return options->PathBiasExtremeUseRate; else return networkstatus_get_param(NULL, "pb_extremeusepct", DFLT_PATH_BIAS_EXTREME_USE_PCT, 0, 100)/100.0; } /** * This is the number of circuits at which we scale our * use counts by mult_factor/scale_factor. Note, this count is * not exact, as we only perform the scaling in the event * of no integer truncation. */ static int pathbias_get_scale_use_threshold(const or_options_t *options) { #define DFLT_PATH_BIAS_SCALE_USE_THRESHOLD 100 if (options->PathBiasScaleUseThreshold >= 10) return options->PathBiasScaleUseThreshold; else return networkstatus_get_param(NULL, "pb_scaleuse", DFLT_PATH_BIAS_SCALE_USE_THRESHOLD, 10, INT32_MAX); } /** * Convert a Guard's path state to string. */ const char * pathbias_state_to_string(path_state_t state) { switch (state) { case PATH_STATE_NEW_CIRC: return "new"; case PATH_STATE_BUILD_ATTEMPTED: return "build attempted"; case PATH_STATE_BUILD_SUCCEEDED: return "build succeeded"; case PATH_STATE_USE_ATTEMPTED: return "use attempted"; case PATH_STATE_USE_SUCCEEDED: return "use succeeded"; case PATH_STATE_USE_FAILED: return "use failed"; case PATH_STATE_ALREADY_COUNTED: return "already counted"; } return "unknown"; } /** * This function decides if a circuit has progressed far enough to count * as a circuit "attempt". As long as end-to-end tagging is possible, * we assume the adversary will use it over hop-to-hop failure. Therefore, * we only need to account bias for the last hop. This should make us * much more resilient to ambient circuit failure, and also make that * failure easier to measure (we only need to measure Exit failure rates). */ static int pathbias_is_new_circ_attempt(origin_circuit_t *circ) { #define N2N_TAGGING_IS_POSSIBLE #ifdef N2N_TAGGING_IS_POSSIBLE /* cpath is a circular list. We want circs with more than one hop, * and the second hop must be waiting for keys still (it's just * about to get them). */ return circ->cpath && circ->cpath->next != circ->cpath && circ->cpath->next->state == CPATH_STATE_AWAITING_KEYS; #else /* If tagging attacks are no longer possible, we probably want to * count bias from the first hop. However, one could argue that * timing-based tagging is still more useful than per-hop failure. * In which case, we'd never want to use this. */ return circ->cpath && circ->cpath->state == CPATH_STATE_AWAITING_KEYS; #endif } /** * Decide if the path bias code should count a circuit. * * @returns 1 if we should count it, 0 otherwise. */ static int pathbias_should_count(origin_circuit_t *circ) { #define PATHBIAS_COUNT_INTERVAL (600) static ratelim_t count_limit = RATELIM_INIT(PATHBIAS_COUNT_INTERVAL); char *rate_msg = NULL; /* We can't do path bias accounting without entry guards. * Testing and controller circuits also have no guards. * * We also don't count server-side rends, because their * endpoint could be chosen maliciously. * Similarly, we can't count client-side intro attempts, * because clients can be manipulated into connecting to * malicious intro points. */ if (get_options()->UseEntryGuards == 0 || circ->base_.purpose == CIRCUIT_PURPOSE_TESTING || circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER || circ->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED || (circ->base_.purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && circ->base_.purpose <= CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)) { /* Check to see if the shouldcount result has changed due to a * unexpected purpose change that would affect our results. * * The reason we check the path state too here is because for the * cannibalized versions of these purposes, we count them as successful * before their purpose change. */ if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_COUNTED && circ->path_state != PATH_STATE_ALREADY_COUNTED) { log_info(LD_BUG, "Circuit %d is now being ignored despite being counted " "in the past. Purpose is %s, path state is %s", circ->global_identifier, circuit_purpose_to_string(circ->base_.purpose), pathbias_state_to_string(circ->path_state)); } circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_IGNORED; return 0; } /* Completely ignore one hop circuits */ if (circ->build_state->onehop_tunnel || circ->build_state->desired_path_len == 1) { /* Check for inconsistency */ if (circ->build_state->desired_path_len != 1 || !circ->build_state->onehop_tunnel) { if ((rate_msg = rate_limit_log(&count_limit, approx_time()))) { log_info(LD_BUG, "One-hop circuit has length %d. Path state is %s. " "Circuit is a %s currently %s.%s", circ->build_state->desired_path_len, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } tor_fragile_assert(); } /* Check to see if the shouldcount result has changed due to a * unexpected change that would affect our results */ if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_COUNTED) { log_info(LD_BUG, "One-hop circuit %d is now being ignored despite being counted " "in the past. Purpose is %s, path state is %s", circ->global_identifier, circuit_purpose_to_string(circ->base_.purpose), pathbias_state_to_string(circ->path_state)); } circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_IGNORED; return 0; } /* Check to see if the shouldcount result has changed due to a * unexpected purpose change that would affect our results */ if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_IGNORED) { log_info(LD_BUG, "Circuit %d is now being counted despite being ignored " "in the past. Purpose is %s, path state is %s", circ->global_identifier, circuit_purpose_to_string(circ->base_.purpose), pathbias_state_to_string(circ->path_state)); } circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_COUNTED; return 1; } /** * Check our circuit state to see if this is a successful circuit attempt. * If so, record it in the current guard's path bias circ_attempt count. * * Also check for several potential error cases for bug #6475. */ static int pathbias_count_build_attempt(origin_circuit_t *circ) { #define CIRC_ATTEMPT_NOTICE_INTERVAL (600) static ratelim_t circ_attempt_notice_limit = RATELIM_INIT(CIRC_ATTEMPT_NOTICE_INTERVAL); char *rate_msg = NULL; if (!pathbias_should_count(circ)) { return 0; } if (pathbias_is_new_circ_attempt(circ)) { /* Help track down the real cause of bug #6475: */ if (circ->has_opened && circ->path_state != PATH_STATE_BUILD_ATTEMPTED) { if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit, approx_time()))) { log_info(LD_BUG, "Opened circuit is in strange path state %s. " "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } } /* Don't re-count cannibalized circs.. */ if (!circ->has_opened) { entry_guard_t *guard = NULL; if (circ->cpath && circ->cpath->extend_info) { guard = entry_guard_get_by_id_digest( circ->cpath->extend_info->identity_digest); } else if (circ->base_.n_chan) { guard = entry_guard_get_by_id_digest(circ->base_.n_chan->identity_digest); } if (guard) { if (circ->path_state == PATH_STATE_NEW_CIRC) { circ->path_state = PATH_STATE_BUILD_ATTEMPTED; if (entry_guard_inc_circ_attempt_count(guard) < 0) { /* Bogus guard; we already warned. */ return -END_CIRC_REASON_TORPROTOCOL; } } else { if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit, approx_time()))) { log_info(LD_BUG, "Unopened circuit has strange path state %s. " "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } } } else { if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit, approx_time()))) { log_info(LD_CIRC, "Unopened circuit has no known guard. " "Circuit is a %s currently %s.%s", circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } } } } return 0; } /** * Check our circuit state to see if this is a successful circuit * completion. If so, record it in the current guard's path bias * success count. * * Also check for several potential error cases for bug #6475. */ static void pathbias_count_build_success(origin_circuit_t *circ) { #define SUCCESS_NOTICE_INTERVAL (600) static ratelim_t success_notice_limit = RATELIM_INIT(SUCCESS_NOTICE_INTERVAL); char *rate_msg = NULL; entry_guard_t *guard = NULL; if (!pathbias_should_count(circ)) { return; } /* Don't count cannibalized/reused circs for path bias * "build" success, since they get counted under "use" success. */ if (!circ->has_opened) { if (circ->cpath && circ->cpath->extend_info) { guard = entry_guard_get_by_id_digest( circ->cpath->extend_info->identity_digest); } if (guard) { if (circ->path_state == PATH_STATE_BUILD_ATTEMPTED) { circ->path_state = PATH_STATE_BUILD_SUCCEEDED; guard->circ_successes++; entry_guards_changed(); log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)", guard->circ_successes, guard->circ_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } else { if ((rate_msg = rate_limit_log(&success_notice_limit, approx_time()))) { log_info(LD_BUG, "Succeeded circuit is in strange path state %s. " "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } } if (guard->circ_attempts < guard->circ_successes) { log_notice(LD_BUG, "Unexpectedly high successes counts (%f/%f) " "for guard %s ($%s)", guard->circ_successes, guard->circ_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. * No need to log that case. */ } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { if ((rate_msg = rate_limit_log(&success_notice_limit, approx_time()))) { log_info(LD_CIRC, "Completed circuit has no known guard. " "Circuit is a %s currently %s.%s", circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } } } else { if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) { if ((rate_msg = rate_limit_log(&success_notice_limit, approx_time()))) { log_info(LD_BUG, "Opened circuit is in strange path state %s. " "Circuit is a %s currently %s.%s", pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), rate_msg); tor_free(rate_msg); } } } } /** * Record an attempt to use a circuit. Changes the circuit's * path state and update its guard's usage counter. * * Used for path bias usage accounting. */ void pathbias_count_use_attempt(origin_circuit_t *circ) { entry_guard_t *guard; if (!pathbias_should_count(circ)) { return; } if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) { log_notice(LD_BUG, "Used circuit is in strange path state %s. " "Circuit is a %s currently %s.", pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state)); } else if (circ->path_state < PATH_STATE_USE_ATTEMPTED) { guard = entry_guard_get_by_id_digest( circ->cpath->extend_info->identity_digest); if (guard) { pathbias_measure_use_rate(guard); pathbias_scale_use_rates(guard); guard->use_attempts++; entry_guards_changed(); log_debug(LD_CIRC, "Marked circuit %d (%f/%f) as used for guard %s ($%s).", circ->global_identifier, guard->use_successes, guard->use_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } circ->path_state = PATH_STATE_USE_ATTEMPTED; } else { /* Harmless but educational log message */ log_info(LD_CIRC, "Used circuit %d is already in path state %s. " "Circuit is a %s currently %s.", circ->global_identifier, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state)); } return; } /** * Check the circuit's path state is appropriate and mark it as * successfully used. Used for path bias usage accounting. * * We don't actually increment the guard's counters until * pathbias_check_close(), because the circuit can still transition * back to PATH_STATE_USE_ATTEMPTED if a stream fails later (this * is done so we can probe the circuit for liveness at close). */ void pathbias_mark_use_success(origin_circuit_t *circ) { if (!pathbias_should_count(circ)) { return; } if (circ->path_state < PATH_STATE_USE_ATTEMPTED) { log_notice(LD_BUG, "Used circuit %d is in strange path state %s. " "Circuit is a %s currently %s.", circ->global_identifier, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state)); pathbias_count_use_attempt(circ); } /* We don't do any accounting at the guard until actual circuit close */ circ->path_state = PATH_STATE_USE_SUCCEEDED; return; } /** * If a stream ever detatches from a circuit in a retriable way, * we need to mark this circuit as still needing either another * successful stream, or in need of a probe. * * An adversary could let the first stream request succeed (ie the * resolve), but then tag and timeout the remainder (via cell * dropping), forcing them on new circuits. * * Rolling back the state will cause us to probe such circuits, which * should lead to probe failures in the event of such tagging due to * either unrecognized cells coming in while we wait for the probe, * or the cipher state getting out of sync in the case of dropped cells. */ void pathbias_mark_use_rollback(origin_circuit_t *circ) { if (circ->path_state == PATH_STATE_USE_SUCCEEDED) { log_info(LD_CIRC, "Rolling back pathbias use state to 'attempted' for detached " "circuit %d", circ->global_identifier); circ->path_state = PATH_STATE_USE_ATTEMPTED; } } /** * Actually count a circuit success towards a guard's usage counters * if the path state is appropriate. */ static void pathbias_count_use_success(origin_circuit_t *circ) { entry_guard_t *guard; if (!pathbias_should_count(circ)) { return; } if (circ->path_state != PATH_STATE_USE_SUCCEEDED) { log_notice(LD_BUG, "Successfully used circuit %d is in strange path state %s. " "Circuit is a %s currently %s.", circ->global_identifier, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state)); } else { guard = entry_guard_get_by_id_digest( circ->cpath->extend_info->identity_digest); if (guard) { guard->use_successes++; entry_guards_changed(); if (guard->use_attempts < guard->use_successes) { log_notice(LD_BUG, "Unexpectedly high use successes counts (%f/%f) " "for guard %s=%s", guard->use_successes, guard->use_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } log_debug(LD_CIRC, "Marked circuit %d (%f/%f) as used successfully for guard " "%s ($%s).", circ->global_identifier, guard->use_successes, guard->use_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } } return; } /** * Send a probe down a circuit that the client attempted to use, * but for which the stream timed out/failed. The probe is a * RELAY_BEGIN cell with a 0.a.b.c destination address, which * the exit will reject and reply back, echoing that address. * * The reason for such probes is because it is possible to bias * a user's paths simply by causing timeouts, and these timeouts * are not possible to differentiate from unresponsive servers. * * The probe is sent at the end of the circuit lifetime for two * reasons: to prevent cryptographic taggers from being able to * drop cells to cause timeouts, and to prevent easy recognition * of probes before any real client traffic happens. * * Returns -1 if we couldn't probe, 0 otherwise. */ static int pathbias_send_usable_probe(circuit_t *circ) { /* Based on connection_ap_handshake_send_begin() */ char payload[CELL_PAYLOAD_SIZE]; int payload_len; origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); crypt_path_t *cpath_layer = NULL; char *probe_nonce = NULL; tor_assert(ocirc); cpath_layer = ocirc->cpath->prev; if (cpath_layer->state != CPATH_STATE_OPEN) { /* This can happen for cannibalized circuits. Their * last hop isn't yet open */ log_info(LD_CIRC, "Got pathbias probe request for unopened circuit %d. " "Opened %d, len %d", ocirc->global_identifier, ocirc->has_opened, ocirc->build_state->desired_path_len); return -1; } /* We already went down this road. */ if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING && ocirc->pathbias_probe_id) { log_info(LD_CIRC, "Got pathbias probe request for circuit %d with " "outstanding probe", ocirc->global_identifier); return -1; } /* Can't probe if the channel isn't open */ if (circ->n_chan == NULL || (circ->n_chan->state != CHANNEL_STATE_OPEN && circ->n_chan->state != CHANNEL_STATE_MAINT)) { log_info(LD_CIRC, "Skipping pathbias probe for circuit %d: Channel is not open.", ocirc->global_identifier); return -1; } circuit_change_purpose(circ, CIRCUIT_PURPOSE_PATH_BIAS_TESTING); /* Update timestamp for when circuit_expire_building() should kill us */ tor_gettimeofday(&circ->timestamp_began); /* Generate a random address for the nonce */ crypto_rand((char*)ô->pathbias_probe_nonce, sizeof(ocirc->pathbias_probe_nonce)); ocirc->pathbias_probe_nonce &= 0x00ffffff; probe_nonce = tor_dup_ip(ocirc->pathbias_probe_nonce); tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:25", probe_nonce); payload_len = (int)strlen(payload)+1; // XXX: need this? Can we assume ipv4 will always be supported? // If not, how do we tell? //if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) { // set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags)); // payload_len += 4; //} /* Generate+Store stream id, make sure it's non-zero */ ocirc->pathbias_probe_id = get_unique_stream_id_by_circ(ocirc); if (ocirc->pathbias_probe_id==0) { log_warn(LD_CIRC, "Ran out of stream IDs on circuit %u during " "pathbias probe attempt.", ocirc->global_identifier); tor_free(probe_nonce); return -1; } log_info(LD_CIRC, "Sending pathbias testing cell to %s:25 on stream %d for circ %d.", probe_nonce, ocirc->pathbias_probe_id, ocirc->global_identifier); tor_free(probe_nonce); /* Send a test relay cell */ if (relay_send_command_from_edge(ocirc->pathbias_probe_id, circ, RELAY_COMMAND_BEGIN, payload, payload_len, cpath_layer) < 0) { log_notice(LD_CIRC, "Failed to send pathbias probe cell on circuit %d.", ocirc->global_identifier); return -1; } /* Mark it freshly dirty so it doesn't get expired in the meantime */ circ->timestamp_dirty = time(NULL); return 0; } /** * Check the response to a pathbias probe, to ensure the * cell is recognized and the nonce and other probe * characteristics are as expected. * * If the response is valid, return 0. Otherwise return < 0. */ int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell) { /* Based on connection_edge_process_relay_cell() */ relay_header_t rh; int reason; uint32_t ipv4_host; origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); tor_assert(cell); tor_assert(ocirc); tor_assert(circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING); relay_header_unpack(&rh, cell->payload); reason = rh.length > 0 ? get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC; if (rh.command == RELAY_COMMAND_END && reason == END_STREAM_REASON_EXITPOLICY && ocirc->pathbias_probe_id == rh.stream_id) { /* Check length+extract host: It is in network order after the reason code. * See connection_edge_end(). */ if (rh.length < 9) { /* reason+ipv4+dns_ttl */ log_notice(LD_PROTOCOL, "Short path bias probe response length field (%d).", rh.length); return - END_CIRC_REASON_TORPROTOCOL; } ipv4_host = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); /* Check nonce */ if (ipv4_host == ocirc->pathbias_probe_nonce) { pathbias_mark_use_success(ocirc); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); log_info(LD_CIRC, "Got valid path bias probe back for circ %d, stream %d.", ocirc->global_identifier, ocirc->pathbias_probe_id); return 0; } else { log_notice(LD_CIRC, "Got strange probe value 0x%x vs 0x%x back for circ %d, " "stream %d.", ipv4_host, ocirc->pathbias_probe_nonce, ocirc->global_identifier, ocirc->pathbias_probe_id); return -1; } } log_info(LD_CIRC, "Got another cell back back on pathbias probe circuit %d: " "Command: %d, Reason: %d, Stream-id: %d", ocirc->global_identifier, rh.command, reason, rh.stream_id); return -1; } /** * Check if a circuit was used and/or closed successfully. * * If we attempted to use the circuit to carry a stream but failed * for whatever reason, or if the circuit mysteriously died before * we could attach any streams, record these two cases. * * If we *have* successfully used the circuit, or it appears to * have been closed by us locally, count it as a success. * * Returns 0 if we're done making decisions with the circ, * or -1 if we want to probe it first. */ int pathbias_check_close(origin_circuit_t *ocirc, int reason) { circuit_t *circ = ô->base_; if (!pathbias_should_count(ocirc)) { return 0; } switch (ocirc->path_state) { /* If the circuit was closed after building, but before use, we need * to ensure we were the ones who tried to close it (and not a remote * actor). */ case PATH_STATE_BUILD_SUCCEEDED: if (reason & END_CIRC_REASON_FLAG_REMOTE) { /* Remote circ close reasons on an unused circuit all could be bias */ log_info(LD_CIRC, "Circuit %d remote-closed without successful use for reason %d. " "Circuit purpose %d currently %d,%s. Len %d.", ocirc->global_identifier, reason, circ->purpose, ocirc->has_opened, circuit_state_to_string(circ->state), ocirc->build_state->desired_path_len); pathbias_count_collapse(ocirc); } else if ((reason & ~END_CIRC_REASON_FLAG_REMOTE) == END_CIRC_REASON_CHANNEL_CLOSED && circ->n_chan && circ->n_chan->reason_for_closing != CHANNEL_CLOSE_REQUESTED) { /* If we didn't close the channel ourselves, it could be bias */ /* XXX: Only count bias if the network is live? * What about clock jumps/suspends? */ log_info(LD_CIRC, "Circuit %d's channel closed without successful use for reason " "%d, channel reason %d. Circuit purpose %d currently %d,%s. Len " "%d.", ocirc->global_identifier, reason, circ->n_chan->reason_for_closing, circ->purpose, ocirc->has_opened, circuit_state_to_string(circ->state), ocirc->build_state->desired_path_len); pathbias_count_collapse(ocirc); } else { pathbias_count_successful_close(ocirc); } break; /* If we tried to use a circuit but failed, we should probe it to ensure * it has not been tampered with. */ case PATH_STATE_USE_ATTEMPTED: /* XXX: Only probe and/or count failure if the network is live? * What about clock jumps/suspends? */ if (pathbias_send_usable_probe(circ) == 0) return -1; else pathbias_count_use_failed(ocirc); /* Any circuit where there were attempted streams but no successful * streams could be bias */ log_info(LD_CIRC, "Circuit %d closed without successful use for reason %d. " "Circuit purpose %d currently %d,%s. Len %d.", ocirc->global_identifier, reason, circ->purpose, ocirc->has_opened, circuit_state_to_string(circ->state), ocirc->build_state->desired_path_len); break; case PATH_STATE_USE_SUCCEEDED: pathbias_count_successful_close(ocirc); pathbias_count_use_success(ocirc); break; case PATH_STATE_USE_FAILED: pathbias_count_use_failed(ocirc); break; case PATH_STATE_NEW_CIRC: case PATH_STATE_BUILD_ATTEMPTED: case PATH_STATE_ALREADY_COUNTED: default: // Other states are uninteresting. No stats to count. break; } ocirc->path_state = PATH_STATE_ALREADY_COUNTED; return 0; } /** * Count a successfully closed circuit. */ static void pathbias_count_successful_close(origin_circuit_t *circ) { entry_guard_t *guard = NULL; if (!pathbias_should_count(circ)) { return; } if (circ->cpath && circ->cpath->extend_info) { guard = entry_guard_get_by_id_digest( circ->cpath->extend_info->identity_digest); } if (guard) { /* In the long run: circuit_success ~= successful_circuit_close + * circ_failure + stream_failure */ guard->successful_circuits_closed++; entry_guards_changed(); } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. * No need to log that case. */ log_info(LD_CIRC, "Successfully closed circuit has no known guard. " "Circuit is a %s currently %s", circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state)); } } /** * Count a circuit that fails after it is built, but before it can * carry any traffic. * * This is needed because there are ways to destroy a * circuit after it has successfully completed. Right now, this is * used for purely informational/debugging purposes. */ static void pathbias_count_collapse(origin_circuit_t *circ) { entry_guard_t *guard = NULL; if (!pathbias_should_count(circ)) { return; } if (circ->cpath && circ->cpath->extend_info) { guard = entry_guard_get_by_id_digest( circ->cpath->extend_info->identity_digest); } if (guard) { guard->collapsed_circuits++; entry_guards_changed(); } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. * No need to log that case. */ log_info(LD_CIRC, "Destroyed circuit has no known guard. " "Circuit is a %s currently %s", circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state)); } } /** * Count a known failed circuit (because we could not probe it). * * This counter is informational. */ static void pathbias_count_use_failed(origin_circuit_t *circ) { entry_guard_t *guard = NULL; if (!pathbias_should_count(circ)) { return; } if (circ->cpath && circ->cpath->extend_info) { guard = entry_guard_get_by_id_digest( circ->cpath->extend_info->identity_digest); } if (guard) { guard->unusable_circuits++; entry_guards_changed(); } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. * No need to log that case. */ /* XXX note cut-and-paste code in this function compared to nearby * functions. Would be nice to refactor. -RD */ log_info(LD_CIRC, "Stream-failing circuit has no known guard. " "Circuit is a %s currently %s", circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state)); } } /** * Count timeouts for path bias log messages. * * These counts are purely informational. */ void pathbias_count_timeout(origin_circuit_t *circ) { entry_guard_t *guard = NULL; if (!pathbias_should_count(circ)) { return; } /* For hidden service circs, they can actually be used * successfully and then time out later (because * the other side declines to use them). */ if (circ->path_state == PATH_STATE_USE_SUCCEEDED) { return; } if (circ->cpath && circ->cpath->extend_info) { guard = entry_guard_get_by_id_digest( circ->cpath->extend_info->identity_digest); } if (guard) { guard->timeouts++; entry_guards_changed(); } } /** * Helper function to count all of the currently opened circuits * for a guard that are in a given path state range. The state * range is inclusive on both ends. */ static int pathbias_count_circs_in_states(entry_guard_t *guard, path_state_t from, path_state_t to) { circuit_t *circ; int open_circuits = 0; /* Count currently open circuits. Give them the benefit of the doubt. */ for (circ = global_circuitlist; circ; circ = circ->next) { origin_circuit_t *ocirc = NULL; if (!CIRCUIT_IS_ORIGIN(circ) || /* didn't originate here */ circ->marked_for_close) /* already counted */ continue; ocirc = TO_ORIGIN_CIRCUIT(circ); if (!ocirc->cpath || !ocirc->cpath->extend_info) continue; if (ocirc->path_state >= from && ocirc->path_state <= to && pathbias_should_count(ocirc) && fast_memeq(guard->identity, ocirc->cpath->extend_info->identity_digest, DIGEST_LEN)) { log_debug(LD_CIRC, "Found opened circuit %d in path_state %s", ocirc->global_identifier, pathbias_state_to_string(ocirc->path_state)); open_circuits++; } } return open_circuits; } /** * Return the number of circuits counted as successfully closed for * this guard. * * Also add in the currently open circuits to give them the benefit * of the doubt. */ double pathbias_get_close_success_count(entry_guard_t *guard) { return guard->successful_circuits_closed + pathbias_count_circs_in_states(guard, PATH_STATE_BUILD_SUCCEEDED, PATH_STATE_USE_SUCCEEDED); } /** * Return the number of circuits counted as successfully used * this guard. * * Also add in the currently open circuits that we are attempting * to use to give them the benefit of the doubt. */ double pathbias_get_use_success_count(entry_guard_t *guard) { return guard->use_successes + pathbias_count_circs_in_states(guard, PATH_STATE_USE_ATTEMPTED, PATH_STATE_USE_SUCCEEDED); } /** * Check the path bias use rate against our consensus parameter limits. * * Emits a log message if the use success rates are too low. * * If pathbias_get_dropguards() is set, we also disable the use of * very failure prone guards. */ static void pathbias_measure_use_rate(entry_guard_t *guard) { const or_options_t *options = get_options(); if (guard->use_attempts > pathbias_get_min_use(options)) { /* Note: We rely on the < comparison here to allow us to set a 0 * rate and disable the feature entirely. If refactoring, don't * change to <= */ if (pathbias_get_use_success_count(guard)/guard->use_attempts < pathbias_get_extreme_use_rate(options)) { /* Dropping is currently disabled by default. */ if (pathbias_get_dropguards(options)) { if (!guard->path_bias_disabled) { log_warn(LD_CIRC, "Your Guard %s ($%s) is failing to carry an extremely large " "amount of stream on its circuits. " "To avoid potential route manipulation attacks, Tor has " "disabled use of this guard. " "Use counts are %ld/%ld. Success counts are %ld/%ld. " "%ld circuits completed, %ld were unusable, %ld collapsed, " "and %ld timed out. " "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), tor_lround(pathbias_get_use_success_count(guard)), tor_lround(guard->use_attempts), tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); guard->path_bias_disabled = 1; guard->bad_since = approx_time(); entry_guards_changed(); return; } } else if (!guard->path_bias_use_extreme) { guard->path_bias_use_extreme = 1; log_warn(LD_CIRC, "Your Guard %s ($%s) is failing to carry an extremely large " "amount of streams on its circuits. " "This could indicate a route manipulation attack, network " "overload, bad local network connectivity, or a bug. " "Use counts are %ld/%ld. Success counts are %ld/%ld. " "%ld circuits completed, %ld were unusable, %ld collapsed, " "and %ld timed out. " "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), tor_lround(pathbias_get_use_success_count(guard)), tor_lround(guard->use_attempts), tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); } } else if (pathbias_get_use_success_count(guard)/guard->use_attempts < pathbias_get_notice_use_rate(options)) { if (!guard->path_bias_use_noticed) { guard->path_bias_use_noticed = 1; log_notice(LD_CIRC, "Your Guard %s ($%s) is failing to carry more streams on its " "circuits than usual. " "Most likely this means the Tor network is overloaded " "or your network connection is poor. " "Use counts are %ld/%ld. Success counts are %ld/%ld. " "%ld circuits completed, %ld were unusable, %ld collapsed, " "and %ld timed out. " "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), tor_lround(pathbias_get_use_success_count(guard)), tor_lround(guard->use_attempts), tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); } } } } /** * Check the path bias circuit close status rates against our consensus * parameter limits. * * Emits a log message if the use success rates are too low. * * If pathbias_get_dropguards() is set, we also disable the use of * very failure prone guards. * * XXX: This function shares similar log messages and checks to * pathbias_measure_use_rate(). It may be possible to combine them * eventually, especially if we can ever remove the need for 3 * levels of closure warns (if the overall circuit failure rate * goes down with ntor). One way to do so would be to multiply * the build rate with the use rate to get an idea of the total * fraction of the total network paths the user is able to use. * See ticket #8159. */ static void pathbias_measure_close_rate(entry_guard_t *guard) { const or_options_t *options = get_options(); if (guard->circ_attempts > pathbias_get_min_circs(options)) { /* Note: We rely on the < comparison here to allow us to set a 0 * rate and disable the feature entirely. If refactoring, don't * change to <= */ if (pathbias_get_close_success_count(guard)/guard->circ_attempts < pathbias_get_extreme_rate(options)) { /* Dropping is currently disabled by default. */ if (pathbias_get_dropguards(options)) { if (!guard->path_bias_disabled) { log_warn(LD_CIRC, "Your Guard %s ($%s) is failing an extremely large " "amount of circuits. " "To avoid potential route manipulation attacks, Tor has " "disabled use of this guard. " "Success counts are %ld/%ld. Use counts are %ld/%ld. " "%ld circuits completed, %ld were unusable, %ld collapsed, " "and %ld timed out. " "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), tor_lround(pathbias_get_use_success_count(guard)), tor_lround(guard->use_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); guard->path_bias_disabled = 1; guard->bad_since = approx_time(); entry_guards_changed(); return; } } else if (!guard->path_bias_extreme) { guard->path_bias_extreme = 1; log_warn(LD_CIRC, "Your Guard %s ($%s) is failing an extremely large " "amount of circuits. " "This could indicate a route manipulation attack, " "extreme network overload, or a bug. " "Success counts are %ld/%ld. Use counts are %ld/%ld. " "%ld circuits completed, %ld were unusable, %ld collapsed, " "and %ld timed out. " "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), tor_lround(pathbias_get_use_success_count(guard)), tor_lround(guard->use_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); } } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts < pathbias_get_warn_rate(options)) { if (!guard->path_bias_warned) { guard->path_bias_warned = 1; log_warn(LD_CIRC, "Your Guard %s ($%s) is failing a very large " "amount of circuits. " "Most likely this means the Tor network is " "overloaded, but it could also mean an attack against " "you or potentially the guard itself. " "Success counts are %ld/%ld. Use counts are %ld/%ld. " "%ld circuits completed, %ld were unusable, %ld collapsed, " "and %ld timed out. " "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), tor_lround(pathbias_get_use_success_count(guard)), tor_lround(guard->use_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); } } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts < pathbias_get_notice_rate(options)) { if (!guard->path_bias_noticed) { guard->path_bias_noticed = 1; log_notice(LD_CIRC, "Your Guard %s ($%s) is failing more circuits than " "usual. " "Most likely this means the Tor network is overloaded. " "Success counts are %ld/%ld. Use counts are %ld/%ld. " "%ld circuits completed, %ld were unusable, %ld collapsed, " "and %ld timed out. " "For reference, your timeout cutoff is %ld seconds.", guard->nickname, hex_str(guard->identity, DIGEST_LEN), tor_lround(pathbias_get_close_success_count(guard)), tor_lround(guard->circ_attempts), tor_lround(pathbias_get_use_success_count(guard)), tor_lround(guard->use_attempts), tor_lround(guard->circ_successes), tor_lround(guard->unusable_circuits), tor_lround(guard->collapsed_circuits), tor_lround(guard->timeouts), tor_lround(circ_times.close_ms/1000)); } } } } /** * This function scales the path bias use rates if we have * more data than the scaling threshold. This allows us to * be more sensitive to recent measurements. * * XXX: The attempt count transfer stuff here might be done * better by keeping separate pending counters that get * transfered at circuit close. See ticket #8160. */ static void pathbias_scale_close_rates(entry_guard_t *guard) { const or_options_t *options = get_options(); /* If we get a ton of circuits, just scale everything down */ if (guard->circ_attempts > pathbias_get_scale_threshold(options)) { double scale_ratio = pathbias_get_scale_ratio(options); int opened_attempts = pathbias_count_circs_in_states(guard, PATH_STATE_BUILD_ATTEMPTED, PATH_STATE_BUILD_ATTEMPTED); int opened_built = pathbias_count_circs_in_states(guard, PATH_STATE_BUILD_SUCCEEDED, PATH_STATE_USE_FAILED); /* Verify that the counts are sane before and after scaling */ int counts_are_sane = (guard->circ_attempts >= guard->circ_successes); guard->circ_attempts -= (opened_attempts+opened_built); guard->circ_successes -= opened_built; guard->circ_attempts *= scale_ratio; guard->circ_successes *= scale_ratio; guard->timeouts *= scale_ratio; guard->successful_circuits_closed *= scale_ratio; guard->collapsed_circuits *= scale_ratio; guard->unusable_circuits *= scale_ratio; guard->circ_attempts += (opened_attempts+opened_built); guard->circ_successes += opened_built; entry_guards_changed(); log_info(LD_CIRC, "Scaled pathbias counts to (%f,%f)/%f (%d/%d open) for guard " "%s ($%s)", guard->circ_successes, guard->successful_circuits_closed, guard->circ_attempts, opened_built, opened_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); /* Have the counts just become invalid by this scaling attempt? */ if (counts_are_sane && guard->circ_attempts < guard->circ_successes) { log_notice(LD_BUG, "Scaling has mangled pathbias counts to %f/%f (%d/%d open) " "for guard %s ($%s)", guard->circ_successes, guard->circ_attempts, opened_built, opened_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } } } /** * This function scales the path bias circuit close rates if we have * more data than the scaling threshold. This allows us to be more * sensitive to recent measurements. * * XXX: The attempt count transfer stuff here might be done * better by keeping separate pending counters that get * transfered at circuit close. See ticket #8160. */ void pathbias_scale_use_rates(entry_guard_t *guard) { const or_options_t *options = get_options(); /* If we get a ton of circuits, just scale everything down */ if (guard->use_attempts > pathbias_get_scale_use_threshold(options)) { double scale_ratio = pathbias_get_scale_ratio(options); int opened_attempts = pathbias_count_circs_in_states(guard, PATH_STATE_USE_ATTEMPTED, PATH_STATE_USE_SUCCEEDED); /* Verify that the counts are sane before and after scaling */ int counts_are_sane = (guard->use_attempts >= guard->use_successes); guard->use_attempts -= opened_attempts; guard->use_attempts *= scale_ratio; guard->use_successes *= scale_ratio; guard->use_attempts += opened_attempts; log_info(LD_CIRC, "Scaled pathbias use counts to %f/%f (%d open) for guard %s ($%s)", guard->use_successes, guard->use_attempts, opened_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); /* Have the counts just become invalid by this scaling attempt? */ if (counts_are_sane && guard->use_attempts < guard->use_successes) { log_notice(LD_BUG, "Scaling has mangled pathbias usage counts to %f/%f " "(%d open) for guard %s ($%s)", guard->circ_successes, guard->circ_attempts, opened_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } entry_guards_changed(); } } /** Increment the number of times we successfully extended a circuit to * guard, first checking if the failure rate is high enough that * we should eliminate the guard. Return -1 if the guard looks no good; * return 0 if the guard looks fine. */ static int entry_guard_inc_circ_attempt_count(entry_guard_t *guard) { entry_guards_changed(); pathbias_measure_close_rate(guard); if (guard->path_bias_disabled) return -1; pathbias_scale_close_rates(guard); guard->circ_attempts++; log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)", guard->circ_successes, guard->circ_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); return 0; } /** A "created" cell reply came back to us on circuit circ. * (The body of reply varies depending on what sort of handshake * this is.) * * Calculate the appropriate keys and digests, make sure KH is * correct, and initialize this hop of the cpath. * * Return - reason if we want to mark circ for close, else return 0. */ int circuit_finish_handshake(origin_circuit_t *circ, const created_cell_t *reply) { char keys[CPATH_KEY_MATERIAL_LEN]; crypt_path_t *hop; int rv; if ((rv = pathbias_count_build_attempt(circ)) < 0) return rv; if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) { hop = circ->cpath; } else { hop = onion_next_hop_in_cpath(circ->cpath); if (!hop) { /* got an extended when we're all done? */ log_warn(LD_PROTOCOL,"got extended when circ already built? Closing."); return - END_CIRC_REASON_TORPROTOCOL; } } tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS); { if (onion_skin_client_handshake(hop->handshake_state.tag, &hop->handshake_state, reply->reply, reply->handshake_len, (uint8_t*)keys, sizeof(keys), (uint8_t*)hop->rend_circ_nonce) < 0) { log_warn(LD_CIRC,"onion_skin_client_handshake failed."); return -END_CIRC_REASON_TORPROTOCOL; } } onion_handshake_state_release(&hop->handshake_state); if (circuit_init_cpath_crypto(hop, keys, 0)<0) { return -END_CIRC_REASON_TORPROTOCOL; } hop->state = CPATH_STATE_OPEN; log_info(LD_CIRC,"Finished building circuit hop:"); circuit_log_path(LOG_INFO,LD_CIRC,circ); control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0); return 0; } /** We received a relay truncated cell on circ. * * Since we don't send truncates currently, getting a truncated * means that a connection broke or an extend failed. For now, * just give up: force circ to close, and return 0. */ int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason) { // crypt_path_t *victim; // connection_t *stream; tor_assert(circ); tor_assert(layer); /* XXX Since we don't send truncates currently, getting a truncated * means that a connection broke or an extend failed. For now, * just give up. */ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FLAG_REMOTE|reason); return 0; #if 0 while (layer->next != circ->cpath) { /* we need to clear out layer->next */ victim = layer->next; log_debug(LD_CIRC, "Killing a layer of the cpath."); for (stream = circ->p_streams; stream; stream=stream->next_stream) { if (stream->cpath_layer == victim) { log_info(LD_APP, "Marking stream %d for close because of truncate.", stream->stream_id); /* no need to send 'end' relay cells, * because the other side's already dead */ connection_mark_unattached_ap(stream, END_STREAM_REASON_DESTROY); } } layer->next = victim->next; circuit_free_cpath_node(victim); } log_info(LD_CIRC, "finished"); return 0; #endif } /** Given a response payload and keys, initialize, then send a created * cell back. */ int onionskin_answer(or_circuit_t *circ, const created_cell_t *created_cell, const char *keys, const uint8_t *rend_circ_nonce) { cell_t cell; crypt_path_t *tmp_cpath; if (created_cell_format(&cell, created_cell) < 0) { log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d)", (int)created_cell->cell_type, (int)created_cell->handshake_len); return -1; } cell.circ_id = circ->p_circ_id; tmp_cpath = tor_malloc_zero(sizeof(crypt_path_t)); tmp_cpath->magic = CRYPT_PATH_MAGIC; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.", (unsigned int)get_uint32(keys), (unsigned int)get_uint32(keys+20)); if (circuit_init_cpath_crypto(tmp_cpath, keys, 0)<0) { log_warn(LD_BUG,"Circuit initialization failed"); tor_free(tmp_cpath); return -1; } circ->n_digest = tmp_cpath->f_digest; circ->n_crypto = tmp_cpath->f_crypto; circ->p_digest = tmp_cpath->b_digest; circ->p_crypto = tmp_cpath->b_crypto; tmp_cpath->magic = 0; tor_free(tmp_cpath); memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN); circ->is_first_hop = (created_cell->cell_type == CELL_CREATED_FAST); append_cell_to_circuit_queue(TO_CIRCUIT(circ), circ->p_chan, &cell, CELL_DIRECTION_IN, 0); log_debug(LD_CIRC,"Finished sending '%s' cell.", circ->is_first_hop ? "created_fast" : "created"); if (!channel_is_local(circ->p_chan) && !channel_is_outgoing(circ->p_chan)) { /* record that we could process create cells from a non-local conn * that we didn't initiate; presumably this means that create cells * can reach us too. */ router_orport_found_reachable(); } return 0; } /** Choose a length for a circuit of purpose purpose: three + the * number of endpoints that would give something away about our destination. * * If the routerlist nodes doesn't have enough routers * to handle the desired path length, return as large a path length as * is feasible, except if it's less than 2, in which case return -1. * XXX ^^ I think this behavior is a hold-over from back when we had only a * few relays in the network, and certainly back before guards existed. * We should very likely get rid of it. -RD */ static int new_route_len(uint8_t purpose, extend_info_t *exit, smartlist_t *nodes) { int num_acceptable_routers; int routelen; tor_assert(nodes); routelen = DEFAULT_ROUTE_LEN; if (exit && purpose != CIRCUIT_PURPOSE_TESTING && purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) routelen++; num_acceptable_routers = count_acceptable_nodes(nodes); log_debug(LD_CIRC,"Chosen route length %d (%d/%d routers suitable).", routelen, num_acceptable_routers, smartlist_len(nodes)); if (num_acceptable_routers < 2) { log_info(LD_CIRC, "Not enough acceptable routers (%d). Discarding this circuit.", num_acceptable_routers); return -1; } if (num_acceptable_routers < routelen) { log_info(LD_CIRC,"Not enough routers: cutting routelen from %d to %d.", routelen, num_acceptable_routers); routelen = num_acceptable_routers; } return routelen; } /** Return a newly allocated list of uint16_t * for each predicted port not * handled by a current circuit. */ static smartlist_t * circuit_get_unhandled_ports(time_t now) { smartlist_t *dest = rep_hist_get_predicted_ports(now); circuit_remove_handled_ports(dest); return dest; } /** Return 1 if we already have circuits present or on the way for * all anticipated ports. Return 0 if we should make more. * * If we're returning 0, set need_uptime and need_capacity to * indicate any requirements that the unhandled ports have. */ int circuit_all_predicted_ports_handled(time_t now, int *need_uptime, int *need_capacity) { int i, enough; uint16_t *port; smartlist_t *sl = circuit_get_unhandled_ports(now); smartlist_t *LongLivedServices = get_options()->LongLivedPorts; tor_assert(need_uptime); tor_assert(need_capacity); // Always predict need_capacity *need_capacity = 1; enough = (smartlist_len(sl) == 0); for (i = 0; i < smartlist_len(sl); ++i) { port = smartlist_get(sl, i); if (smartlist_contains_int_as_string(LongLivedServices, *port)) *need_uptime = 1; tor_free(port); } smartlist_free(sl); return enough; } /** Return 1 if node can handle one or more of the ports in * needed_ports, else return 0. */ static int node_handles_some_port(const node_t *node, smartlist_t *needed_ports) { /* XXXX MOVE */ int i; uint16_t port; for (i = 0; i < smartlist_len(needed_ports); ++i) { addr_policy_result_t r; /* alignment issues aren't a worry for this dereference, since needed_ports is explicitly a smartlist of uint16_t's */ port = *(uint16_t *)smartlist_get(needed_ports, i); tor_assert(port); if (node) r = compare_tor_addr_to_node_policy(NULL, port, node); else continue; if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED) return 1; } return 0; } /** Return true iff conn needs another general circuit to be * built. */ static int ap_stream_wants_exit_attention(connection_t *conn) { entry_connection_t *entry; if (conn->type != CONN_TYPE_AP) return 0; entry = TO_ENTRY_CONN(conn); if (conn->state == AP_CONN_STATE_CIRCUIT_WAIT && !conn->marked_for_close && !(entry->want_onehop) && /* ignore one-hop streams */ !(entry->use_begindir) && /* ignore targeted dir fetches */ !(entry->chosen_exit_name) && /* ignore defined streams */ !connection_edge_is_rendezvous_stream(TO_EDGE_CONN(conn)) && !circuit_stream_is_being_handled(TO_ENTRY_CONN(conn), 0, MIN_CIRCUITS_HANDLING_STREAM)) return 1; return 0; } /** Return a pointer to a suitable router to be the exit node for the * general-purpose circuit we're about to build. * * Look through the connection array, and choose a router that maximizes * the number of pending streams that can exit from this router. * * Return NULL if we can't find any suitable routers. */ static const node_t * choose_good_exit_server_general(int need_uptime, int need_capacity) { int *n_supported; int n_pending_connections = 0; smartlist_t *connections; int best_support = -1; int n_best_support=0; const or_options_t *options = get_options(); const smartlist_t *the_nodes; const node_t *node=NULL; connections = get_connection_array(); /* Count how many connections are waiting for a circuit to be built. * We use this for log messages now, but in the future we may depend on it. */ SMARTLIST_FOREACH(connections, connection_t *, conn, { if (ap_stream_wants_exit_attention(conn)) ++n_pending_connections; }); // log_fn(LOG_DEBUG, "Choosing exit node; %d connections are pending", // n_pending_connections); /* Now we count, for each of the routers in the directory, how many * of the pending connections could possibly exit from that * router (n_supported[i]). (We can't be sure about cases where we * don't know the IP address of the pending connection.) * * -1 means "Don't use this router at all." */ the_nodes = nodelist_get_list(); n_supported = tor_malloc(sizeof(int)*smartlist_len(the_nodes)); SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) { const int i = node_sl_idx; if (router_digest_is_me(node->identity)) { n_supported[i] = -1; // log_fn(LOG_DEBUG,"Skipping node %s -- it's me.", router->nickname); /* XXX there's probably a reverse predecessor attack here, but * it's slow. should we take this out? -RD */ continue; } if (!node_has_descriptor(node)) { n_supported[i] = -1; continue; } if (!node->is_running || node->is_bad_exit) { n_supported[i] = -1; continue; /* skip routers that are known to be down or bad exits */ } if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) { /* never pick a non-general node as a random exit. */ n_supported[i] = -1; continue; } if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) { n_supported[i] = -1; continue; /* user asked us not to use it, no matter what */ } if (options->ExitNodes && !routerset_contains_node(options->ExitNodes, node)) { n_supported[i] = -1; continue; /* not one of our chosen exit nodes */ } if (node_is_unreliable(node, need_uptime, need_capacity, 0)) { n_supported[i] = -1; continue; /* skip routers that are not suitable. Don't worry if * this makes us reject all the possible routers: if so, * we'll retry later in this function with need_update and * need_capacity set to 0. */ } if (!(node->is_valid || options->AllowInvalid_ & ALLOW_INVALID_EXIT)) { /* if it's invalid and we don't want it */ n_supported[i] = -1; // log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.", // router->nickname, i); continue; /* skip invalid routers */ } if (options->ExcludeSingleHopRelays && node_allows_single_hop_exits(node)) { n_supported[i] = -1; continue; } if (node_exit_policy_rejects_all(node)) { n_supported[i] = -1; // log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.", // router->nickname, i); continue; /* skip routers that reject all */ } n_supported[i] = 0; /* iterate over connections */ SMARTLIST_FOREACH_BEGIN(connections, connection_t *, conn) { if (!ap_stream_wants_exit_attention(conn)) continue; /* Skip everything but APs in CIRCUIT_WAIT */ if (connection_ap_can_use_exit(TO_ENTRY_CONN(conn), node)) { ++n_supported[i]; // log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.", // router->nickname, i, n_supported[i]); } else { // log_fn(LOG_DEBUG,"%s (index %d) would reject this stream.", // router->nickname, i); } } SMARTLIST_FOREACH_END(conn); if (n_pending_connections > 0 && n_supported[i] == 0) { /* Leave best_support at -1 if that's where it is, so we can * distinguish it later. */ continue; } if (n_supported[i] > best_support) { /* If this router is better than previous ones, remember its index * and goodness, and start counting how many routers are this good. */ best_support = n_supported[i]; n_best_support=1; // log_fn(LOG_DEBUG,"%s is new best supported option so far.", // router->nickname); } else if (n_supported[i] == best_support) { /* If this router is _as good_ as the best one, just increment the * count of equally good routers.*/ ++n_best_support; } } SMARTLIST_FOREACH_END(node); log_info(LD_CIRC, "Found %d servers that might support %d/%d pending connections.", n_best_support, best_support >= 0 ? best_support : 0, n_pending_connections); /* If any routers definitely support any pending connections, choose one * at random. */ if (best_support > 0) { smartlist_t *supporting = smartlist_new(); SMARTLIST_FOREACH(the_nodes, const node_t *, node, { if (n_supported[node_sl_idx] == best_support) smartlist_add(supporting, (void*)node); }); node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT); smartlist_free(supporting); } else { /* Either there are no pending connections, or no routers even seem to * possibly support any of them. Choose a router at random that satisfies * at least one predicted exit port. */ int attempt; smartlist_t *needed_ports, *supporting; if (best_support == -1) { if (need_uptime || need_capacity) { log_info(LD_CIRC, "We couldn't find any live%s%s routers; falling back " "to list of all routers.", need_capacity?", fast":"", need_uptime?", stable":""); tor_free(n_supported); return choose_good_exit_server_general(0, 0); } log_notice(LD_CIRC, "All routers are down or won't exit%s -- " "choosing a doomed exit at random.", options->ExcludeExitNodesUnion_ ? " or are Excluded" : ""); } supporting = smartlist_new(); needed_ports = circuit_get_unhandled_ports(time(NULL)); for (attempt = 0; attempt < 2; attempt++) { /* try once to pick only from routers that satisfy a needed port, * then if there are none, pick from any that support exiting. */ SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) { if (n_supported[node_sl_idx] != -1 && (attempt || node_handles_some_port(node, needed_ports))) { // log_fn(LOG_DEBUG,"Try %d: '%s' is a possibility.", // try, router->nickname); smartlist_add(supporting, (void*)node); } } SMARTLIST_FOREACH_END(node); node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT); if (node) break; smartlist_clear(supporting); /* If we reach this point, we can't actually support any unhandled * predicted ports, so clear all the remaining ones. */ if (smartlist_len(needed_ports)) rep_hist_remove_predicted_ports(needed_ports); } SMARTLIST_FOREACH(needed_ports, uint16_t *, cp, tor_free(cp)); smartlist_free(needed_ports); smartlist_free(supporting); } tor_free(n_supported); if (node) { log_info(LD_CIRC, "Chose exit server '%s'", node_describe(node)); return node; } if (options->ExitNodes) { log_warn(LD_CIRC, "No specified %sexit routers seem to be running: " "can't choose an exit.", options->ExcludeExitNodesUnion_ ? "non-excluded " : ""); } return NULL; } /** Return a pointer to a suitable router to be the exit node for the * circuit of purpose purpose that we're about to build (or NULL * if no router is suitable). * * For general-purpose circuits, pass it off to * choose_good_exit_server_general() * * For client-side rendezvous circuits, choose a random node, weighted * toward the preferences in 'options'. */ static const node_t * choose_good_exit_server(uint8_t purpose, int need_uptime, int need_capacity, int is_internal) { const or_options_t *options = get_options(); router_crn_flags_t flags = CRN_NEED_DESC; if (need_uptime) flags |= CRN_NEED_UPTIME; if (need_capacity) flags |= CRN_NEED_CAPACITY; switch (purpose) { case CIRCUIT_PURPOSE_C_GENERAL: if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE) flags |= CRN_ALLOW_INVALID; if (is_internal) /* pick it like a middle hop */ return router_choose_random_node(NULL, options->ExcludeNodes, flags); else return choose_good_exit_server_general(need_uptime,need_capacity); case CIRCUIT_PURPOSE_C_ESTABLISH_REND: if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS) flags |= CRN_ALLOW_INVALID; return router_choose_random_node(NULL, options->ExcludeNodes, flags); } log_warn(LD_BUG,"Unhandled purpose %d", purpose); tor_fragile_assert(); return NULL; } /** Log a warning if the user specified an exit for the circuit that * has been excluded from use by ExcludeNodes or ExcludeExitNodes. */ static void warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit) { const or_options_t *options = get_options(); routerset_t *rs = options->ExcludeNodes; const char *description; uint8_t purpose = circ->base_.purpose; if (circ->build_state->onehop_tunnel) return; switch (purpose) { default: case CIRCUIT_PURPOSE_OR: case CIRCUIT_PURPOSE_INTRO_POINT: case CIRCUIT_PURPOSE_REND_POINT_WAITING: case CIRCUIT_PURPOSE_REND_ESTABLISHED: log_warn(LD_BUG, "Called on non-origin circuit (purpose %d, %s)", (int)purpose, circuit_purpose_to_string(purpose)); return; case CIRCUIT_PURPOSE_C_GENERAL: if (circ->build_state->is_internal) return; description = "requested exit node"; rs = options->ExcludeExitNodesUnion_; break; case CIRCUIT_PURPOSE_C_INTRODUCING: case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: case CIRCUIT_PURPOSE_S_CONNECT_REND: case CIRCUIT_PURPOSE_S_REND_JOINED: case CIRCUIT_PURPOSE_TESTING: return; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: case CIRCUIT_PURPOSE_C_REND_READY: case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: case CIRCUIT_PURPOSE_C_REND_JOINED: description = "chosen rendezvous point"; break; case CIRCUIT_PURPOSE_CONTROLLER: rs = options->ExcludeExitNodesUnion_; description = "controller-selected circuit target"; break; } if (routerset_contains_extendinfo(rs, exit)) { /* We should never get here if StrictNodes is set to 1. */ if (options->StrictNodes) { log_warn(LD_BUG, "Using %s '%s' which is listed in ExcludeNodes%s, " "even though StrictNodes is set. Please report. " "(Circuit purpose: %s)", description, extend_info_describe(exit), rs==options->ExcludeNodes?"":" or ExcludeExitNodes", circuit_purpose_to_string(purpose)); } else { log_warn(LD_CIRC, "Using %s '%s' which is listed in " "ExcludeNodes%s, because no better options were available. To " "prevent this (and possibly break your Tor functionality), " "set the StrictNodes configuration option. " "(Circuit purpose: %s)", description, extend_info_describe(exit), rs==options->ExcludeNodes?"":" or ExcludeExitNodes", circuit_purpose_to_string(purpose)); } circuit_log_path(LOG_WARN, LD_CIRC, circ); } return; } /** Decide a suitable length for circ's cpath, and pick an exit * router (or use exit if provided). Store these in the * cpath. Return 0 if ok, -1 if circuit should be closed. */ static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit) { cpath_build_state_t *state = circ->build_state; if (state->onehop_tunnel) { log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel."); state->desired_path_len = 1; } else { int r = new_route_len(circ->base_.purpose, exit, nodelist_get_list()); if (r < 1) /* must be at least 1 */ return -1; state->desired_path_len = r; } if (exit) { /* the circuit-builder pre-requested one */ warn_if_last_router_excluded(circ, exit); log_info(LD_CIRC,"Using requested exit node '%s'", extend_info_describe(exit)); exit = extend_info_dup(exit); } else { /* we have to decide one */ const node_t *node = choose_good_exit_server(circ->base_.purpose, state->need_uptime, state->need_capacity, state->is_internal); if (!node) { log_warn(LD_CIRC,"failed to choose an exit server"); return -1; } exit = extend_info_from_node(node, 0); tor_assert(exit); } state->chosen_exit = exit; return 0; } /** Give circ a new exit destination to exit, and add a * hop to the cpath reflecting this. Don't send the next extend cell -- * the caller will do this if it wants to. */ int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *exit) { cpath_build_state_t *state; tor_assert(exit); tor_assert(circ); state = circ->build_state; tor_assert(state); extend_info_free(state->chosen_exit); state->chosen_exit = extend_info_dup(exit); ++circ->build_state->desired_path_len; onion_append_hop(&circ->cpath, exit); return 0; } /** Take an open circ, and add a new hop at the end, based on * info. Set its state back to CIRCUIT_STATE_BUILDING, and then * send the next extend cell to begin connecting to that hop. */ int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit) { int err_reason = 0; warn_if_last_router_excluded(circ, exit); tor_gettimeofday(&circ->base_.timestamp_began); circuit_append_new_exit(circ, exit); circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); if ((err_reason = circuit_send_next_onion_skin(circ))<0) { log_warn(LD_CIRC, "Couldn't extend circuit to new point %s.", extend_info_describe(exit)); circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); return -1; } // XXX: Should cannibalized circuits be dirty or not? Not easy to say.. return 0; } /** Return the number of routers in routers that are currently up * and available for building circuits through. */ static int count_acceptable_nodes(smartlist_t *nodes) { int num=0; SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) { // log_debug(LD_CIRC, // "Contemplating whether router %d (%s) is a new option.", // i, r->nickname); if (! node->is_running) // log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i); continue; if (! node->is_valid) // log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i); continue; if (! node_has_descriptor(node)) continue; /* XXX This clause makes us count incorrectly: if AllowInvalidRouters * allows this node in some places, then we're getting an inaccurate * count. For now, be conservative and don't count it. But later we * should try to be smarter. */ ++num; } SMARTLIST_FOREACH_END(node); // log_debug(LD_CIRC,"I like %d. num_acceptable_routers now %d.",i, num); return num; } /** Add new_hop to the end of the doubly-linked-list head_ptr. * This function is used to extend cpath by another hop. */ void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop) { if (*head_ptr) { new_hop->next = (*head_ptr); new_hop->prev = (*head_ptr)->prev; (*head_ptr)->prev->next = new_hop; (*head_ptr)->prev = new_hop; } else { *head_ptr = new_hop; new_hop->prev = new_hop->next = new_hop; } } /** A helper function used by onion_extend_cpath(). Use purpose * and state and the cpath head (currently populated only * to length cur_len to decide a suitable middle hop for a * circuit. In particular, make sure we don't pick the exit node or its * family, and make sure we don't duplicate any previous nodes or their * families. */ static const node_t * choose_good_middle_server(uint8_t purpose, cpath_build_state_t *state, crypt_path_t *head, int cur_len) { int i; const node_t *r, *choice; crypt_path_t *cpath; smartlist_t *excluded; const or_options_t *options = get_options(); router_crn_flags_t flags = CRN_NEED_DESC; tor_assert(CIRCUIT_PURPOSE_MIN_ <= purpose && purpose <= CIRCUIT_PURPOSE_MAX_); log_debug(LD_CIRC, "Contemplating intermediate hop: random choice."); excluded = smartlist_new(); if ((r = build_state_get_exit_node(state))) { nodelist_add_node_and_family(excluded, r); } for (i = 0, cpath = head; i < cur_len; ++i, cpath=cpath->next) { if ((r = node_get_by_id(cpath->extend_info->identity_digest))) { nodelist_add_node_and_family(excluded, r); } } if (state->need_uptime) flags |= CRN_NEED_UPTIME; if (state->need_capacity) flags |= CRN_NEED_CAPACITY; if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE) flags |= CRN_ALLOW_INVALID; choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); smartlist_free(excluded); return choice; } /** Pick a good entry server for the circuit to be built according to * state. Don't reuse a chosen exit (if any), don't use this * router (if we're an OR), and respect firewall settings; if we're * configured to use entry guards, return one. * * If state is NULL, we're choosing a router to serve as an entry * guard, not for any particular circuit. */ /* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ const node_t * choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) { const node_t *choice; smartlist_t *excluded; const or_options_t *options = get_options(); router_crn_flags_t flags = CRN_NEED_GUARD|CRN_NEED_DESC; const node_t *node; if (state && options->UseEntryGuards && (purpose != CIRCUIT_PURPOSE_TESTING || options->BridgeRelay)) { /* This request is for an entry server to use for a regular circuit, * and we use entry guard nodes. Just return one of the guard nodes. */ return choose_random_entry(state); } excluded = smartlist_new(); if (state && (node = build_state_get_exit_node(state))) { /* Exclude the exit node from the state, if we have one. Also exclude its * family. */ nodelist_add_node_and_family(excluded, node); } if (firewall_is_fascist_or()) { /* Exclude all ORs that we can't reach through our firewall */ smartlist_t *nodes = nodelist_get_list(); SMARTLIST_FOREACH(nodes, const node_t *, node, { if (!fascist_firewall_allows_node(node)) smartlist_add(excluded, (void*)node); }); } /* and exclude current entry guards and their families, if applicable */ /*XXXX025 use the using_as_guard flag to accomplish this.*/ if (options->UseEntryGuards) { SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry, { if ((node = node_get_by_id(entry->identity))) { nodelist_add_node_and_family(excluded, node); } }); } if (state) { if (state->need_uptime) flags |= CRN_NEED_UPTIME; if (state->need_capacity) flags |= CRN_NEED_CAPACITY; } if (options->AllowInvalid_ & ALLOW_INVALID_ENTRY) flags |= CRN_ALLOW_INVALID; choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); smartlist_free(excluded); return choice; } /** Return the first non-open hop in cpath, or return NULL if all * hops are open. */ static crypt_path_t * onion_next_hop_in_cpath(crypt_path_t *cpath) { crypt_path_t *hop = cpath; do { if (hop->state != CPATH_STATE_OPEN) return hop; hop = hop->next; } while (hop != cpath); return NULL; } /** Choose a suitable next hop in the cpath head_ptr, * based on state. Append the hop info to head_ptr. */ static int onion_extend_cpath(origin_circuit_t *circ) { uint8_t purpose = circ->base_.purpose; cpath_build_state_t *state = circ->build_state; int cur_len = circuit_get_cpath_len(circ); extend_info_t *info = NULL; if (cur_len >= state->desired_path_len) { log_debug(LD_CIRC, "Path is complete: %d steps long", state->desired_path_len); return 1; } log_debug(LD_CIRC, "Path is %d long; we want %d", cur_len, state->desired_path_len); if (cur_len == state->desired_path_len - 1) { /* Picking last node */ info = extend_info_dup(state->chosen_exit); } else if (cur_len == 0) { /* picking first node */ const node_t *r = choose_good_entry_server(purpose, state); if (r) { /* If we're a client, use the preferred address rather than the primary address, for potentially connecting to an IPv6 OR port. */ info = extend_info_from_node(r, server_mode(get_options()) == 0); tor_assert(info); } } else { const node_t *r = choose_good_middle_server(purpose, state, circ->cpath, cur_len); if (r) { info = extend_info_from_node(r, 0); tor_assert(info); } } if (!info) { log_warn(LD_CIRC,"Failed to find node for hop %d of our path. Discarding " "this circuit.", cur_len); return -1; } log_debug(LD_CIRC,"Chose router %s for hop %d (exit is %s)", extend_info_describe(info), cur_len+1, build_state_get_exit_nickname(state)); onion_append_hop(&circ->cpath, info); extend_info_free(info); return 0; } /** Create a new hop, annotate it with information about its * corresponding router choice, and append it to the * end of the cpath head_ptr. */ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) { crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t)); /* link hop into the cpath, at the end. */ onion_append_to_cpath(head_ptr, hop); hop->magic = CRYPT_PATH_MAGIC; hop->state = CPATH_STATE_CLOSED; hop->extend_info = extend_info_dup(choice); hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; return 0; } /** Allocate a new extend_info object based on the various arguments. */ extend_info_t * extend_info_new(const char *nickname, const char *digest, crypto_pk_t *onion_key, const curve25519_public_key_t *curve25519_key, const tor_addr_t *addr, uint16_t port) { extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t)); memcpy(info->identity_digest, digest, DIGEST_LEN); if (nickname) strlcpy(info->nickname, nickname, sizeof(info->nickname)); if (onion_key) info->onion_key = crypto_pk_dup_key(onion_key); #ifdef CURVE25519_ENABLED if (curve25519_key) memcpy(&info->curve25519_onion_key, curve25519_key, sizeof(curve25519_public_key_t)); #else (void)curve25519_key; #endif tor_addr_copy(&info->addr, addr); info->port = port; return info; } /** Allocate and return a new extend_info that can be used to build a * circuit to or through the node node. Use the primary address * of the node (i.e. its IPv4 address) unless * for_direct_connect is true, in which case the preferred * address is used instead. May return NULL if there is not enough * info about node to extend to it--for example, if there is no * routerinfo_t or microdesc_t. **/ extend_info_t * extend_info_from_node(const node_t *node, int for_direct_connect) { tor_addr_port_t ap; if (node->ri == NULL && (node->rs == NULL || node->md == NULL)) return NULL; if (for_direct_connect) node_get_pref_orport(node, &ap); else node_get_prim_orport(node, &ap); log_debug(LD_CIRC, "using %s for %s", fmt_addrport(&ap.addr, ap.port), node->ri ? node->ri->nickname : node->rs->nickname); if (node->ri) return extend_info_new(node->ri->nickname, node->identity, node->ri->onion_pkey, node->ri->onion_curve25519_pkey, &ap.addr, ap.port); else if (node->rs && node->md) return extend_info_new(node->rs->nickname, node->identity, node->md->onion_pkey, node->md->onion_curve25519_pkey, &ap.addr, ap.port); else return NULL; } /** Release storage held by an extend_info_t struct. */ void extend_info_free(extend_info_t *info) { if (!info) return; crypto_pk_free(info->onion_key); tor_free(info); } /** Allocate and return a new extend_info_t with the same contents as * info. */ extend_info_t * extend_info_dup(extend_info_t *info) { extend_info_t *newinfo; tor_assert(info); newinfo = tor_malloc(sizeof(extend_info_t)); memcpy(newinfo, info, sizeof(extend_info_t)); if (info->onion_key) newinfo->onion_key = crypto_pk_dup_key(info->onion_key); else newinfo->onion_key = NULL; return newinfo; } /** Return the routerinfo_t for the chosen exit router in state. * If there is no chosen exit, or if we don't know the routerinfo_t for * the chosen exit, return NULL. */ const node_t * build_state_get_exit_node(cpath_build_state_t *state) { if (!state || !state->chosen_exit) return NULL; return node_get_by_id(state->chosen_exit->identity_digest); } /** Return the nickname for the chosen exit router in state. If * there is no chosen exit, or if we don't know the routerinfo_t for the * chosen exit, return NULL. */ const char * build_state_get_exit_nickname(cpath_build_state_t *state) { if (!state || !state->chosen_exit) return NULL; return state->chosen_exit->nickname; } tor-0.2.4.20/src/or/relay.h0000644000175000017500000000724612255745673012207 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file relay.h * \brief Header file for relay.c. **/ #ifndef TOR_RELAY_H #define TOR_RELAY_H extern uint64_t stats_n_relay_cells_relayed; extern uint64_t stats_n_relay_cells_delivered; int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, cell_direction_t cell_direction); void relay_header_pack(uint8_t *dest, const relay_header_t *src); void relay_header_unpack(relay_header_t *dest, const uint8_t *src); int relay_send_command_from_edge_(streamid_t stream_id, circuit_t *circ, uint8_t relay_command, const char *payload, size_t payload_len, crypt_path_t *cpath_layer, const char *filename, int lineno); #define relay_send_command_from_edge(stream_id, circ, relay_command, payload, \ payload_len, cpath_layer) \ relay_send_command_from_edge_((stream_id), (circ), (relay_command), \ (payload), (payload_len), (cpath_layer), \ __FILE__, __LINE__) int connection_edge_send_command(edge_connection_t *fromconn, uint8_t relay_command, const char *payload, size_t payload_len); int connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, int *max_cells); void connection_edge_consider_sending_sendme(edge_connection_t *conn); extern uint64_t stats_n_data_cells_packaged; extern uint64_t stats_n_data_bytes_packaged; extern uint64_t stats_n_data_cells_received; extern uint64_t stats_n_data_bytes_received; void init_cell_pool(void); void free_cell_pool(void); void clean_cell_pool(void); void dump_cell_pool_usage(int severity); size_t packed_cell_mem_cost(void); /* For channeltls.c */ void packed_cell_free(packed_cell_t *cell); void cell_queue_clear(cell_queue_t *queue); void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell); void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell, int wide_circ_ids); void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, cell_t *cell, cell_direction_t direction, streamid_t fromstream); void channel_unlink_all_circuits(channel_t *chan); int channel_flush_from_first_active_circuit(channel_t *chan, int max); void assert_circuit_mux_okay(channel_t *chan); void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction, const char *file, int lineno); #define update_circuit_on_cmux(circ, direction) \ update_circuit_on_cmux_((circ), (direction), SHORT_FILE__, __LINE__) int append_address_to_payload(uint8_t *payload_out, const tor_addr_t *addr); const uint8_t *decode_address_from_payload(tor_addr_t *addr_out, const uint8_t *payload, int payload_len); void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan); void stream_choice_seed_weak_rng(void); #ifdef RELAY_PRIVATE int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t **layer_hint, char *recognized); int connected_cell_parse(const relay_header_t *rh, const cell_t *cell, tor_addr_t *addr_out, int *ttl_out); #endif #endif tor-0.2.4.20/src/or/onion_fast.c0000644000175000017500000000766012255745673013225 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file onion_fast.c * \brief Functions implement the CREATE_FAST circuit handshake. **/ #include "or.h" #include "onion_fast.h" /** Release all state held in victim. */ void fast_handshake_state_free(fast_handshake_state_t *victim) { if (! victim) return; memwipe(victim, 0, sizeof(fast_handshake_state_t)); tor_free(victim); } /** Create the state needed to perform a CREATE_FAST hasnshake. Return 0 * on success, -1 on failure. */ int fast_onionskin_create(fast_handshake_state_t **handshake_state_out, uint8_t *handshake_out) { fast_handshake_state_t *s; *handshake_state_out = s = tor_malloc(sizeof(fast_handshake_state_t)); if (crypto_rand((char*)s->state, sizeof(s->state)) < 0) { tor_free(s); return -1; } memcpy(handshake_out, s->state, DIGEST_LEN); return 0; } /** Implement the server side of the CREATE_FAST abbreviated handshake. The * client has provided DIGEST_LEN key bytes in key_in ("x"). We * generate a reply of DIGEST_LEN*2 bytes in key_out, consisting of a * new random "y", followed by H(x|y) to check for correctness. We set * key_out_len bytes of key material in key_out. * Return 0 on success, <0 on failure. **/ int fast_server_handshake(const uint8_t *key_in, /* DIGEST_LEN bytes */ uint8_t *handshake_reply_out, /* DIGEST_LEN*2 bytes */ uint8_t *key_out, size_t key_out_len) { uint8_t tmp[DIGEST_LEN+DIGEST_LEN]; uint8_t *out = NULL; size_t out_len; int r = -1; if (crypto_rand((char*)handshake_reply_out, DIGEST_LEN)<0) return -1; memcpy(tmp, key_in, DIGEST_LEN); memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN); out_len = key_out_len+DIGEST_LEN; out = tor_malloc(out_len); if (crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len)) { goto done; } memcpy(handshake_reply_out+DIGEST_LEN, out, DIGEST_LEN); memcpy(key_out, out+DIGEST_LEN, key_out_len); r = 0; done: memwipe(tmp, 0, sizeof(tmp)); memwipe(out, 0, out_len); tor_free(out); return r; } /** Implement the second half of the client side of the CREATE_FAST handshake. * We sent the server handshake_state ("x") already, and the server * told us handshake_reply_out (y|H(x|y)). Make sure that the hash is * correct, and generate key material in key_out. Return 0 on success, * true on failure. * * NOTE: The "CREATE_FAST" handshake path is distinguishable from regular * "onionskin" handshakes, and is not secure if an adversary can see or modify * the messages. Therefore, it should only be used by clients, and only as * the first hop of a circuit (since the first hop is already authenticated * and protected by TLS). */ int fast_client_handshake(const fast_handshake_state_t *handshake_state, const uint8_t *handshake_reply_out,/*DIGEST_LEN*2 bytes*/ uint8_t *key_out, size_t key_out_len) { uint8_t tmp[DIGEST_LEN+DIGEST_LEN]; uint8_t *out; size_t out_len; int r = -1; memcpy(tmp, handshake_state->state, DIGEST_LEN); memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN); out_len = key_out_len+DIGEST_LEN; out = tor_malloc(out_len); if (crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len)) { goto done; } if (tor_memneq(out, handshake_reply_out+DIGEST_LEN, DIGEST_LEN)) { /* H(K) does *not* match. Something fishy. */ log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on fast handshake. " "Bug or attack."); goto done; } memcpy(key_out, out+DIGEST_LEN, key_out_len); r = 0; done: memwipe(tmp, 0, sizeof(tmp)); memwipe(out, 0, out_len); tor_free(out); return r; } tor-0.2.4.20/src/or/Makefile.nmake0000644000175000017500000000275212166112776013442 00000000000000all: tor.exe CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common \ /I ..\ext LIBS = ..\..\..\build-alpha\lib\libevent.lib \ ..\..\..\build-alpha\lib\libcrypto.lib \ ..\..\..\build-alpha\lib\libssl.lib \ ..\..\..\build-alpha\lib\libz.lib \ ws2_32.lib advapi32.lib shell32.lib \ crypt32.lib gdi32.lib user32.lib LIBTOR_OBJECTS = \ addressmap.obj \ buffers.obj \ channel.obj \ channeltls.obj \ circuitbuild.obj \ circuitlist.obj \ circuitmux.obj \ circuitmux_ewma.obj \ circuitstats.obj \ circuituse.obj \ command.obj \ config.obj \ config_codedigest.obj \ confparse.obj \ connection.obj \ connection_edge.obj \ connection_or.obj \ control.obj \ cpuworker.obj \ directory.obj \ dirserv.obj \ dirvote.obj \ dns.obj \ dnsserv.obj \ fp_pair.obj \ entrynodes.obj \ geoip.obj \ hibernate.obj \ main.obj \ microdesc.obj \ networkstatus.obj \ nodelist.obj \ ntmain.obj \ onion.obj \ onion_fast.obj \ onion_ntor.obj \ onion_tap.obj \ policies.obj \ reasons.obj \ relay.obj \ rendclient.obj \ rendcommon.obj \ rendmid.obj \ rendservice.obj \ rephist.obj \ replaycache.obj \ router.obj \ routerlist.obj \ routerparse.obj \ routerset.obj \ statefile.obj \ status.obj \ transports.obj libtor.lib: $(LIBTOR_OBJECTS) lib $(LIBTOR_OBJECTS) /out:$@ tor.exe: libtor.lib tor_main.obj $(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib tor_main.obj /Fe$@ clean: del $(LIBTOR_OBJECTS) *.lib tor.exe tor-0.2.4.20/src/or/circuitmux_ewma.h0000644000175000017500000000133312166112776014260 00000000000000/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file circuitmux_ewma.h * \brief Header file for circuitmux_ewma.c **/ #ifndef TOR_CIRCUITMUX_EWMA_H #define TOR_CIRCUITMUX_EWMA_H #include "or.h" #include "circuitmux.h" /* Everything but circuitmux_ewma.c should see this extern */ #ifndef TOR_CIRCUITMUX_EWMA_C_ extern circuitmux_policy_t ewma_policy; #endif /* !(TOR_CIRCUITMUX_EWMA_C_) */ /* Externally visible EWMA functions */ int cell_ewma_enabled(void); unsigned int cell_ewma_get_tick(void); void cell_ewma_set_scale_factor(const or_options_t *options, const networkstatus_t *consensus); #endif /* TOR_CIRCUITMUX_EWMA_H */ tor-0.2.4.20/src/or/nodelist.c0000644000175000017500000013363512255745673012711 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "or.h" #include "address.h" #include "config.h" #include "control.h" #include "dirserv.h" #include "geoip.h" #include "main.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "policies.h" #include "rendservice.h" #include "router.h" #include "routerlist.h" #include "routerset.h" #include static void nodelist_drop_node(node_t *node, int remove_from_ht); static void node_free(node_t *node); static void update_router_have_minimum_dir_info(void); /** A nodelist_t holds a node_t object for every router we're "willing to use * for something". Specifically, it should hold a node_t for every node that * is currently in the routerlist, or currently in the consensus we're using. */ typedef struct nodelist_t { /* A list of all the nodes. */ smartlist_t *nodes; /* Hash table to map from node ID digest to node. */ HT_HEAD(nodelist_map, node_t) nodes_by_id; } nodelist_t; static INLINE unsigned int node_id_hash(const node_t *node) { #if SIZEOF_INT == 4 const uint32_t *p = (const uint32_t*)node->identity; return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4]; #elif SIZEOF_INT == 8 const uint64_t *p = (const uint32_t*)node->identity; const uint32_t *p32 = (const uint32_t*)node->identity; return p[0] ^ p[1] ^ p32[4]; #endif } static INLINE unsigned int node_id_eq(const node_t *node1, const node_t *node2) { return tor_memeq(node1->identity, node2->identity, DIGEST_LEN); } HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq); HT_GENERATE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq, 0.6, malloc, realloc, free); /** The global nodelist. */ static nodelist_t *the_nodelist=NULL; /** Create an empty nodelist if we haven't done so already. */ static void init_nodelist(void) { if (PREDICT_UNLIKELY(the_nodelist == NULL)) { the_nodelist = tor_malloc_zero(sizeof(nodelist_t)); HT_INIT(nodelist_map, &the_nodelist->nodes_by_id); the_nodelist->nodes = smartlist_new(); } } /** As node_get_by_id, but returns a non-const pointer */ node_t * node_get_mutable_by_id(const char *identity_digest) { node_t search, *node; if (PREDICT_UNLIKELY(the_nodelist == NULL)) return NULL; memcpy(&search.identity, identity_digest, DIGEST_LEN); node = HT_FIND(nodelist_map, &the_nodelist->nodes_by_id, &search); return node; } /** Return the node_t whose identity is identity_digest, or NULL * if no such node exists. */ const node_t * node_get_by_id(const char *identity_digest) { return node_get_mutable_by_id(identity_digest); } /** Internal: return the node_t whose identity_digest is * identity_digest. If none exists, create a new one, add it to the * nodelist, and return it. * * Requires that the nodelist be initialized. */ static node_t * node_get_or_create(const char *identity_digest) { node_t *node; if ((node = node_get_mutable_by_id(identity_digest))) return node; node = tor_malloc_zero(sizeof(node_t)); memcpy(node->identity, identity_digest, DIGEST_LEN); HT_INSERT(nodelist_map, &the_nodelist->nodes_by_id, node); smartlist_add(the_nodelist->nodes, node); node->nodelist_idx = smartlist_len(the_nodelist->nodes) - 1; node->country = -1; return node; } /** Called when a node's address changes. */ static void node_addrs_changed(node_t *node) { node->last_reachable = node->last_reachable6 = 0; node->country = -1; } /** Add ri to an appropriate node in the nodelist. If we replace an * old routerinfo, and ri_old_out is not NULL, set *ri_old_out * to the previous routerinfo. */ node_t * nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out) { node_t *node; const char *id_digest; int had_router = 0; tor_assert(ri); init_nodelist(); id_digest = ri->cache_info.identity_digest; node = node_get_or_create(id_digest); if (node->ri) { if (!routers_have_same_or_addrs(node->ri, ri)) { node_addrs_changed(node); } had_router = 1; if (ri_old_out) *ri_old_out = node->ri; } else { if (ri_old_out) *ri_old_out = NULL; } node->ri = ri; if (node->country == -1) node_set_country(node); if (authdir_mode(get_options()) && !had_router) { const char *discard=NULL; uint32_t status = dirserv_router_get_status(ri, &discard); dirserv_set_node_flags_from_authoritative_status(node, status); } return node; } /** Set the appropriate node_t to use md as its microdescriptor. * * Called when a new microdesc has arrived and the usable consensus flavor * is "microdesc". **/ node_t * nodelist_add_microdesc(microdesc_t *md) { networkstatus_t *ns = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC); const routerstatus_t *rs; node_t *node; if (ns == NULL) return NULL; init_nodelist(); /* Microdescriptors don't carry an identity digest, so we need to figure * it out by looking up the routerstatus. */ rs = router_get_consensus_status_by_descriptor_digest(ns, md->digest); if (rs == NULL) return NULL; node = node_get_mutable_by_id(rs->identity_digest); if (node) { if (node->md) node->md->held_by_nodes--; node->md = md; md->held_by_nodes++; } return node; } /** Tell the nodelist that the current usable consensus is ns. * This makes the nodelist change all of the routerstatus entries for * the nodes, drop nodes that no longer have enough info to get used, * and grab microdescriptors into nodes as appropriate. */ void nodelist_set_consensus(networkstatus_t *ns) { const or_options_t *options = get_options(); int authdir = authdir_mode_v2(options) || authdir_mode_v3(options); int client = !server_mode(options); init_nodelist(); if (ns->flavor == FLAV_MICRODESC) (void) get_microdesc_cache(); /* Make sure it exists first. */ SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node, node->rs = NULL); SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { node_t *node = node_get_or_create(rs->identity_digest); node->rs = rs; if (ns->flavor == FLAV_MICRODESC) { if (node->md == NULL || tor_memneq(node->md->digest,rs->descriptor_digest,DIGEST256_LEN)) { if (node->md) node->md->held_by_nodes--; node->md = microdesc_cache_lookup_by_digest256(NULL, rs->descriptor_digest); if (node->md) node->md->held_by_nodes++; } } node_set_country(node); /* If we're not an authdir, believe others. */ if (!authdir) { node->is_valid = rs->is_valid; node->is_running = rs->is_flagged_running; node->is_fast = rs->is_fast; node->is_stable = rs->is_stable; node->is_possible_guard = rs->is_possible_guard; node->is_exit = rs->is_exit; node->is_bad_directory = rs->is_bad_directory; node->is_bad_exit = rs->is_bad_exit; node->is_hs_dir = rs->is_hs_dir; node->ipv6_preferred = 0; if (client && options->ClientPreferIPv6ORPort == 1 && (tor_addr_is_null(&rs->ipv6_addr) == 0 || (node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0))) node->ipv6_preferred = 1; } } SMARTLIST_FOREACH_END(rs); nodelist_purge(); if (! authdir) { SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { /* We have no routerstatus for this router. Clear flags so we can skip * it, maybe.*/ if (!node->rs) { tor_assert(node->ri); /* if it had only an md, or nothing, purge * would have removed it. */ if (node->ri->purpose == ROUTER_PURPOSE_GENERAL) { /* Clear all flags. */ node->is_valid = node->is_running = node->is_hs_dir = node->is_fast = node->is_stable = node->is_possible_guard = node->is_exit = node->is_bad_exit = node->is_bad_directory = node->ipv6_preferred = 0; } } } SMARTLIST_FOREACH_END(node); } } /** Helper: return true iff a node has a usable amount of information*/ static INLINE int node_is_usable(const node_t *node) { return (node->rs) || (node->ri); } /** Tell the nodelist that md is no longer a microdescriptor for the * node with identity_digest. */ void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md) { node_t *node = node_get_mutable_by_id(identity_digest); if (node && node->md == md) { node->md = NULL; md->held_by_nodes--; } } /** Tell the nodelist that ri is no longer in the routerlist. */ void nodelist_remove_routerinfo(routerinfo_t *ri) { node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); if (node && node->ri == ri) { node->ri = NULL; if (! node_is_usable(node)) { nodelist_drop_node(node, 1); node_free(node); } } } /** Remove node from the nodelist. (Asserts that it was there to begin * with.) */ static void nodelist_drop_node(node_t *node, int remove_from_ht) { node_t *tmp; int idx; if (remove_from_ht) { tmp = HT_REMOVE(nodelist_map, &the_nodelist->nodes_by_id, node); tor_assert(tmp == node); } idx = node->nodelist_idx; tor_assert(idx >= 0); tor_assert(node == smartlist_get(the_nodelist->nodes, idx)); smartlist_del(the_nodelist->nodes, idx); if (idx < smartlist_len(the_nodelist->nodes)) { tmp = smartlist_get(the_nodelist->nodes, idx); tmp->nodelist_idx = idx; } node->nodelist_idx = -1; } /** Release storage held by node */ static void node_free(node_t *node) { if (!node) return; if (node->md) node->md->held_by_nodes--; tor_assert(node->nodelist_idx == -1); tor_free(node); } /** Remove all entries from the nodelist that don't have enough info to be * usable for anything. */ void nodelist_purge(void) { node_t **iter; if (PREDICT_UNLIKELY(the_nodelist == NULL)) return; /* Remove the non-usable nodes. */ for (iter = HT_START(nodelist_map, &the_nodelist->nodes_by_id); iter; ) { node_t *node = *iter; if (node->md && !node->rs) { /* An md is only useful if there is an rs. */ node->md->held_by_nodes--; node->md = NULL; } if (node_is_usable(node)) { iter = HT_NEXT(nodelist_map, &the_nodelist->nodes_by_id, iter); } else { iter = HT_NEXT_RMV(nodelist_map, &the_nodelist->nodes_by_id, iter); nodelist_drop_node(node, 0); node_free(node); } } nodelist_assert_ok(); } /** Release all storage held by the nodelist. */ void nodelist_free_all(void) { if (PREDICT_UNLIKELY(the_nodelist == NULL)) return; HT_CLEAR(nodelist_map, &the_nodelist->nodes_by_id); SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { node->nodelist_idx = -1; node_free(node); } SMARTLIST_FOREACH_END(node); smartlist_free(the_nodelist->nodes); tor_free(the_nodelist); } /** Check that the nodelist is internally consistent, and consistent with * the directory info it's derived from. */ void nodelist_assert_ok(void) { routerlist_t *rl = router_get_routerlist(); networkstatus_t *ns = networkstatus_get_latest_consensus(); digestmap_t *dm; if (!the_nodelist) return; dm = digestmap_new(); /* every routerinfo in rl->routers should be in the nodelist. */ if (rl) { SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { const node_t *node = node_get_by_id(ri->cache_info.identity_digest); tor_assert(node && node->ri == ri); tor_assert(fast_memeq(ri->cache_info.identity_digest, node->identity, DIGEST_LEN)); tor_assert(! digestmap_get(dm, node->identity)); digestmap_set(dm, node->identity, (void*)node); } SMARTLIST_FOREACH_END(ri); } /* every routerstatus in ns should be in the nodelist */ if (ns) { SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { const node_t *node = node_get_by_id(rs->identity_digest); tor_assert(node && node->rs == rs); tor_assert(fast_memeq(rs->identity_digest, node->identity, DIGEST_LEN)); digestmap_set(dm, node->identity, (void*)node); if (ns->flavor == FLAV_MICRODESC) { /* If it's a microdesc consensus, every entry that has a * microdescriptor should be in the nodelist. */ microdesc_t *md = microdesc_cache_lookup_by_digest256(NULL, rs->descriptor_digest); tor_assert(md == node->md); if (md) tor_assert(md->held_by_nodes >= 1); } } SMARTLIST_FOREACH_END(rs); } /* The nodelist should have no other entries, and its entries should be * well-formed. */ SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { tor_assert(digestmap_get(dm, node->identity) != NULL); tor_assert(node_sl_idx == node->nodelist_idx); } SMARTLIST_FOREACH_END(node); tor_assert((long)smartlist_len(the_nodelist->nodes) == (long)HT_SIZE(&the_nodelist->nodes_by_id)); digestmap_free(dm, NULL); } /** Return a list of a node_t * for every node we know about. The caller * MUST NOT modify the list. (You can set and clear flags in the nodes if * you must, but you must not add or remove nodes.) */ smartlist_t * nodelist_get_list(void) { init_nodelist(); return the_nodelist->nodes; } /** Given a hex-encoded nickname of the format DIGEST, $DIGEST, $DIGEST=name, * or $DIGEST~name, return the node with the matching identity digest and * nickname (if any). Return NULL if no such node exists, or if hex_id * is not well-formed. */ const node_t * node_get_by_hex_id(const char *hex_id) { char digest_buf[DIGEST_LEN]; char nn_buf[MAX_NICKNAME_LEN+1]; char nn_char='\0'; if (hex_digest_nickname_decode(hex_id, digest_buf, &nn_char, nn_buf)==0) { const node_t *node = node_get_by_id(digest_buf); if (!node) return NULL; if (nn_char) { const char *real_name = node_get_nickname(node); if (!real_name || strcasecmp(real_name, nn_buf)) return NULL; if (nn_char == '=') { const char *named_id = networkstatus_get_router_digest_by_nickname(nn_buf); if (!named_id || tor_memneq(named_id, digest_buf, DIGEST_LEN)) return NULL; } } return node; } return NULL; } /** Given a nickname (possibly verbose, possibly a hexadecimal digest), return * the corresponding node_t, or NULL if none exists. Warn the user if * warn_if_unnamed is set, and they have specified a router by * nickname, but the Named flag isn't set for that router. */ const node_t * node_get_by_nickname(const char *nickname, int warn_if_unnamed) { const node_t *node; if (!the_nodelist) return NULL; /* Handle these cases: DIGEST, $DIGEST, $DIGEST=name, $DIGEST~name. */ if ((node = node_get_by_hex_id(nickname)) != NULL) return node; if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) return NULL; /* Okay, so if we get here, the nickname is just a nickname. Is there * a binding for it in the consensus? */ { const char *named_id = networkstatus_get_router_digest_by_nickname(nickname); if (named_id) return node_get_by_id(named_id); } /* Is it marked as owned-by-someone-else? */ if (networkstatus_nickname_is_unnamed(nickname)) { log_info(LD_GENERAL, "The name %s is listed as Unnamed: there is some " "router that holds it, but not one listed in the current " "consensus.", escaped(nickname)); return NULL; } /* Okay, so the name is not canonical for anybody. */ { smartlist_t *matches = smartlist_new(); const node_t *choice = NULL; SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { if (!strcasecmp(node_get_nickname(node), nickname)) smartlist_add(matches, node); } SMARTLIST_FOREACH_END(node); if (smartlist_len(matches)>1 && warn_if_unnamed) { int any_unwarned = 0; SMARTLIST_FOREACH_BEGIN(matches, node_t *, node) { if (!node->name_lookup_warned) { node->name_lookup_warned = 1; any_unwarned = 1; } } SMARTLIST_FOREACH_END(node); if (any_unwarned) { log_warn(LD_CONFIG, "There are multiple matches for the name %s, " "but none is listed as Named in the directory consensus. " "Choosing one arbitrarily.", nickname); } } else if (smartlist_len(matches)>1 && warn_if_unnamed) { char fp[HEX_DIGEST_LEN+1]; node_t *node = smartlist_get(matches, 0); if (node->name_lookup_warned) { base16_encode(fp, sizeof(fp), node->identity, DIGEST_LEN); log_warn(LD_CONFIG, "You specified a server \"%s\" by name, but the directory " "authorities do not have any key registered for this " "nickname -- so it could be used by any server, not just " "the one you meant. " "To make sure you get the same server in the future, refer " "to it by key, as \"$%s\".", nickname, fp); node->name_lookup_warned = 1; } } if (smartlist_len(matches)) choice = smartlist_get(matches, 0); smartlist_free(matches); return choice; } } /** Return the nickname of node, or NULL if we can't find one. */ const char * node_get_nickname(const node_t *node) { tor_assert(node); if (node->rs) return node->rs->nickname; else if (node->ri) return node->ri->nickname; else return NULL; } /** Return true iff the nickname of node is canonical, based on the * latest consensus. */ int node_is_named(const node_t *node) { const char *named_id; const char *nickname = node_get_nickname(node); if (!nickname) return 0; named_id = networkstatus_get_router_digest_by_nickname(nickname); if (!named_id) return 0; return tor_memeq(named_id, node->identity, DIGEST_LEN); } /** Return true iff node appears to be a directory authority or * directory cache */ int node_is_dir(const node_t *node) { if (node->rs) return node->rs->dir_port != 0; else if (node->ri) return node->ri->dir_port != 0; else return 0; } /** Return true iff node has either kind of usable descriptor -- that * is, a routerdescriptor or a microdescriptor. */ int node_has_descriptor(const node_t *node) { return (node->ri || (node->rs && node->md)); } /** Return the router_purpose of node. */ int node_get_purpose(const node_t *node) { if (node->ri) return node->ri->purpose; else return ROUTER_PURPOSE_GENERAL; } /** Compute the verbose ("extended") nickname of node and store it * into the MAX_VERBOSE_NICKNAME_LEN+1 character buffer at * verbose_nickname_out */ void node_get_verbose_nickname(const node_t *node, char *verbose_name_out) { const char *nickname = node_get_nickname(node); int is_named = node_is_named(node); verbose_name_out[0] = '$'; base16_encode(verbose_name_out+1, HEX_DIGEST_LEN+1, node->identity, DIGEST_LEN); if (!nickname) return; verbose_name_out[1+HEX_DIGEST_LEN] = is_named ? '=' : '~'; strlcpy(verbose_name_out+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1); } /** Return true iff it seems that node allows circuits to exit * through it directlry from the client. */ int node_allows_single_hop_exits(const node_t *node) { if (node && node->ri) return node->ri->allow_single_hop_exits; else return 0; } /** Return true iff it seems that node has an exit policy that doesn't * actually permit anything to exit, or we don't know its exit policy */ int node_exit_policy_rejects_all(const node_t *node) { if (node->rejects_all) return 1; if (node->ri) return node->ri->policy_is_reject_star; else if (node->md) return node->md->exit_policy == NULL || short_policy_is_reject_star(node->md->exit_policy); else return 1; } /** Return true iff the exit policy for node is such that we can treat * rejecting an address of type family unexpectedly as a sign of that * node's failure. */ int node_exit_policy_is_exact(const node_t *node, sa_family_t family) { if (family == AF_UNSPEC) { return 1; /* Rejecting an address but not telling us what address * is a bad sign. */ } else if (family == AF_INET) { return node->ri != NULL; } else if (family == AF_INET6) { return 0; } tor_fragile_assert(); return 1; } /** Return list of tor_addr_port_t with all OR ports (in the sense IP * addr + TCP port) for node. Caller must free all elements * using tor_free() and free the list using smartlist_free(). * * XXX this is potentially a memory fragmentation hog -- if on * critical path consider the option of having the caller allocate the * memory */ smartlist_t * node_get_all_orports(const node_t *node) { smartlist_t *sl = smartlist_new(); if (node->ri != NULL) { if (node->ri->addr != 0) { tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); tor_addr_from_ipv4h(&ap->addr, node->ri->addr); ap->port = node->ri->or_port; smartlist_add(sl, ap); } if (!tor_addr_is_null(&node->ri->ipv6_addr)) { tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); tor_addr_copy(&ap->addr, &node->ri->ipv6_addr); ap->port = node->ri->or_port; smartlist_add(sl, ap); } } else if (node->rs != NULL) { tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); tor_addr_from_ipv4h(&ap->addr, node->rs->addr); ap->port = node->rs->or_port; smartlist_add(sl, ap); } return sl; } /** Wrapper around node_get_prim_orport for backward compatibility. */ void node_get_addr(const node_t *node, tor_addr_t *addr_out) { tor_addr_port_t ap; node_get_prim_orport(node, &ap); tor_addr_copy(addr_out, &ap.addr); } /** Return the host-order IPv4 address for node, or 0 if it doesn't * seem to have one. */ uint32_t node_get_prim_addr_ipv4h(const node_t *node) { if (node->ri) { return node->ri->addr; } else if (node->rs) { return node->rs->addr; } return 0; } /** Copy a string representation of an IP address for node into * the len-byte buffer at buf. */ void node_get_address_string(const node_t *node, char *buf, size_t len) { if (node->ri) { strlcpy(buf, node->ri->address, len); } else if (node->rs) { tor_addr_t addr; tor_addr_from_ipv4h(&addr, node->rs->addr); tor_addr_to_str(buf, &addr, len, 0); } else { buf[0] = '\0'; } } /** Return node's declared uptime, or -1 if it doesn't seem to have * one. */ long node_get_declared_uptime(const node_t *node) { if (node->ri) return node->ri->uptime; else return -1; } /** Return node's platform string, or NULL if we don't know it. */ const char * node_get_platform(const node_t *node) { /* If we wanted, we could record the version in the routerstatus_t, since * the consensus lists it. We don't, though, so this function just won't * work with microdescriptors. */ if (node->ri) return node->ri->platform; else return NULL; } /** Return node's time of publication, or 0 if we don't have one. */ time_t node_get_published_on(const node_t *node) { if (node->ri) return node->ri->cache_info.published_on; else return 0; } /** Return true iff node is one representing this router. */ int node_is_me(const node_t *node) { return router_digest_is_me(node->identity); } /** Return node declared family (as a list of names), or NULL if * the node didn't declare a family. */ const smartlist_t * node_get_declared_family(const node_t *node) { if (node->ri && node->ri->declared_family) return node->ri->declared_family; else if (node->md && node->md->family) return node->md->family; else return NULL; } /** Return 1 if we prefer the IPv6 address and OR TCP port of * node, else 0. * * We prefer the IPv6 address if the router has an IPv6 address and * i) the node_t says that it prefers IPv6 * or * ii) the router has no IPv4 address. */ int node_ipv6_preferred(const node_t *node) { tor_addr_port_t ipv4_addr; node_assert_ok(node); if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) { if (node->ri) return !tor_addr_is_null(&node->ri->ipv6_addr); if (node->md) return !tor_addr_is_null(&node->md->ipv6_addr); if (node->rs) return !tor_addr_is_null(&node->rs->ipv6_addr); } return 0; } /** Copy the primary (IPv4) OR port (IP address and TCP port) for * node into *ap_out. Return 0 if a valid address and * port was copied, else return non-zero.*/ int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out) { node_assert_ok(node); tor_assert(ap_out); if (node->ri) { if (node->ri->addr == 0 || node->ri->or_port == 0) return -1; tor_addr_from_ipv4h(&ap_out->addr, node->ri->addr); ap_out->port = node->ri->or_port; return 0; } if (node->rs) { if (node->rs->addr == 0 || node->rs->or_port == 0) return -1; tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr); ap_out->port = node->rs->or_port; return 0; } return -1; } /** Copy the preferred OR port (IP address and TCP port) for * node into *ap_out. */ void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out) { const or_options_t *options = get_options(); tor_assert(ap_out); /* Cheap implementation of config option ClientUseIPv6 -- simply don't prefer IPv6 when ClientUseIPv6 is not set and we're not a client running with bridges. See #4455 for more on this subject. Note that this filter is too strict since we're hindering not only clients! Erring on the safe side shouldn't be a problem though. XXX move this check to where outgoing connections are made? -LN */ if ((options->ClientUseIPv6 || options->UseBridges) && node_ipv6_preferred(node)) { node_get_pref_ipv6_orport(node, ap_out); } else { node_get_prim_orport(node, ap_out); } } /** Copy the preferred IPv6 OR port (IP address and TCP port) for * node into *ap_out. */ void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out) { node_assert_ok(node); tor_assert(ap_out); /* We prefer the microdesc over a potential routerstatus here. They are not being synchronised atm so there might be a chance that they differ at some point, f.ex. when flipping UseMicrodescriptors? -LN */ if (node->ri) { tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr); ap_out->port = node->ri->ipv6_orport; } else if (node->md) { tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr); ap_out->port = node->md->ipv6_orport; } else if (node->rs) { tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr); ap_out->port = node->rs->ipv6_orport; } } /** Return true iff node has a curve25519 onion key. */ int node_has_curve25519_onion_key(const node_t *node) { if (node->ri) return node->ri->onion_curve25519_pkey != NULL; else if (node->md) return node->md->onion_curve25519_pkey != NULL; else return 0; } /** Refresh the country code of ri. This function MUST be called on * each router when the GeoIP database is reloaded, and on all new routers. */ void node_set_country(node_t *node) { tor_addr_t addr = TOR_ADDR_NULL; /* XXXXipv6 */ if (node->rs) tor_addr_from_ipv4h(&addr, node->rs->addr); else if (node->ri) tor_addr_from_ipv4h(&addr, node->ri->addr); node->country = geoip_get_country_by_addr(&addr); } /** Set the country code of all routers in the routerlist. */ void nodelist_refresh_countries(void) { smartlist_t *nodes = nodelist_get_list(); SMARTLIST_FOREACH(nodes, node_t *, node, node_set_country(node)); } /** Return true iff router1 and router2 have similar enough network addresses * that we should treat them as being in the same family */ static INLINE int addrs_in_same_network_family(const tor_addr_t *a1, const tor_addr_t *a2) { return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC); } /** Return true if node's nickname matches nickname * (case-insensitive), or if node's identity key digest * matches a hexadecimal value stored in nickname. Return * false otherwise. */ static int node_nickname_matches(const node_t *node, const char *nickname) { const char *n = node_get_nickname(node); if (n && nickname[0]!='$' && !strcasecmp(n, nickname)) return 1; return hex_digest_nickname_matches(nickname, node->identity, n, node_is_named(node)); } /** Return true iff node is named by some nickname in lst. */ static INLINE int node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node) { if (!lst) return 0; SMARTLIST_FOREACH(lst, const char *, name, { if (node_nickname_matches(node, name)) return 1; }); return 0; } /** Return true iff r1 and r2 are in the same family, but not the same * router. */ int nodes_in_same_family(const node_t *node1, const node_t *node2) { const or_options_t *options = get_options(); /* Are they in the same family because of their addresses? */ if (options->EnforceDistinctSubnets) { tor_addr_t a1, a2; node_get_addr(node1, &a1); node_get_addr(node2, &a2); if (addrs_in_same_network_family(&a1, &a2)) return 1; } /* Are they in the same family because the agree they are? */ { const smartlist_t *f1, *f2; f1 = node_get_declared_family(node1); f2 = node_get_declared_family(node2); if (f1 && f2 && node_in_nickname_smartlist(f1, node2) && node_in_nickname_smartlist(f2, node1)) return 1; } /* Are they in the same option because the user says they are? */ if (options->NodeFamilySets) { SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { if (routerset_contains_node(rs, node1) && routerset_contains_node(rs, node2)) return 1; }); } return 0; } /** * Add all the family of node, including node itself, to * the smartlist sl. * * This is used to make sure we don't pick siblings in a single path, or * pick more than one relay from a family for our entry guard list. * Note that a node may be added to sl more than once if it is * part of node's family for more than one reason. */ void nodelist_add_node_and_family(smartlist_t *sl, const node_t *node) { const smartlist_t *all_nodes = nodelist_get_list(); const smartlist_t *declared_family; const or_options_t *options = get_options(); tor_assert(node); declared_family = node_get_declared_family(node); /* Let's make sure that we have the node itself, if it's a real node. */ { const node_t *real_node = node_get_by_id(node->identity); if (real_node) smartlist_add(sl, (node_t*)real_node); } /* First, add any nodes with similar network addresses. */ if (options->EnforceDistinctSubnets) { tor_addr_t node_addr; node_get_addr(node, &node_addr); SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) { tor_addr_t a; node_get_addr(node2, &a); if (addrs_in_same_network_family(&a, &node_addr)) smartlist_add(sl, (void*)node2); } SMARTLIST_FOREACH_END(node2); } /* Now, add all nodes in the declared_family of this node, if they * also declare this node to be in their family. */ if (declared_family) { /* Add every r such that router declares familyness with node, and node * declares familyhood with router. */ SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) { const node_t *node2; const smartlist_t *family2; if (!(node2 = node_get_by_nickname(name, 0))) continue; if (!(family2 = node_get_declared_family(node2))) continue; SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) { if (node_nickname_matches(node, name2)) { smartlist_add(sl, (void*)node2); break; } } SMARTLIST_FOREACH_END(name2); } SMARTLIST_FOREACH_END(name); } /* If the user declared any families locally, honor those too. */ if (options->NodeFamilySets) { SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { if (routerset_contains_node(rs, node)) { routerset_get_all_nodes(sl, rs, NULL, 0); } }); } } /** Find a router that's up, that has this IP address, and * that allows exit to this address:port, or return NULL if there * isn't a good one. * Don't exit enclave to excluded relays -- it wouldn't actually * hurt anything, but this way there are fewer confused users. */ const node_t * router_find_exact_exit_enclave(const char *address, uint16_t port) {/*XXXX MOVE*/ uint32_t addr; struct in_addr in; tor_addr_t a; const or_options_t *options = get_options(); if (!tor_inet_aton(address, &in)) return NULL; /* it's not an IP already */ addr = ntohl(in.s_addr); tor_addr_from_ipv4h(&a, addr); SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, { if (node_get_addr_ipv4h(node) == addr && node->is_running && compare_tor_addr_to_node_policy(&a, port, node) == ADDR_POLICY_ACCEPTED && !routerset_contains_node(options->ExcludeExitNodesUnion_, node)) return node; }); return NULL; } /** Return 1 if router is not suitable for these parameters, else 0. * If need_uptime is non-zero, we require a minimum uptime. * If need_capacity is non-zero, we require a minimum advertised * bandwidth. * If need_guard, we require that the router is a possible entry guard. */ int node_is_unreliable(const node_t *node, int need_uptime, int need_capacity, int need_guard) { if (need_uptime && !node->is_stable) return 1; if (need_capacity && !node->is_fast) return 1; if (need_guard && !node->is_possible_guard) return 1; return 0; } /** Return 1 if all running sufficiently-stable routers we can use will reject * addr:port. Return 0 if any might accept it. */ int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port, int need_uptime) { addr_policy_result_t r; SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { if (node->is_running && !node_is_unreliable(node, need_uptime, 0, 0)) { r = compare_tor_addr_to_node_policy(addr, port, node); if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED) return 0; /* this one could be ok. good enough. */ } } SMARTLIST_FOREACH_END(node); return 1; /* all will reject. */ } /** Mark the router with ID digest as running or non-running * in our routerlist. */ void router_set_status(const char *digest, int up) { node_t *node; tor_assert(digest); SMARTLIST_FOREACH(router_get_fallback_dir_servers(), dir_server_t *, d, if (tor_memeq(d->digest, digest, DIGEST_LEN)) d->is_running = up); SMARTLIST_FOREACH(router_get_trusted_dir_servers(), dir_server_t *, d, if (tor_memeq(d->digest, digest, DIGEST_LEN)) d->is_running = up); node = node_get_mutable_by_id(digest); if (node) { #if 0 log_debug(LD_DIR,"Marking router %s as %s.", node_describe(node), up ? "up" : "down"); #endif if (!up && node_is_me(node) && !net_is_disabled()) log_warn(LD_NET, "We just marked ourself as down. Are your external " "addresses reachable?"); node->is_running = up; } router_dir_info_changed(); } /** True iff, the last time we checked whether we had enough directory info * to build circuits, the answer was "yes". */ static int have_min_dir_info = 0; /** True iff enough has changed since the last time we checked whether we had * enough directory info to build circuits that our old answer can no longer * be trusted. */ static int need_to_update_have_min_dir_info = 1; /** String describing what we're missing before we have enough directory * info. */ static char dir_info_status[256] = ""; /** Return true iff we have enough networkstatus and router information to * start building circuits. Right now, this means "more than half the * networkstatus documents, and at least 1/4 of expected routers." */ //XXX should consider whether we have enough exiting nodes here. int router_have_minimum_dir_info(void) { if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) { update_router_have_minimum_dir_info(); need_to_update_have_min_dir_info = 0; } return have_min_dir_info; } /** Called when our internal view of the directory has changed. This can be * when the authorities change, networkstatuses change, the list of routerdescs * changes, or number of running routers changes. */ void router_dir_info_changed(void) { need_to_update_have_min_dir_info = 1; rend_hsdir_routers_changed(); } /** Return a string describing what we're missing before we have enough * directory info. */ const char * get_dir_info_status_string(void) { return dir_info_status; } /** Iterate over the servers listed in consensus, and count how many of * them seem like ones we'd use, and how many of those we have * descriptors for. Store the former in *num_usable and the latter in * *num_present. If in_set is non-NULL, only consider those * routers in in_set. If exit_only is true, only consider nodes * with the Exit flag. If *descs_out is present, add a node_t for each * usable descriptor to it. */ static void count_usable_descriptors(int *num_present, int *num_usable, smartlist_t *descs_out, const networkstatus_t *consensus, const or_options_t *options, time_t now, routerset_t *in_set, int exit_only) { const int md = (consensus->flavor == FLAV_MICRODESC); *num_present = 0, *num_usable=0; SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs) { const node_t *node = node_get_by_id(rs->identity_digest); if (!node) continue; /* This would be a bug: every entry in the consensus is * supposed to have a node. */ if (exit_only && ! rs->is_exit) continue; if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1)) continue; if (client_would_use_router(rs, now, options)) { const char * const digest = rs->descriptor_digest; int present; ++*num_usable; /* the consensus says we want it. */ if (md) present = NULL != microdesc_cache_lookup_by_digest256(NULL, digest); else present = NULL != router_get_by_descriptor_digest(digest); if (present) { /* we have the descriptor listed in the consensus. */ ++*num_present; } if (descs_out) smartlist_add(descs_out, (node_t*)node); } } SMARTLIST_FOREACH_END(rs); log_debug(LD_DIR, "%d usable, %d present (%s%s).", *num_usable, *num_present, md ? "microdesc" : "desc", exit_only ? " exits" : "s"); } /** Return an extimate of which fraction of usable paths through the Tor * network we have available for use. */ static double compute_frac_paths_available(const networkstatus_t *consensus, const or_options_t *options, time_t now, int *num_present_out, int *num_usable_out, char **status_out) { smartlist_t *guards = smartlist_new(); smartlist_t *mid = smartlist_new(); smartlist_t *exits = smartlist_new(); smartlist_t *myexits= smartlist_new(); double f_guard, f_mid, f_exit, f_myexit; int np, nu; /* Ignored */ const int authdir = authdir_mode_v2(options) || authdir_mode_v3(options); count_usable_descriptors(num_present_out, num_usable_out, mid, consensus, options, now, NULL, 0); if (options->EntryNodes) { count_usable_descriptors(&np, &nu, guards, consensus, options, now, options->EntryNodes, 0); } else { SMARTLIST_FOREACH(mid, const node_t *, node, { if (authdir) { if (node->rs && node->rs->is_possible_guard) smartlist_add(guards, (node_t*)node); } else { if (node->is_possible_guard) smartlist_add(guards, (node_t*)node); } }); } count_usable_descriptors(&np, &nu, exits, consensus, options, now, NULL, 1); count_usable_descriptors(&np, &nu, myexits, consensus, options, now, options->ExitNodes, 1); f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD); f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID); f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT); f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT); smartlist_free(guards); smartlist_free(mid); smartlist_free(exits); smartlist_free(myexits); /* This is a tricky point here: we don't want to make it easy for a * directory to trickle exits to us until it learns which exits we have * configured, so require that we have a threshold both of total exits * and usable exits. */ if (f_myexit < f_exit) f_exit = f_myexit; tor_asprintf(status_out, "%d%% of guards bw, " "%d%% of midpoint bw, and " "%d%% of exit bw", (int)(f_guard*100), (int)(f_mid*100), (int)(f_exit*100)); return f_guard * f_mid * f_exit; } /** We just fetched a new set of descriptors. Compute how far through * the "loading descriptors" bootstrapping phase we are, so we can inform * the controller of our progress. */ int count_loading_descriptors_progress(void) { int num_present = 0, num_usable=0; time_t now = time(NULL); const networkstatus_t *consensus = networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor()); double fraction; if (!consensus) return 0; /* can't count descriptors if we have no list of them */ count_usable_descriptors(&num_present, &num_usable, NULL, consensus, get_options(), now, NULL, 0); if (num_usable == 0) return 0; /* don't div by 0 */ fraction = num_present / (num_usable/4.); if (fraction > 1.0) return 0; /* it's not the number of descriptors holding us back */ return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int) (fraction*(BOOTSTRAP_STATUS_CONN_OR-1 - BOOTSTRAP_STATUS_LOADING_DESCRIPTORS)); } /** Return the fraction of paths needed before we're willing to build * circuits, as configured in options, or in the consensus ns. */ static double get_frac_paths_needed_for_circs(const or_options_t *options, const networkstatus_t *ns) { #define DFLT_PCT_USABLE_NEEDED 60 if (options->PathsNeededToBuildCircuits >= 0.0) { return options->PathsNeededToBuildCircuits; } else { return networkstatus_get_param(ns, "min_paths_for_circs_pct", DFLT_PCT_USABLE_NEEDED, 25, 95)/100.0; } } /** Change the value of have_min_dir_info, setting it true iff we have enough * network and router information to build circuits. Clear the value of * need_to_update_have_min_dir_info. */ static void update_router_have_minimum_dir_info(void) { time_t now = time(NULL); int res; const or_options_t *options = get_options(); const networkstatus_t *consensus = networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor()); int using_md; if (!consensus) { if (!networkstatus_get_latest_consensus()) strlcpy(dir_info_status, "We have no usable consensus.", sizeof(dir_info_status)); else strlcpy(dir_info_status, "We have no recent usable consensus.", sizeof(dir_info_status)); res = 0; goto done; } if (should_delay_dir_fetches(get_options())) { log_notice(LD_DIR, "no known bridge descriptors running yet; stalling"); strlcpy(dir_info_status, "No live bridge descriptors.", sizeof(dir_info_status)); res = 0; goto done; } using_md = consensus->flavor == FLAV_MICRODESC; { char *status = NULL; int num_present=0, num_usable=0; double paths = compute_frac_paths_available(consensus, options, now, &num_present, &num_usable, &status); if (paths < get_frac_paths_needed_for_circs(options,consensus)) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "We need more %sdescriptors: we have %d/%d, and " "can only build %d%% of likely paths. (We have %s.)", using_md?"micro":"", num_present, num_usable, (int)(paths*100), status); /* log_notice(LD_NET, "%s", dir_info_status); */ tor_free(status); res = 0; control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); goto done; } tor_free(status); res = 1; } done: if (res && !have_min_dir_info) { log_notice(LD_DIR, "We now have enough directory information to build circuits."); control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO"); control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0); } if (!res && have_min_dir_info) { int quiet = directory_too_idle_to_fetch_descriptors(options, now); tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, "Our directory information is no longer up-to-date " "enough to build circuits: %s", dir_info_status); /* a) make us log when we next complete a circuit, so we know when Tor * is back up and usable, and b) disable some activities that Tor * should only do while circuits are working, like reachability tests * and fetching bridge descriptors only over circuits. */ can_complete_circuit = 0; control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO"); } have_min_dir_info = res; need_to_update_have_min_dir_info = 0; } tor-0.2.4.20/src/or/onion_fast.h0000644000175000017500000000221312166112777013211 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file onion_fast.h * \brief Header file for onion_fast.c. **/ #ifndef TOR_ONION_FAST_H #define TOR_ONION_FAST_H #define CREATE_FAST_LEN DIGEST_LEN #define CREATED_FAST_LEN (DIGEST_LEN*2) typedef struct fast_handshake_state_t { uint8_t state[DIGEST_LEN]; } fast_handshake_state_t; void fast_handshake_state_free(fast_handshake_state_t *victim); int fast_onionskin_create(fast_handshake_state_t **handshake_state_out, uint8_t *handshake_out); int fast_server_handshake(const uint8_t *message_in, uint8_t *handshake_reply_out, uint8_t *key_out, size_t key_out_len); int fast_client_handshake(const fast_handshake_state_t *handshake_state, const uint8_t *handshake_reply_out, uint8_t *key_out, size_t key_out_len); #endif tor-0.2.4.20/src/or/status.c0000644000175000017500000000703612255745673012406 00000000000000/* Copyright (c) 2010-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file status.c * \brief Keep status information and log the heartbeat messages. **/ #include "or.h" #include "config.h" #include "status.h" #include "nodelist.h" #include "relay.h" #include "router.h" #include "circuitlist.h" #include "main.h" #include "hibernate.h" /** Return the total number of circuits. */ static int count_circuits(void) { circuit_t *circ; int nr=0; for (circ = circuit_get_global_list_(); circ; circ = circ->next) nr++; return nr; } /** Take seconds secs and return a newly allocated human-readable * uptime string */ static char * secs_to_uptime(long secs) { long int days = secs / 86400; int hours = (int)((secs - (days * 86400)) / 3600); int minutes = (int)((secs - (days * 86400) - (hours * 3600)) / 60); char *uptime_string = NULL; switch (days) { case 0: tor_asprintf(&uptime_string, "%d:%02d hours", hours, minutes); break; case 1: tor_asprintf(&uptime_string, "%ld day %d:%02d hours", days, hours, minutes); break; default: tor_asprintf(&uptime_string, "%ld days %d:%02d hours", days, hours, minutes); break; } return uptime_string; } /** Take bytes and returns a newly allocated human-readable usage * string. */ static char * bytes_to_usage(uint64_t bytes) { char *bw_string = NULL; if (bytes < (1<<20)) { /* Less than a megabyte. */ tor_asprintf(&bw_string, U64_FORMAT" kB", U64_PRINTF_ARG(bytes>>10)); } else if (bytes < (1<<30)) { /* Megabytes. Let's add some precision. */ double bw = U64_TO_DBL(bytes); tor_asprintf(&bw_string, "%.2f MB", bw/(1<<20)); } else { /* Gigabytes. */ double bw = U64_TO_DBL(bytes); tor_asprintf(&bw_string, "%.2f GB", bw/(1<<30)); } return bw_string; } /** Log a "heartbeat" message describing Tor's status and history so that the * user can know that there is indeed a running Tor. Return 0 on success and * -1 on failure. */ int log_heartbeat(time_t now) { char *bw_sent = NULL; char *bw_rcvd = NULL; char *uptime = NULL; const routerinfo_t *me; double r = tls_get_write_overhead_ratio(); const int hibernating = we_are_hibernating(); const or_options_t *options = get_options(); (void)now; if (public_server_mode(options) && !hibernating) { /* Let's check if we are in the current cached consensus. */ if (!(me = router_get_my_routerinfo())) return -1; /* Something stinks, we won't even attempt this. */ else if (!node_get_by_id(me->cache_info.identity_digest)) log_fn(LOG_NOTICE, LD_HEARTBEAT, "Heartbeat: It seems like we are not " "in the cached consensus."); } uptime = secs_to_uptime(get_uptime()); bw_rcvd = bytes_to_usage(get_bytes_read()); bw_sent = bytes_to_usage(get_bytes_written()); log_fn(LOG_NOTICE, LD_HEARTBEAT, "Heartbeat: Tor's uptime is %s, with %d " "circuits open. I've sent %s and received %s.%s", uptime, count_circuits(),bw_sent,bw_rcvd, hibernating?" We are currently hibernating.":""); if (stats_n_data_cells_packaged && !hibernating) log_notice(LD_HEARTBEAT, "Average packaged cell fullness: %2.3f%%", 100*(U64_TO_DBL(stats_n_data_bytes_packaged) / U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); if (r > 1.0) { double overhead = ( r - 1.0 ) * 100.0; log_notice(LD_HEARTBEAT, "TLS write overhead: %.f%%", overhead); } tor_free(uptime); tor_free(bw_sent); tor_free(bw_rcvd); return 0; } tor-0.2.4.20/src/or/main.c0000644000175000017500000026372312255745673012016 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file main.c * \brief Toplevel module. Handles signals, multiplexes between * connections, implements main loop, and drives scheduled events. **/ #define MAIN_PRIVATE #include "or.h" #include "addressmap.h" #include "buffers.h" #include "channel.h" #include "channeltls.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuituse.h" #include "command.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "connection_or.h" #include "control.h" #include "cpuworker.h" #include "directory.h" #include "dirserv.h" #include "dirvote.h" #include "dns.h" #include "dnsserv.h" #include "entrynodes.h" #include "geoip.h" #include "hibernate.h" #include "main.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "ntmain.h" #include "onion.h" #include "policies.h" #include "transports.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" #include "rendservice.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" #include "statefile.h" #include "status.h" #ifdef USE_DMALLOC #include #include #endif #include "memarea.h" #ifdef HAVE_EVENT2_EVENT_H #include #else #include #endif #ifdef USE_BUFFEREVENTS #include #endif void evdns_shutdown(int); /********* PROTOTYPES **********/ static void dumpmemusage(int severity); static void dumpstats(int severity); /* log stats */ static void conn_read_callback(evutil_socket_t fd, short event, void *_conn); static void conn_write_callback(evutil_socket_t fd, short event, void *_conn); static void second_elapsed_callback(periodic_timer_t *timer, void *args); static int conn_close_if_marked(int i); static void connection_start_reading_from_linked_conn(connection_t *conn); static int connection_should_read_from_linked_conn(connection_t *conn); /********* START VARIABLES **********/ #ifndef USE_BUFFEREVENTS int global_read_bucket; /**< Max number of bytes I can read this second. */ int global_write_bucket; /**< Max number of bytes I can write this second. */ /** Max number of relayed (bandwidth class 1) bytes I can read this second. */ int global_relayed_read_bucket; /** Max number of relayed (bandwidth class 1) bytes I can write this second. */ int global_relayed_write_bucket; /** What was the read bucket before the last second_elapsed_callback() call? * (used to determine how many bytes we've read). */ static int stats_prev_global_read_bucket; /** What was the write bucket before the last second_elapsed_callback() call? * (used to determine how many bytes we've written). */ static int stats_prev_global_write_bucket; #endif /* DOCDOC stats_prev_n_read */ static uint64_t stats_prev_n_read = 0; /* DOCDOC stats_prev_n_written */ static uint64_t stats_prev_n_written = 0; /* XXX we might want to keep stats about global_relayed_*_bucket too. Or not.*/ /** How many bytes have we read since we started the process? */ static uint64_t stats_n_bytes_read = 0; /** How many bytes have we written since we started the process? */ static uint64_t stats_n_bytes_written = 0; /** What time did this process start up? */ time_t time_of_process_start = 0; /** How many seconds have we been running? */ long stats_n_seconds_working = 0; /** When do we next launch DNS wildcarding checks? */ static time_t time_to_check_for_correct_dns = 0; /** How often will we honor SIGNEWNYM requests? */ #define MAX_SIGNEWNYM_RATE 10 /** When did we last process a SIGNEWNYM request? */ static time_t time_of_last_signewnym = 0; /** Is there a signewnym request we're currently waiting to handle? */ static int signewnym_is_pending = 0; /** How many times have we called newnym? */ static unsigned newnym_epoch = 0; /** Smartlist of all open connections. */ static smartlist_t *connection_array = NULL; /** List of connections that have been marked for close and need to be freed * and removed from connection_array. */ static smartlist_t *closeable_connection_lst = NULL; /** List of linked connections that are currently reading data into their * inbuf from their partner's outbuf. */ static smartlist_t *active_linked_connection_lst = NULL; /** Flag: Set to true iff we entered the current libevent main loop via * loop_once. If so, there's no need to trigger a loopexit in order * to handle linked connections. */ static int called_loop_once = 0; /** We set this to 1 when we've opened a circuit, so we can print a log * entry to inform the user that Tor is working. We set it to 0 when * we think the fact that we once opened a circuit doesn't mean we can do so * any longer (a big time jump happened, when we notice our directory is * heinously out-of-date, etc. */ int can_complete_circuit=0; /** How often do we check for router descriptors that we should download * when we have too little directory info? */ #define GREEDY_DESCRIPTOR_RETRY_INTERVAL (10) /** How often do we check for router descriptors that we should download * when we have enough directory info? */ #define LAZY_DESCRIPTOR_RETRY_INTERVAL (60) /** How often do we 'forgive' undownloadable router descriptors and attempt * to download them again? */ #define DESCRIPTOR_FAILURE_RESET_INTERVAL (60*60) /** How long do we let a directory connection stall before expiring it? */ #define DIR_CONN_MAX_STALL (5*60) /** Decides our behavior when no logs are configured/before any * logs have been configured. For 0, we log notice to stdout as normal. * For 1, we log warnings only. For 2, we log nothing. */ int quiet_level = 0; /********* END VARIABLES ************/ /**************************************************************************** * * This section contains accessors and other methods on the connection_array * variables (which are global within this file and unavailable outside it). * ****************************************************************************/ #if 0 && defined(USE_BUFFEREVENTS) static void free_old_inbuf(connection_t *conn) { if (! conn->inbuf) return; tor_assert(conn->outbuf); tor_assert(buf_datalen(conn->inbuf) == 0); tor_assert(buf_datalen(conn->outbuf) == 0); buf_free(conn->inbuf); buf_free(conn->outbuf); conn->inbuf = conn->outbuf = NULL; if (conn->read_event) { event_del(conn->read_event); tor_event_free(conn->read_event); } if (conn->write_event) { event_del(conn->read_event); tor_event_free(conn->write_event); } conn->read_event = conn->write_event = NULL; } #endif #if defined(_WIN32) && defined(USE_BUFFEREVENTS) /** Remove the kernel-space send and receive buffers for s. For use * with IOCP only. */ static int set_buffer_lengths_to_zero(tor_socket_t s) { int zero = 0; int r = 0; if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&zero, sizeof(zero))) { log_warn(LD_NET, "Unable to clear SO_SNDBUF"); r = -1; } if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&zero, sizeof(zero))) { log_warn(LD_NET, "Unable to clear SO_RCVBUF"); r = -1; } return r; } #endif /** Add conn to the array of connections that we can poll on. The * connection's socket must be set; the connection starts out * non-reading and non-writing. */ int connection_add_impl(connection_t *conn, int is_connecting) { tor_assert(conn); tor_assert(SOCKET_OK(conn->s) || conn->linked || (conn->type == CONN_TYPE_AP && TO_EDGE_CONN(conn)->is_dns_request)); tor_assert(conn->conn_array_index == -1); /* can only connection_add once */ conn->conn_array_index = smartlist_len(connection_array); smartlist_add(connection_array, conn); #ifdef USE_BUFFEREVENTS if (connection_type_uses_bufferevent(conn)) { if (SOCKET_OK(conn->s) && !conn->linked) { #ifdef _WIN32 if (tor_libevent_using_iocp_bufferevents() && get_options()->UserspaceIOCPBuffers) { set_buffer_lengths_to_zero(conn->s); } #endif conn->bufev = bufferevent_socket_new( tor_libevent_get_base(), conn->s, BEV_OPT_DEFER_CALLBACKS); if (!conn->bufev) { log_warn(LD_BUG, "Unable to create socket bufferevent"); smartlist_del(connection_array, conn->conn_array_index); conn->conn_array_index = -1; return -1; } if (is_connecting) { /* Put the bufferevent into a "connecting" state so that we'll get * a "connected" event callback on successful write. */ bufferevent_socket_connect(conn->bufev, NULL, 0); } connection_configure_bufferevent_callbacks(conn); } else if (conn->linked && conn->linked_conn && connection_type_uses_bufferevent(conn->linked_conn)) { tor_assert(!(SOCKET_OK(conn->s))); if (!conn->bufev) { struct bufferevent *pair[2] = { NULL, NULL }; if (bufferevent_pair_new(tor_libevent_get_base(), BEV_OPT_DEFER_CALLBACKS, pair) < 0) { log_warn(LD_BUG, "Unable to create bufferevent pair"); smartlist_del(connection_array, conn->conn_array_index); conn->conn_array_index = -1; return -1; } tor_assert(pair[0]); conn->bufev = pair[0]; conn->linked_conn->bufev = pair[1]; } /* else the other side already was added, and got a bufferevent_pair */ connection_configure_bufferevent_callbacks(conn); } else { tor_assert(!conn->linked); } if (conn->bufev) tor_assert(conn->inbuf == NULL); if (conn->linked_conn && conn->linked_conn->bufev) tor_assert(conn->linked_conn->inbuf == NULL); } #else (void) is_connecting; #endif if (!HAS_BUFFEREVENT(conn) && (SOCKET_OK(conn->s) || conn->linked)) { conn->read_event = tor_event_new(tor_libevent_get_base(), conn->s, EV_READ|EV_PERSIST, conn_read_callback, conn); conn->write_event = tor_event_new(tor_libevent_get_base(), conn->s, EV_WRITE|EV_PERSIST, conn_write_callback, conn); /* XXXX CHECK FOR NULL RETURN! */ } log_debug(LD_NET,"new conn type %s, socket %d, address %s, n_conns %d.", conn_type_to_string(conn->type), (int)conn->s, conn->address, smartlist_len(connection_array)); return 0; } /** Tell libevent that we don't care about conn any more. */ void connection_unregister_events(connection_t *conn) { if (conn->read_event) { if (event_del(conn->read_event)) log_warn(LD_BUG, "Error removing read event for %d", (int)conn->s); tor_free(conn->read_event); } if (conn->write_event) { if (event_del(conn->write_event)) log_warn(LD_BUG, "Error removing write event for %d", (int)conn->s); tor_free(conn->write_event); } #ifdef USE_BUFFEREVENTS if (conn->bufev) { bufferevent_free(conn->bufev); conn->bufev = NULL; } #endif if (conn->type == CONN_TYPE_AP_DNS_LISTENER) { dnsserv_close_listener(conn); } } /** Remove the connection from the global list, and remove the * corresponding poll entry. Calling this function will shift the last * connection (if any) into the position occupied by conn. */ int connection_remove(connection_t *conn) { int current_index; connection_t *tmp; tor_assert(conn); log_debug(LD_NET,"removing socket %d (type %s), n_conns now %d", (int)conn->s, conn_type_to_string(conn->type), smartlist_len(connection_array)); tor_assert(conn->conn_array_index >= 0); current_index = conn->conn_array_index; connection_unregister_events(conn); /* This is redundant, but cheap. */ if (current_index == smartlist_len(connection_array)-1) { /* at the end */ smartlist_del(connection_array, current_index); return 0; } /* replace this one with the one at the end */ smartlist_del(connection_array, current_index); tmp = smartlist_get(connection_array, current_index); tmp->conn_array_index = current_index; return 0; } /** If conn is an edge conn, remove it from the list * of conn's on this circuit. If it's not on an edge, * flush and send destroys for all circuits on this conn. * * Remove it from connection_array (if applicable) and * from closeable_connection_list. * * Then free it. */ static void connection_unlink(connection_t *conn) { connection_about_to_close_connection(conn); if (conn->conn_array_index >= 0) { connection_remove(conn); } if (conn->linked_conn) { conn->linked_conn->linked_conn = NULL; if (! conn->linked_conn->marked_for_close && conn->linked_conn->reading_from_linked_conn) connection_start_reading(conn->linked_conn); conn->linked_conn = NULL; } smartlist_remove(closeable_connection_lst, conn); smartlist_remove(active_linked_connection_lst, conn); if (conn->type == CONN_TYPE_EXIT) { assert_connection_edge_not_dns_pending(TO_EDGE_CONN(conn)); } if (conn->type == CONN_TYPE_OR) { if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) connection_or_remove_from_identity_map(TO_OR_CONN(conn)); /* connection_unlink() can only get called if the connection * was already on the closeable list, and it got there by * connection_mark_for_close(), which was called from * connection_or_close_normally() or * connection_or_close_for_error(), so the channel should * already be in CHANNEL_STATE_CLOSING, and then the * connection_about_to_close_connection() goes to * connection_or_about_to_close(), which calls channel_closed() * to notify the channel_t layer, and closed the channel, so * nothing more to do here to deal with the channel associated * with an orconn. */ } connection_free(conn); } /** Schedule conn to be closed. **/ void add_connection_to_closeable_list(connection_t *conn) { tor_assert(!smartlist_contains(closeable_connection_lst, conn)); tor_assert(conn->marked_for_close); assert_connection_ok(conn, time(NULL)); smartlist_add(closeable_connection_lst, conn); } /** Return 1 if conn is on the closeable list, else return 0. */ int connection_is_on_closeable_list(connection_t *conn) { return smartlist_contains(closeable_connection_lst, conn); } /** Return true iff conn is in the current poll array. */ int connection_in_array(connection_t *conn) { return smartlist_contains(connection_array, conn); } /** Set *array to an array of all connections, and *n * to the length of the array. *array and *n must not * be modified. */ smartlist_t * get_connection_array(void) { if (!connection_array) connection_array = smartlist_new(); return connection_array; } /** Provides the traffic read and written over the life of the process. */ uint64_t get_bytes_read(void) { return stats_n_bytes_read; } /* DOCDOC get_bytes_written */ uint64_t get_bytes_written(void) { return stats_n_bytes_written; } /** Set the event mask on conn to events. (The event * mask is a bitmask whose bits are READ_EVENT and WRITE_EVENT) */ void connection_watch_events(connection_t *conn, watchable_events_t events) { IF_HAS_BUFFEREVENT(conn, { short ev = ((short)events) & (EV_READ|EV_WRITE); short old_ev = bufferevent_get_enabled(conn->bufev); if ((ev & ~old_ev) != 0) { bufferevent_enable(conn->bufev, ev); } if ((old_ev & ~ev) != 0) { bufferevent_disable(conn->bufev, old_ev & ~ev); } return; }); if (events & READ_EVENT) connection_start_reading(conn); else connection_stop_reading(conn); if (events & WRITE_EVENT) connection_start_writing(conn); else connection_stop_writing(conn); } /** Return true iff conn is listening for read events. */ int connection_is_reading(connection_t *conn) { tor_assert(conn); IF_HAS_BUFFEREVENT(conn, return (bufferevent_get_enabled(conn->bufev) & EV_READ) != 0; ); return conn->reading_from_linked_conn || (conn->read_event && event_pending(conn->read_event, EV_READ, NULL)); } /** Tell the main loop to stop notifying conn of any read events. */ void connection_stop_reading(connection_t *conn) { tor_assert(conn); IF_HAS_BUFFEREVENT(conn, { bufferevent_disable(conn->bufev, EV_READ); return; }); tor_assert(conn->read_event); if (conn->linked) { conn->reading_from_linked_conn = 0; connection_stop_reading_from_linked_conn(conn); } else { if (event_del(conn->read_event)) log_warn(LD_NET, "Error from libevent setting read event state for %d " "to unwatched: %s", (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); } } /** Tell the main loop to start notifying conn of any read events. */ void connection_start_reading(connection_t *conn) { tor_assert(conn); IF_HAS_BUFFEREVENT(conn, { bufferevent_enable(conn->bufev, EV_READ); return; }); tor_assert(conn->read_event); if (conn->linked) { conn->reading_from_linked_conn = 1; if (connection_should_read_from_linked_conn(conn)) connection_start_reading_from_linked_conn(conn); } else { if (event_add(conn->read_event, NULL)) log_warn(LD_NET, "Error from libevent setting read event state for %d " "to watched: %s", (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); } } /** Return true iff conn is listening for write events. */ int connection_is_writing(connection_t *conn) { tor_assert(conn); IF_HAS_BUFFEREVENT(conn, return (bufferevent_get_enabled(conn->bufev) & EV_WRITE) != 0; ); return conn->writing_to_linked_conn || (conn->write_event && event_pending(conn->write_event, EV_WRITE, NULL)); } /** Tell the main loop to stop notifying conn of any write events. */ void connection_stop_writing(connection_t *conn) { tor_assert(conn); IF_HAS_BUFFEREVENT(conn, { bufferevent_disable(conn->bufev, EV_WRITE); return; }); tor_assert(conn->write_event); if (conn->linked) { conn->writing_to_linked_conn = 0; if (conn->linked_conn) connection_stop_reading_from_linked_conn(conn->linked_conn); } else { if (event_del(conn->write_event)) log_warn(LD_NET, "Error from libevent setting write event state for %d " "to unwatched: %s", (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); } } /** Tell the main loop to start notifying conn of any write events. */ void connection_start_writing(connection_t *conn) { tor_assert(conn); IF_HAS_BUFFEREVENT(conn, { bufferevent_enable(conn->bufev, EV_WRITE); return; }); tor_assert(conn->write_event); if (conn->linked) { conn->writing_to_linked_conn = 1; if (conn->linked_conn && connection_should_read_from_linked_conn(conn->linked_conn)) connection_start_reading_from_linked_conn(conn->linked_conn); } else { if (event_add(conn->write_event, NULL)) log_warn(LD_NET, "Error from libevent setting write event state for %d " "to watched: %s", (int)conn->s, tor_socket_strerror(tor_socket_errno(conn->s))); } } /** Return true iff conn is linked conn, and reading from the conn * linked to it would be good and feasible. (Reading is "feasible" if the * other conn exists and has data in its outbuf, and is "good" if we have our * reading_from_linked_conn flag set and the other conn has its * writing_to_linked_conn flag set.)*/ static int connection_should_read_from_linked_conn(connection_t *conn) { if (conn->linked && conn->reading_from_linked_conn) { if (! conn->linked_conn || (conn->linked_conn->writing_to_linked_conn && buf_datalen(conn->linked_conn->outbuf))) return 1; } return 0; } /** Helper: Tell the main loop to begin reading bytes into conn from * its linked connection, if it is not doing so already. Called by * connection_start_reading and connection_start_writing as appropriate. */ static void connection_start_reading_from_linked_conn(connection_t *conn) { tor_assert(conn); tor_assert(conn->linked == 1); if (!conn->active_on_link) { conn->active_on_link = 1; smartlist_add(active_linked_connection_lst, conn); if (!called_loop_once) { /* This is the first event on the list; we won't be in LOOP_ONCE mode, * so we need to make sure that the event_base_loop() actually exits at * the end of its run through the current connections and lets us * activate read events for linked connections. */ struct timeval tv = { 0, 0 }; tor_event_base_loopexit(tor_libevent_get_base(), &tv); } } else { tor_assert(smartlist_contains(active_linked_connection_lst, conn)); } } /** Tell the main loop to stop reading bytes into conn from its linked * connection, if is currently doing so. Called by connection_stop_reading, * connection_stop_writing, and connection_read. */ void connection_stop_reading_from_linked_conn(connection_t *conn) { tor_assert(conn); tor_assert(conn->linked == 1); if (conn->active_on_link) { conn->active_on_link = 0; /* FFFF We could keep an index here so we can smartlist_del * cleanly. On the other hand, this doesn't show up on profiles, * so let's leave it alone for now. */ smartlist_remove(active_linked_connection_lst, conn); } else { tor_assert(!smartlist_contains(active_linked_connection_lst, conn)); } } /** Close all connections that have been scheduled to get closed. */ static void close_closeable_connections(void) { int i; for (i = 0; i < smartlist_len(closeable_connection_lst); ) { connection_t *conn = smartlist_get(closeable_connection_lst, i); if (conn->conn_array_index < 0) { connection_unlink(conn); /* blow it away right now */ } else { if (!conn_close_if_marked(conn->conn_array_index)) ++i; } } } /** Libevent callback: this gets invoked when (connection_t*)conn has * some data to read. */ static void conn_read_callback(evutil_socket_t fd, short event, void *_conn) { connection_t *conn = _conn; (void)fd; (void)event; log_debug(LD_NET,"socket %d wants to read.",(int)conn->s); /* assert_connection_ok(conn, time(NULL)); */ if (connection_handle_read(conn) < 0) { if (!conn->marked_for_close) { #ifndef _WIN32 log_warn(LD_BUG,"Unhandled error on read for %s connection " "(fd %d); removing", conn_type_to_string(conn->type), (int)conn->s); tor_fragile_assert(); #endif if (CONN_IS_EDGE(conn)) connection_edge_end_errno(TO_EDGE_CONN(conn)); connection_mark_for_close(conn); } } assert_connection_ok(conn, time(NULL)); if (smartlist_len(closeable_connection_lst)) close_closeable_connections(); } /** Libevent callback: this gets invoked when (connection_t*)conn has * some data to write. */ static void conn_write_callback(evutil_socket_t fd, short events, void *_conn) { connection_t *conn = _conn; (void)fd; (void)events; LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "socket %d wants to write.", (int)conn->s)); /* assert_connection_ok(conn, time(NULL)); */ if (connection_handle_write(conn, 0) < 0) { if (!conn->marked_for_close) { /* this connection is broken. remove it. */ log_fn(LOG_WARN,LD_BUG, "unhandled error on write for %s connection (fd %d); removing", conn_type_to_string(conn->type), (int)conn->s); tor_fragile_assert(); if (CONN_IS_EDGE(conn)) { /* otherwise we cry wolf about duplicate close */ edge_connection_t *edge_conn = TO_EDGE_CONN(conn); if (!edge_conn->end_reason) edge_conn->end_reason = END_STREAM_REASON_INTERNAL; edge_conn->edge_has_sent_end = 1; } connection_close_immediate(conn); /* So we don't try to flush. */ connection_mark_for_close(conn); } } assert_connection_ok(conn, time(NULL)); if (smartlist_len(closeable_connection_lst)) close_closeable_connections(); } /** If the connection at connection_array[i] is marked for close, then: * - If it has data that it wants to flush, try to flush it. * - If it _still_ has data to flush, and conn->hold_open_until_flushed is * true, then leave the connection open and return. * - Otherwise, remove the connection from connection_array and from * all other lists, close it, and free it. * Returns 1 if the connection was closed, 0 otherwise. */ static int conn_close_if_marked(int i) { connection_t *conn; int retval; time_t now; conn = smartlist_get(connection_array, i); if (!conn->marked_for_close) return 0; /* nothing to see here, move along */ now = time(NULL); assert_connection_ok(conn, now); /* assert_all_pending_dns_resolves_ok(); */ #ifdef USE_BUFFEREVENTS if (conn->bufev) { if (conn->hold_open_until_flushed && evbuffer_get_length(bufferevent_get_output(conn->bufev))) { /* don't close yet. */ return 0; } if (conn->linked_conn && ! conn->linked_conn->marked_for_close) { /* We need to do this explicitly so that the linked connection * notices that there was an EOF. */ bufferevent_flush(conn->bufev, EV_WRITE, BEV_FINISHED); } } #endif log_debug(LD_NET,"Cleaning up connection (fd "TOR_SOCKET_T_FORMAT").", conn->s); /* If the connection we are about to close was trying to connect to a proxy server and failed, the client won't be able to use that proxy. We should warn the user about this. */ if (conn->proxy_state == PROXY_INFANT) log_failed_proxy_connection(conn); IF_HAS_BUFFEREVENT(conn, goto unlink); if ((SOCKET_OK(conn->s) || conn->linked_conn) && connection_wants_to_flush(conn)) { /* s == -1 means it's an incomplete edge connection, or that the socket * has already been closed as unflushable. */ ssize_t sz = connection_bucket_write_limit(conn, now); if (!conn->hold_open_until_flushed) log_info(LD_NET, "Conn (addr %s, fd %d, type %s, state %d) marked, but wants " "to flush %d bytes. (Marked at %s:%d)", escaped_safe_str_client(conn->address), (int)conn->s, conn_type_to_string(conn->type), conn->state, (int)conn->outbuf_flushlen, conn->marked_for_close_file, conn->marked_for_close); if (conn->linked_conn) { retval = move_buf_to_buf(conn->linked_conn->inbuf, conn->outbuf, &conn->outbuf_flushlen); if (retval >= 0) { /* The linked conn will notice that it has data when it notices that * we're gone. */ connection_start_reading_from_linked_conn(conn->linked_conn); } log_debug(LD_GENERAL, "Flushed last %d bytes from a linked conn; " "%d left; flushlen %d; wants-to-flush==%d", retval, (int)connection_get_outbuf_len(conn), (int)conn->outbuf_flushlen, connection_wants_to_flush(conn)); } else if (connection_speaks_cells(conn)) { if (conn->state == OR_CONN_STATE_OPEN) { retval = flush_buf_tls(TO_OR_CONN(conn)->tls, conn->outbuf, sz, &conn->outbuf_flushlen); } else retval = -1; /* never flush non-open broken tls connections */ } else { retval = flush_buf(conn->s, conn->outbuf, sz, &conn->outbuf_flushlen); } if (retval >= 0 && /* Technically, we could survive things like TLS_WANT_WRITE here. But don't bother for now. */ conn->hold_open_until_flushed && connection_wants_to_flush(conn)) { if (retval > 0) { LOG_FN_CONN(conn, (LOG_INFO,LD_NET, "Holding conn (fd %d) open for more flushing.", (int)conn->s)); conn->timestamp_lastwritten = now; /* reset so we can flush more */ } else if (sz == 0) { /* Also, retval==0. If we get here, we didn't want to write anything * (because of rate-limiting) and we didn't. */ /* Connection must flush before closing, but it's being rate-limited. * Let's remove from Libevent, and mark it as blocked on bandwidth * so it will be re-added on next token bucket refill. Prevents * busy Libevent loops where we keep ending up here and returning * 0 until we are no longer blocked on bandwidth. */ if (connection_is_writing(conn)) { conn->write_blocked_on_bw = 1; connection_stop_writing(conn); } if (connection_is_reading(conn)) { /* XXXX024 We should make this code unreachable; if a connection is * marked for close and flushing, there is no point in reading to it * at all. Further, checking at this point is a bit of a hack: it * would make much more sense to react in * connection_handle_read_impl, or to just stop reading in * mark_and_flush */ #if 0 #define MARKED_READING_RATE 180 static ratelim_t marked_read_lim = RATELIM_INIT(MARKED_READING_RATE); char *m; if ((m = rate_limit_log(&marked_read_lim, now))) { log_warn(LD_BUG, "Marked connection (fd %d, type %s, state %s) " "is still reading; that shouldn't happen.%s", (int)conn->s, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state), m); tor_free(m); } #endif conn->read_blocked_on_bw = 1; connection_stop_reading(conn); } } return 0; } if (connection_wants_to_flush(conn)) { int severity; if (conn->type == CONN_TYPE_EXIT || (conn->type == CONN_TYPE_OR && server_mode(get_options())) || (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER)) severity = LOG_INFO; else severity = LOG_NOTICE; /* XXXX Maybe allow this to happen a certain amount per hour; it usually * is meaningless. */ log_fn(severity, LD_NET, "We stalled too much while trying to write %d " "bytes to address %s. If this happens a lot, either " "something is wrong with your network connection, or " "something is wrong with theirs. " "(fd %d, type %s, state %d, marked at %s:%d).", (int)connection_get_outbuf_len(conn), escaped_safe_str_client(conn->address), (int)conn->s, conn_type_to_string(conn->type), conn->state, conn->marked_for_close_file, conn->marked_for_close); } } #ifdef USE_BUFFEREVENTS unlink: #endif connection_unlink(conn); /* unlink, remove, free */ return 1; } /** We've just tried every dirserver we know about, and none of * them were reachable. Assume the network is down. Change state * so next time an application connection arrives we'll delay it * and try another directory fetch. Kill off all the circuit_wait * streams that are waiting now, since they will all timeout anyway. */ void directory_all_unreachable(time_t now) { connection_t *conn; (void)now; stats_n_seconds_working=0; /* reset it */ while ((conn = connection_get_by_type_state(CONN_TYPE_AP, AP_CONN_STATE_CIRCUIT_WAIT))) { entry_connection_t *entry_conn = TO_ENTRY_CONN(conn); log_notice(LD_NET, "Is your network connection down? " "Failing connection to '%s:%d'.", safe_str_client(entry_conn->socks_request->address), entry_conn->socks_request->port); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_NET_UNREACHABLE); } control_event_general_status(LOG_ERR, "DIR_ALL_UNREACHABLE"); } /** This function is called whenever we successfully pull down some new * network statuses or server descriptors. */ void directory_info_has_arrived(time_t now, int from_cache) { const or_options_t *options = get_options(); if (!router_have_minimum_dir_info()) { int quiet = from_cache || directory_too_idle_to_fetch_descriptors(options, now); tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, "I learned some more directory information, but not enough to " "build a circuit: %s", get_dir_info_status_string()); update_all_descriptor_downloads(now); return; } else { if (directory_fetches_from_authorities(options)) { update_all_descriptor_downloads(now); } /* if we have enough dir info, then update our guard status with * whatever we just learned. */ entry_guards_compute_status(options, now); /* Don't even bother trying to get extrainfo until the rest of our * directory info is up-to-date */ if (options->DownloadExtraInfo) update_extrainfo_downloads(now); } if (server_mode(options) && !net_is_disabled() && !from_cache && (can_complete_circuit || !any_predicted_circuits(now))) consider_testing_reachability(1, 1); } /** How long do we wait before killing OR connections with no circuits? * In Tor versions up to 0.2.1.25 and 0.2.2.12-alpha, we waited 15 minutes * before cancelling these connections, which caused fast relays to accrue * many many idle connections. Hopefully 3 minutes is low enough that * it kills most idle connections, without being so low that we cause * clients to bounce on and off. */ #define IDLE_OR_CONN_TIMEOUT 180 /** Perform regular maintenance tasks for a single connection. This * function gets run once per second per connection by run_scheduled_events. */ static void run_connection_housekeeping(int i, time_t now) { cell_t cell; connection_t *conn = smartlist_get(connection_array, i); const or_options_t *options = get_options(); or_connection_t *or_conn; int past_keepalive = now >= conn->timestamp_lastwritten + options->KeepalivePeriod; if (conn->outbuf && !connection_get_outbuf_len(conn) && conn->type == CONN_TYPE_OR) TO_OR_CONN(conn)->timestamp_lastempty = now; if (conn->marked_for_close) { /* nothing to do here */ return; } /* Expire any directory connections that haven't been active (sent * if a server or received if a client) for 5 min */ if (conn->type == CONN_TYPE_DIR && ((DIR_CONN_IS_SERVER(conn) && conn->timestamp_lastwritten + DIR_CONN_MAX_STALL < now) || (!DIR_CONN_IS_SERVER(conn) && conn->timestamp_lastread + DIR_CONN_MAX_STALL < now))) { log_info(LD_DIR,"Expiring wedged directory conn (fd %d, purpose %d)", (int)conn->s, conn->purpose); /* This check is temporary; it's to let us know whether we should consider * parsing partial serverdesc responses. */ if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC && connection_get_inbuf_len(conn) >= 1024) { log_info(LD_DIR,"Trying to extract information from wedged server desc " "download."); connection_dir_reached_eof(TO_DIR_CONN(conn)); } else { connection_mark_for_close(conn); } return; } if (!connection_speaks_cells(conn)) return; /* we're all done here, the rest is just for OR conns */ /* If we haven't written to an OR connection for a while, then either nuke the connection or send a keepalive, depending. */ or_conn = TO_OR_CONN(conn); #ifdef USE_BUFFEREVENTS tor_assert(conn->bufev); #else tor_assert(conn->outbuf); #endif if (channel_is_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan)) && !connection_or_get_num_circuits(or_conn)) { /* It's bad for new circuits, and has no unmarked circuits on it: * mark it now. */ log_info(LD_OR, "Expiring non-used OR connection to fd %d (%s:%d) [Too old].", (int)conn->s, conn->address, conn->port); if (conn->state == OR_CONN_STATE_CONNECTING) connection_or_connect_failed(TO_OR_CONN(conn), END_OR_CONN_REASON_TIMEOUT, "Tor gave up on the connection"); connection_or_close_normally(TO_OR_CONN(conn), 1); } else if (!connection_state_is_open(conn)) { if (past_keepalive) { /* We never managed to actually get this connection open and happy. */ log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).", (int)conn->s,conn->address, conn->port); connection_or_close_normally(TO_OR_CONN(conn), 0); } } else if (we_are_hibernating() && !connection_or_get_num_circuits(or_conn) && !connection_get_outbuf_len(conn)) { /* We're hibernating, there's no circuits, and nothing to flush.*/ log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " "[Hibernating or exiting].", (int)conn->s,conn->address, conn->port); connection_or_close_normally(TO_OR_CONN(conn), 1); } else if (!connection_or_get_num_circuits(or_conn) && now >= or_conn->timestamp_last_added_nonpadding + IDLE_OR_CONN_TIMEOUT) { log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " "[idle %d].", (int)conn->s,conn->address, conn->port, (int)(now - or_conn->timestamp_last_added_nonpadding)); connection_or_close_normally(TO_OR_CONN(conn), 0); } else if ( now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 && now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) { log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL, "Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to " "flush; %d seconds since last write)", (int)conn->s, conn->address, conn->port, (int)connection_get_outbuf_len(conn), (int)(now-conn->timestamp_lastwritten)); connection_or_close_normally(TO_OR_CONN(conn), 0); } else if (past_keepalive && !connection_get_outbuf_len(conn)) { /* send a padding cell */ log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)", conn->address, conn->port); memset(&cell,0,sizeof(cell_t)); cell.command = CELL_PADDING; connection_or_write_cell_to_buf(&cell, or_conn); } } /** Honor a NEWNYM request: make future requests unlinkable to past * requests. */ static void signewnym_impl(time_t now) { const or_options_t *options = get_options(); if (!proxy_mode(options)) { log_info(LD_CONTROL, "Ignoring SIGNAL NEWNYM because client functionality " "is disabled."); return; } circuit_mark_all_dirty_circs_as_unusable(); addressmap_clear_transient(); rend_client_purge_state(); time_of_last_signewnym = now; signewnym_is_pending = 0; ++newnym_epoch; control_event_signal(SIGNEWNYM); } /** Return the number of times that signewnym has been called. */ unsigned get_signewnym_epoch(void) { return newnym_epoch; } /** Perform regular maintenance tasks. This function gets run once per * second by second_elapsed_callback(). */ static void run_scheduled_events(time_t now) { static time_t last_rotated_x509_certificate = 0; static time_t time_to_check_v3_certificate = 0; static time_t time_to_check_listeners = 0; static time_t time_to_check_descriptor = 0; static time_t time_to_shrink_memory = 0; static time_t time_to_try_getting_descriptors = 0; static time_t time_to_reset_descriptor_failures = 0; static time_t time_to_add_entropy = 0; static time_t time_to_write_bridge_status_file = 0; static time_t time_to_downrate_stability = 0; static time_t time_to_save_stability = 0; static time_t time_to_clean_caches = 0; static time_t time_to_recheck_bandwidth = 0; static time_t time_to_check_for_expired_networkstatus = 0; static time_t time_to_write_stats_files = 0; static time_t time_to_write_bridge_stats = 0; static time_t time_to_check_port_forwarding = 0; static time_t time_to_launch_reachability_tests = 0; static int should_init_bridge_stats = 1; static time_t time_to_retry_dns_init = 0; static time_t time_to_next_heartbeat = 0; const or_options_t *options = get_options(); int is_server = server_mode(options); int i; int have_dir_info; /** 0. See if we've been asked to shut down and our timeout has * expired; or if our bandwidth limits are exhausted and we * should hibernate; or if it's time to wake up from hibernation. */ consider_hibernation(now); #if 0 { static time_t nl_check_time = 0; if (nl_check_time <= now) { nodelist_assert_ok(); nl_check_time = now + 30; } } #endif /* 0b. If we've deferred a signewnym, make sure it gets handled * eventually. */ if (signewnym_is_pending && time_of_last_signewnym + MAX_SIGNEWNYM_RATE <= now) { log_info(LD_CONTROL, "Honoring delayed NEWNYM request"); signewnym_impl(now); } /* 0c. If we've deferred log messages for the controller, handle them now */ flush_pending_log_callbacks(); /** 1a. Every MIN_ONION_KEY_LIFETIME seconds, rotate the onion keys, * shut down and restart all cpuworkers, and update the directory if * necessary. */ if (is_server && get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) { log_info(LD_GENERAL,"Rotating onion key."); rotate_onion_key(); cpuworkers_rotate(); if (router_rebuild_descriptor(1)<0) { log_info(LD_CONFIG, "Couldn't rebuild router descriptor"); } if (advertised_server_mode() && !options->DisableNetwork) router_upload_dir_desc_to_dirservers(0); } if (!options->DisableNetwork && time_to_try_getting_descriptors < now) { update_all_descriptor_downloads(now); update_extrainfo_downloads(now); if (router_have_minimum_dir_info()) time_to_try_getting_descriptors = now + LAZY_DESCRIPTOR_RETRY_INTERVAL; else time_to_try_getting_descriptors = now + GREEDY_DESCRIPTOR_RETRY_INTERVAL; } if (time_to_reset_descriptor_failures < now) { router_reset_descriptor_download_failures(); time_to_reset_descriptor_failures = now + DESCRIPTOR_FAILURE_RESET_INTERVAL; } if (options->UseBridges) fetch_bridge_descriptors(options, now); /** 1b. Every MAX_SSL_KEY_LIFETIME_INTERNAL seconds, we change our * TLS context. */ if (!last_rotated_x509_certificate) last_rotated_x509_certificate = now; if (last_rotated_x509_certificate+MAX_SSL_KEY_LIFETIME_INTERNAL < now) { log_info(LD_GENERAL,"Rotating tls context."); if (router_initialize_tls_context() < 0) { log_warn(LD_BUG, "Error reinitializing TLS context"); /* XXX is it a bug here, that we just keep going? -RD */ } last_rotated_x509_certificate = now; /* We also make sure to rotate the TLS connections themselves if they've * been up for too long -- but that's done via is_bad_for_new_circs in * connection_run_housekeeping() above. */ } if (time_to_add_entropy < now) { if (time_to_add_entropy) { /* We already seeded once, so don't die on failure. */ crypto_seed_rng(0); } /** How often do we add more entropy to OpenSSL's RNG pool? */ #define ENTROPY_INTERVAL (60*60) time_to_add_entropy = now + ENTROPY_INTERVAL; } /** 1c. If we have to change the accounting interval or record * bandwidth used in this accounting interval, do so. */ if (accounting_is_enabled(options)) accounting_run_housekeeping(now); if (time_to_launch_reachability_tests < now && (authdir_mode_tests_reachability(options)) && !net_is_disabled()) { time_to_launch_reachability_tests = now + REACHABILITY_TEST_INTERVAL; /* try to determine reachability of the other Tor relays */ dirserv_test_reachability(now); } /** 1d. Periodically, we discount older stability information so that new * stability info counts more, and save the stability information to disk as * appropriate. */ if (time_to_downrate_stability < now) time_to_downrate_stability = rep_hist_downrate_old_runs(now); if (authdir_mode_tests_reachability(options)) { if (time_to_save_stability < now) { if (time_to_save_stability && rep_hist_record_mtbf_data(now, 1)<0) { log_warn(LD_GENERAL, "Couldn't store mtbf data."); } #define SAVE_STABILITY_INTERVAL (30*60) time_to_save_stability = now + SAVE_STABILITY_INTERVAL; } } /* 1e. Periodically, if we're a v3 authority, we check whether our cert is * close to expiring and warn the admin if it is. */ if (time_to_check_v3_certificate < now) { v3_authority_check_key_expiry(); #define CHECK_V3_CERTIFICATE_INTERVAL (5*60) time_to_check_v3_certificate = now + CHECK_V3_CERTIFICATE_INTERVAL; } /* 1f. Check whether our networkstatus has expired. */ if (time_to_check_for_expired_networkstatus < now) { networkstatus_t *ns = networkstatus_get_latest_consensus(); /*XXXX RD: This value needs to be the same as REASONABLY_LIVE_TIME in * networkstatus_get_reasonably_live_consensus(), but that value is way * way too high. Arma: is the bridge issue there resolved yet? -NM */ #define NS_EXPIRY_SLOP (24*60*60) if (ns && ns->valid_until < now+NS_EXPIRY_SLOP && router_have_minimum_dir_info()) { router_dir_info_changed(); } #define CHECK_EXPIRED_NS_INTERVAL (2*60) time_to_check_for_expired_networkstatus = now + CHECK_EXPIRED_NS_INTERVAL; } /* 1g. Check whether we should write statistics to disk. */ if (time_to_write_stats_files < now) { #define CHECK_WRITE_STATS_INTERVAL (60*60) time_t next_time_to_write_stats_files = (time_to_write_stats_files > 0 ? time_to_write_stats_files : now) + CHECK_WRITE_STATS_INTERVAL; if (options->CellStatistics) { time_t next_write = rep_hist_buffer_stats_write(time_to_write_stats_files); if (next_write && next_write < next_time_to_write_stats_files) next_time_to_write_stats_files = next_write; } if (options->DirReqStatistics) { time_t next_write = geoip_dirreq_stats_write(time_to_write_stats_files); if (next_write && next_write < next_time_to_write_stats_files) next_time_to_write_stats_files = next_write; } if (options->EntryStatistics) { time_t next_write = geoip_entry_stats_write(time_to_write_stats_files); if (next_write && next_write < next_time_to_write_stats_files) next_time_to_write_stats_files = next_write; } if (options->ExitPortStatistics) { time_t next_write = rep_hist_exit_stats_write(time_to_write_stats_files); if (next_write && next_write < next_time_to_write_stats_files) next_time_to_write_stats_files = next_write; } if (options->ConnDirectionStatistics) { time_t next_write = rep_hist_conn_stats_write(time_to_write_stats_files); if (next_write && next_write < next_time_to_write_stats_files) next_time_to_write_stats_files = next_write; } if (options->BridgeAuthoritativeDir) { time_t next_write = rep_hist_desc_stats_write(time_to_write_stats_files); if (next_write && next_write < next_time_to_write_stats_files) next_time_to_write_stats_files = next_write; } time_to_write_stats_files = next_time_to_write_stats_files; /* Also commandeer this opportunity to log how our circuit handshake * stats have been doing. */ if (public_server_mode(options)) rep_hist_log_circuit_handshake_stats(now); } /* 1h. Check whether we should write bridge statistics to disk. */ if (should_record_bridge_info(options)) { if (time_to_write_bridge_stats < now) { if (should_init_bridge_stats) { /* (Re-)initialize bridge statistics. */ geoip_bridge_stats_init(now); time_to_write_bridge_stats = now + WRITE_STATS_INTERVAL; should_init_bridge_stats = 0; } else { /* Possibly write bridge statistics to disk and ask when to write * them next time. */ time_to_write_bridge_stats = geoip_bridge_stats_write( time_to_write_bridge_stats); } } } else if (!should_init_bridge_stats) { /* Bridge mode was turned off. Ensure that stats are re-initialized * next time bridge mode is turned on. */ should_init_bridge_stats = 1; } /* Remove old information from rephist and the rend cache. */ if (time_to_clean_caches < now) { rep_history_clean(now - options->RephistTrackTime); rend_cache_clean(now); rend_cache_clean_v2_descs_as_dir(now); microdesc_cache_rebuild(NULL, 0); #define CLEAN_CACHES_INTERVAL (30*60) time_to_clean_caches = now + CLEAN_CACHES_INTERVAL; } #define RETRY_DNS_INTERVAL (10*60) /* If we're a server and initializing dns failed, retry periodically. */ if (time_to_retry_dns_init < now) { time_to_retry_dns_init = now + RETRY_DNS_INTERVAL; if (is_server && has_dns_init_failed()) dns_init(); } /** 2. Periodically, we consider force-uploading our descriptor * (if we've passed our internal checks). */ /** How often do we check whether part of our router info has changed in a * way that would require an upload? That includes checking whether our IP * address has changed. */ #define CHECK_DESCRIPTOR_INTERVAL (60) /* 2b. Once per minute, regenerate and upload the descriptor if the old * one is inaccurate. */ if (time_to_check_descriptor < now && !options->DisableNetwork) { static int dirport_reachability_count = 0; time_to_check_descriptor = now + CHECK_DESCRIPTOR_INTERVAL; check_descriptor_bandwidth_changed(now); check_descriptor_ipaddress_changed(now); mark_my_descriptor_dirty_if_too_old(now); consider_publishable_server(0); /* also, check religiously for reachability, if it's within the first * 20 minutes of our uptime. */ if (is_server && (can_complete_circuit || !any_predicted_circuits(now)) && !we_are_hibernating()) { if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { consider_testing_reachability(1, dirport_reachability_count==0); if (++dirport_reachability_count > 5) dirport_reachability_count = 0; } else if (time_to_recheck_bandwidth < now) { /* If we haven't checked for 12 hours and our bandwidth estimate is * low, do another bandwidth test. This is especially important for * bridges, since they might go long periods without much use. */ const routerinfo_t *me = router_get_my_routerinfo(); if (time_to_recheck_bandwidth && me && me->bandwidthcapacity < me->bandwidthrate && me->bandwidthcapacity < 51200) { reset_bandwidth_test(); } #define BANDWIDTH_RECHECK_INTERVAL (12*60*60) time_to_recheck_bandwidth = now + BANDWIDTH_RECHECK_INTERVAL; } } /* If any networkstatus documents are no longer recent, we need to * update all the descriptors' running status. */ /* purge obsolete entries */ networkstatus_v2_list_clean(now); /* Remove dead routers. */ routerlist_remove_old_routers(); /* Also, once per minute, check whether we want to download any * networkstatus documents. */ update_networkstatus_downloads(now); } /** 2c. Let directory voting happen. */ if (authdir_mode_v3(options)) dirvote_act(options, now); /** 3a. Every second, we examine pending circuits and prune the * ones which have been pending for more than a few seconds. * We do this before step 4, so it can try building more if * it's not comfortable with the number of available circuits. */ /* (If our circuit build timeout can ever become lower than a second (which * it can't, currently), we should do this more often.) */ circuit_expire_building(); /** 3b. Also look at pending streams and prune the ones that 'began' * a long time ago but haven't gotten a 'connected' yet. * Do this before step 4, so we can put them back into pending * state to be picked up by the new circuit. */ connection_ap_expire_beginning(); /** 3c. And expire connections that we've held open for too long. */ connection_expire_held_open(); /** 3d. And every 60 seconds, we relaunch listeners if any died. */ if (!net_is_disabled() && time_to_check_listeners < now) { retry_all_listeners(NULL, NULL, 0); time_to_check_listeners = now+60; } /** 4. Every second, we try a new circuit if there are no valid * circuits. Every NewCircuitPeriod seconds, we expire circuits * that became dirty more than MaxCircuitDirtiness seconds ago, * and we make a new circ if there are no clean circuits. */ have_dir_info = router_have_minimum_dir_info(); if (have_dir_info && !net_is_disabled()) circuit_build_needed_circs(now); /* every 10 seconds, but not at the same second as other such events */ if (now % 10 == 5) circuit_expire_old_circuits_serverside(now); /** 5. We do housekeeping for each connection... */ connection_or_set_bad_connections(NULL, 0); for (i=0;ioutbuf) buf_shrink(conn->outbuf); if (conn->inbuf) buf_shrink(conn->inbuf); }); clean_cell_pool(); buf_shrink_freelists(0); /** How often do we check buffers and pools for empty space that can be * deallocated? */ #define MEM_SHRINK_INTERVAL (60) time_to_shrink_memory = now + MEM_SHRINK_INTERVAL; } /** 6. And remove any marked circuits... */ circuit_close_all_marked(); /** 7. And upload service descriptors if necessary. */ if (can_complete_circuit && !net_is_disabled()) { rend_consider_services_upload(now); rend_consider_descriptor_republication(); } /** 8. and blow away any connections that need to die. have to do this now, * because if we marked a conn for close and left its socket -1, then * we'll pass it to poll/select and bad things will happen. */ close_closeable_connections(); /** 8b. And if anything in our state is ready to get flushed to disk, we * flush it. */ or_state_save(now); /** 8c. Do channel cleanup just like for connections */ channel_run_cleanup(); channel_listener_run_cleanup(); /** 9. and if we're a server, check whether our DNS is telling stories to * us. */ if (!net_is_disabled() && public_server_mode(options) && time_to_check_for_correct_dns < now) { if (!time_to_check_for_correct_dns) { time_to_check_for_correct_dns = now + 60 + crypto_rand_int(120); } else { dns_launch_correctness_checks(); time_to_check_for_correct_dns = now + 12*3600 + crypto_rand_int(12*3600); } } /** 10. write bridge networkstatus file to disk */ if (options->BridgeAuthoritativeDir && time_to_write_bridge_status_file < now) { networkstatus_dump_bridge_status_to_file(now); #define BRIDGE_STATUSFILE_INTERVAL (30*60) time_to_write_bridge_status_file = now+BRIDGE_STATUSFILE_INTERVAL; } /** 11. check the port forwarding app */ if (!net_is_disabled() && time_to_check_port_forwarding < now && options->PortForwarding && is_server) { #define PORT_FORWARDING_CHECK_INTERVAL 5 smartlist_t *ports_to_forward = get_list_of_ports_to_forward(); if (ports_to_forward) { tor_check_port_forwarding(options->PortForwardingHelper, ports_to_forward, now); SMARTLIST_FOREACH(ports_to_forward, char *, cp, tor_free(cp)); smartlist_free(ports_to_forward); } time_to_check_port_forwarding = now+PORT_FORWARDING_CHECK_INTERVAL; } /** 11b. check pending unconfigured managed proxies */ if (!net_is_disabled() && pt_proxies_configuration_pending()) pt_configure_remaining_proxies(); /** 12. write the heartbeat message */ if (options->HeartbeatPeriod && time_to_next_heartbeat <= now) { if (time_to_next_heartbeat) /* don't log the first heartbeat */ log_heartbeat(now); time_to_next_heartbeat = now+options->HeartbeatPeriod; } } /** Timer: used to invoke second_elapsed_callback() once per second. */ static periodic_timer_t *second_timer = NULL; /** Number of libevent errors in the last second: we die if we get too many. */ static int n_libevent_errors = 0; /** Libevent callback: invoked once every second. */ static void second_elapsed_callback(periodic_timer_t *timer, void *arg) { /* XXXX This could be sensibly refactored into multiple callbacks, and we * could use Libevent's timers for this rather than checking the current * time against a bunch of timeouts every second. */ static time_t current_second = 0; time_t now; size_t bytes_written; size_t bytes_read; int seconds_elapsed; const or_options_t *options = get_options(); (void)timer; (void)arg; n_libevent_errors = 0; /* log_notice(LD_GENERAL, "Tick."); */ now = time(NULL); update_approx_time(now); /* the second has rolled over. check more stuff. */ seconds_elapsed = current_second ? (int)(now - current_second) : 0; #ifdef USE_BUFFEREVENTS { uint64_t cur_read,cur_written; connection_get_rate_limit_totals(&cur_read, &cur_written); bytes_written = (size_t)(cur_written - stats_prev_n_written); bytes_read = (size_t)(cur_read - stats_prev_n_read); stats_n_bytes_read += bytes_read; stats_n_bytes_written += bytes_written; if (accounting_is_enabled(options) && seconds_elapsed >= 0) accounting_add_bytes(bytes_read, bytes_written, seconds_elapsed); stats_prev_n_written = cur_written; stats_prev_n_read = cur_read; } #else bytes_read = (size_t)(stats_n_bytes_read - stats_prev_n_read); bytes_written = (size_t)(stats_n_bytes_written - stats_prev_n_written); stats_prev_n_read = stats_n_bytes_read; stats_prev_n_written = stats_n_bytes_written; #endif control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written); control_event_stream_bandwidth_used(); if (server_mode(options) && !net_is_disabled() && seconds_elapsed > 0 && can_complete_circuit && stats_n_seconds_working / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT != (stats_n_seconds_working+seconds_elapsed) / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { /* every 20 minutes, check and complain if necessary */ const routerinfo_t *me = router_get_my_routerinfo(); if (me && !check_whether_orport_reachable()) { log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that " "its ORPort is reachable. Please check your firewalls, ports, " "address, /etc/hosts file, etc.", me->address, me->or_port); control_event_server_status(LOG_WARN, "REACHABILITY_FAILED ORADDRESS=%s:%d", me->address, me->or_port); } if (me && !check_whether_dirport_reachable()) { log_warn(LD_CONFIG, "Your server (%s:%d) has not managed to confirm that its " "DirPort is reachable. Please check your firewalls, ports, " "address, /etc/hosts file, etc.", me->address, me->dir_port); control_event_server_status(LOG_WARN, "REACHABILITY_FAILED DIRADDRESS=%s:%d", me->address, me->dir_port); } } /** If more than this many seconds have elapsed, probably the clock * jumped: doesn't count. */ #define NUM_JUMPED_SECONDS_BEFORE_WARN 100 if (seconds_elapsed < -NUM_JUMPED_SECONDS_BEFORE_WARN || seconds_elapsed >= NUM_JUMPED_SECONDS_BEFORE_WARN) { circuit_note_clock_jumped(seconds_elapsed); /* XXX if the time jumps *back* many months, do our events in * run_scheduled_events() recover? I don't think they do. -RD */ } else if (seconds_elapsed > 0) stats_n_seconds_working += seconds_elapsed; run_scheduled_events(now); current_second = now; /* remember which second it is, for next time */ } #ifndef USE_BUFFEREVENTS /** Timer: used to invoke refill_callback(). */ static periodic_timer_t *refill_timer = NULL; /** Libevent callback: invoked periodically to refill token buckets * and count r/w bytes. It is only used when bufferevents are disabled. */ static void refill_callback(periodic_timer_t *timer, void *arg) { static struct timeval current_millisecond; struct timeval now; size_t bytes_written; size_t bytes_read; int milliseconds_elapsed = 0; int seconds_rolled_over = 0; const or_options_t *options = get_options(); (void)timer; (void)arg; tor_gettimeofday(&now); /* If this is our first time, no time has passed. */ if (current_millisecond.tv_sec) { long mdiff = tv_mdiff(¤t_millisecond, &now); if (mdiff > INT_MAX) mdiff = INT_MAX; milliseconds_elapsed = (int)mdiff; seconds_rolled_over = (int)(now.tv_sec - current_millisecond.tv_sec); } bytes_written = stats_prev_global_write_bucket - global_write_bucket; bytes_read = stats_prev_global_read_bucket - global_read_bucket; stats_n_bytes_read += bytes_read; stats_n_bytes_written += bytes_written; if (accounting_is_enabled(options) && milliseconds_elapsed >= 0) accounting_add_bytes(bytes_read, bytes_written, seconds_rolled_over); if (milliseconds_elapsed > 0) connection_bucket_refill(milliseconds_elapsed, now.tv_sec); stats_prev_global_read_bucket = global_read_bucket; stats_prev_global_write_bucket = global_write_bucket; current_millisecond = now; /* remember what time it is, for next time */ } #endif #ifndef _WIN32 /** Called when a possibly ignorable libevent error occurs; ensures that we * don't get into an infinite loop by ignoring too many errors from * libevent. */ static int got_libevent_error(void) { if (++n_libevent_errors > 8) { log_err(LD_NET, "Too many libevent errors in one second; dying"); return -1; } return 0; } #endif #define UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST (6*60*60) /** Called when our IP address seems to have changed. at_interface * should be true if we detected a change in our interface, and false if we * detected a change in our published address. */ void ip_address_changed(int at_interface) { int server = server_mode(get_options()); if (at_interface) { if (! server) { /* Okay, change our keys. */ if (init_keys()<0) log_warn(LD_GENERAL, "Unable to rotate keys after IP change!"); } } else { if (server) { if (stats_n_seconds_working > UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST) reset_bandwidth_test(); stats_n_seconds_working = 0; router_reset_reachability(); mark_my_descriptor_dirty("IP address changed"); } } dns_servers_relaunch_checks(); } /** Forget what we've learned about the correctness of our DNS servers, and * start learning again. */ void dns_servers_relaunch_checks(void) { if (server_mode(get_options())) { dns_reset_correctness_checks(); time_to_check_for_correct_dns = 0; } } /** Called when we get a SIGHUP: reload configuration files and keys, * retry all connections, and so on. */ static int do_hup(void) { const or_options_t *options = get_options(); #ifdef USE_DMALLOC dmalloc_log_stats(); dmalloc_log_changed(0, 1, 0, 0); #endif log_notice(LD_GENERAL,"Received reload signal (hup). Reloading config and " "resetting internal state."); if (accounting_is_enabled(options)) accounting_record_bandwidth_usage(time(NULL), get_or_state()); router_reset_warnings(); routerlist_reset_warnings(); /* first, reload config variables, in case they've changed */ if (options->ReloadTorrcOnSIGHUP) { /* no need to provide argc/v, they've been cached in init_from_config */ if (options_init_from_torrc(0, NULL) < 0) { log_err(LD_CONFIG,"Reading config failed--see warnings above. " "For usage, try -h."); return -1; } options = get_options(); /* they have changed now */ } else { char *msg = NULL; log_notice(LD_GENERAL, "Not reloading config file: the controller told " "us not to."); /* Make stuff get rescanned, reloaded, etc. */ if (set_options((or_options_t*)options, &msg) < 0) { if (!msg) msg = tor_strdup("Unknown error"); log_warn(LD_GENERAL, "Unable to re-set previous options: %s", msg); tor_free(msg); } } if (authdir_mode_handles_descs(options, -1)) { /* reload the approved-routers file */ if (dirserv_load_fingerprint_file() < 0) { /* warnings are logged from dirserv_load_fingerprint_file() directly */ log_info(LD_GENERAL, "Error reloading fingerprints. " "Continuing with old list."); } } /* Rotate away from the old dirty circuits. This has to be done * after we've read the new options, but before we start using * circuits for directory fetches. */ circuit_mark_all_dirty_circs_as_unusable(); /* retry appropriate downloads */ router_reset_status_download_failures(); router_reset_descriptor_download_failures(); if (!options->DisableNetwork) update_networkstatus_downloads(time(NULL)); /* We'll retry routerstatus downloads in about 10 seconds; no need to * force a retry there. */ if (server_mode(options)) { /* Restart cpuworker and dnsworker processes, so they get up-to-date * configuration options. */ cpuworkers_rotate(); dns_reset(); } return 0; } /** Tor main loop. */ /* static */ int do_main_loop(void) { int loop_result; time_t now; /* initialize dns resolve map, spawn workers if needed */ if (dns_init() < 0) { if (get_options()->ServerDNSAllowBrokenConfig) log_warn(LD_GENERAL, "Couldn't set up any working nameservers. " "Network not up yet? Will try again soon."); else { log_err(LD_GENERAL,"Error initializing dns subsystem; exiting. To " "retry instead, set the ServerDNSAllowBrokenResolvConf option."); } } #ifdef USE_BUFFEREVENTS log_warn(LD_GENERAL, "Tor was compiled with the --enable-bufferevents " "option. This is still experimental, and might cause strange " "bugs. If you want a more stable Tor, be sure to build without " "--enable-bufferevents."); #endif handle_signals(1); /* load the private keys, if we're supposed to have them, and set up the * TLS context. */ if (! client_identity_key_is_set()) { if (init_keys() < 0) { log_err(LD_BUG,"Error initializing keys; exiting"); return -1; } } /* Set up the packed_cell_t memory pool. */ init_cell_pool(); /* Set up our buckets */ connection_bucket_init(); #ifndef USE_BUFFEREVENTS stats_prev_global_read_bucket = global_read_bucket; stats_prev_global_write_bucket = global_write_bucket; #endif /* initialize the bootstrap status events to know we're starting up */ control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0); if (trusted_dirs_reload_certs()) { log_warn(LD_DIR, "Couldn't load all cached v3 certificates. Starting anyway."); } if (router_reload_v2_networkstatus()) { return -1; } if (router_reload_consensus_networkstatus()) { return -1; } /* load the routers file, or assign the defaults. */ if (router_reload_router_list()) { return -1; } /* load the networkstatuses. (This launches a download for new routers as * appropriate.) */ now = time(NULL); directory_info_has_arrived(now, 1); if (server_mode(get_options())) { /* launch cpuworkers. Need to do this *after* we've read the onion key. */ cpu_init(); } /* set up once-a-second callback. */ if (! second_timer) { struct timeval one_second; one_second.tv_sec = 1; one_second.tv_usec = 0; second_timer = periodic_timer_new(tor_libevent_get_base(), &one_second, second_elapsed_callback, NULL); tor_assert(second_timer); } #ifndef USE_BUFFEREVENTS if (!refill_timer) { struct timeval refill_interval; int msecs = get_options()->TokenBucketRefillInterval; refill_interval.tv_sec = msecs/1000; refill_interval.tv_usec = (msecs%1000)*1000; refill_timer = periodic_timer_new(tor_libevent_get_base(), &refill_interval, refill_callback, NULL); tor_assert(refill_timer); } #endif for (;;) { if (nt_service_is_stopping()) return 0; #ifndef _WIN32 /* Make it easier to tell whether libevent failure is our fault or not. */ errno = 0; #endif /* All active linked conns should get their read events activated. */ SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn, event_active(conn->read_event, EV_READ, 1)); called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0; update_approx_time(time(NULL)); /* poll until we have an event, or the second ends, or until we have * some active linked connections to trigger events for. */ loop_result = event_base_loop(tor_libevent_get_base(), called_loop_once ? EVLOOP_ONCE : 0); /* let catch() handle things like ^c, and otherwise don't worry about it */ if (loop_result < 0) { int e = tor_socket_errno(-1); /* let the program survive things like ^z */ if (e != EINTR && !ERRNO_IS_EINPROGRESS(e)) { log_err(LD_NET,"libevent call with %s failed: %s [%d]", tor_libevent_get_method(), tor_socket_strerror(e), e); return -1; #ifndef _WIN32 } else if (e == EINVAL) { log_warn(LD_NET, "EINVAL from libevent: should you upgrade libevent?"); if (got_libevent_error()) return -1; #endif } else { if (ERRNO_IS_EINPROGRESS(e)) log_warn(LD_BUG, "libevent call returned EINPROGRESS? Please report."); log_debug(LD_NET,"libevent call interrupted."); /* You can't trust the results of this poll(). Go back to the * top of the big for loop. */ continue; } } } } #ifndef _WIN32 /* Only called when we're willing to use signals */ /** Libevent callback: invoked when we get a signal. */ static void signal_callback(int fd, short events, void *arg) { uintptr_t sig = (uintptr_t)arg; (void)fd; (void)events; process_signal(sig); } #endif /** Do the work of acting on a signal received in sig */ void process_signal(uintptr_t sig) { switch (sig) { case SIGTERM: log_notice(LD_GENERAL,"Catching signal TERM, exiting cleanly."); tor_cleanup(); exit(0); break; case SIGINT: if (!server_mode(get_options())) { /* do it now */ log_notice(LD_GENERAL,"Interrupt: exiting cleanly."); tor_cleanup(); exit(0); } hibernate_begin_shutdown(); break; #ifdef SIGPIPE case SIGPIPE: log_debug(LD_GENERAL,"Caught SIGPIPE. Ignoring."); break; #endif case SIGUSR1: /* prefer to log it at INFO, but make sure we always see it */ dumpstats(get_min_log_level() 0) ; /* keep reaping until no more zombies */ break; #endif case SIGNEWNYM: { time_t now = time(NULL); if (time_of_last_signewnym + MAX_SIGNEWNYM_RATE > now) { signewnym_is_pending = 1; log_notice(LD_CONTROL, "Rate limiting NEWNYM request: delaying by %d second(s)", (int)(MAX_SIGNEWNYM_RATE+time_of_last_signewnym-now)); } else { signewnym_impl(now); } break; } case SIGCLEARDNSCACHE: addressmap_clear_transient(); control_event_signal(sig); break; } } /** Returns Tor's uptime. */ long get_uptime(void) { return stats_n_seconds_working; } extern uint64_t rephist_total_alloc; extern uint32_t rephist_total_num; /** * Write current memory usage information to the log. */ static void dumpmemusage(int severity) { connection_dump_buffer_mem_stats(severity); tor_log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.", U64_PRINTF_ARG(rephist_total_alloc), rephist_total_num); dump_routerlist_mem_usage(severity); dump_cell_pool_usage(severity); dump_dns_mem_usage(severity); buf_dump_freelist_sizes(severity); tor_log_mallinfo(severity); } /** Write all statistics to the log, with log level severity. Called * in response to a SIGUSR1. */ static void dumpstats(int severity) { time_t now = time(NULL); time_t elapsed; size_t rbuf_cap, wbuf_cap, rbuf_len, wbuf_len; tor_log(severity, LD_GENERAL, "Dumping stats:"); SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) { int i = conn_sl_idx; tor_log(severity, LD_GENERAL, "Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago", i, (int)conn->s, conn->type, conn_type_to_string(conn->type), conn->state, conn_state_to_string(conn->type, conn->state), (int)(now - conn->timestamp_created)); if (!connection_is_listener(conn)) { tor_log(severity,LD_GENERAL, "Conn %d is to %s:%d.", i, safe_str_client(conn->address), conn->port); tor_log(severity,LD_GENERAL, "Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)", i, (int)connection_get_inbuf_len(conn), (int)buf_allocation(conn->inbuf), (int)(now - conn->timestamp_lastread)); tor_log(severity,LD_GENERAL, "Conn %d: %d bytes waiting on outbuf " "(len %d, last written %d secs ago)",i, (int)connection_get_outbuf_len(conn), (int)buf_allocation(conn->outbuf), (int)(now - conn->timestamp_lastwritten)); if (conn->type == CONN_TYPE_OR) { or_connection_t *or_conn = TO_OR_CONN(conn); if (or_conn->tls) { tor_tls_get_buffer_sizes(or_conn->tls, &rbuf_cap, &rbuf_len, &wbuf_cap, &wbuf_len); tor_log(severity, LD_GENERAL, "Conn %d: %d/%d bytes used on OpenSSL read buffer; " "%d/%d bytes used on write buffer.", i, (int)rbuf_len, (int)rbuf_cap, (int)wbuf_len, (int)wbuf_cap); } } } circuit_dump_by_conn(conn, severity); /* dump info about all the circuits * using this conn */ } SMARTLIST_FOREACH_END(conn); channel_dumpstats(severity); channel_listener_dumpstats(severity); tor_log(severity, LD_NET, "Cells processed: "U64_FORMAT" padding\n" " "U64_FORMAT" create\n" " "U64_FORMAT" created\n" " "U64_FORMAT" relay\n" " ("U64_FORMAT" relayed)\n" " ("U64_FORMAT" delivered)\n" " "U64_FORMAT" destroy", U64_PRINTF_ARG(stats_n_padding_cells_processed), U64_PRINTF_ARG(stats_n_create_cells_processed), U64_PRINTF_ARG(stats_n_created_cells_processed), U64_PRINTF_ARG(stats_n_relay_cells_processed), U64_PRINTF_ARG(stats_n_relay_cells_relayed), U64_PRINTF_ARG(stats_n_relay_cells_delivered), U64_PRINTF_ARG(stats_n_destroy_cells_processed)); if (stats_n_data_cells_packaged) tor_log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%", 100*(U64_TO_DBL(stats_n_data_bytes_packaged) / U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); if (stats_n_data_cells_received) tor_log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%", 100*(U64_TO_DBL(stats_n_data_bytes_received) / U64_TO_DBL(stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) ); cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_TAP, "TAP"); cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_NTOR,"ntor"); if (now - time_of_process_start >= 0) elapsed = now - time_of_process_start; else elapsed = 0; if (elapsed) { tor_log(severity, LD_NET, "Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec reading", U64_PRINTF_ARG(stats_n_bytes_read), (int)elapsed, (int) (stats_n_bytes_read/elapsed)); tor_log(severity, LD_NET, "Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec writing", U64_PRINTF_ARG(stats_n_bytes_written), (int)elapsed, (int) (stats_n_bytes_written/elapsed)); } tor_log(severity, LD_NET, "--------------- Dumping memory information:"); dumpmemusage(severity); rep_hist_dump_stats(now,severity); rend_service_dump_stats(severity); dump_pk_ops(severity); dump_distinct_digest_count(severity); } /** Called by exit() as we shut down the process. */ static void exit_function(void) { /* NOTE: If we ever daemonize, this gets called immediately. That's * okay for now, because we only use this on Windows. */ #ifdef _WIN32 WSACleanup(); #endif } /** Set up the signal handlers for either parent or child. */ void handle_signals(int is_parent) { #ifndef _WIN32 /* do signal stuff only on Unix */ int i; static const int signals[] = { SIGINT, /* do a controlled slow shutdown */ SIGTERM, /* to terminate now */ SIGPIPE, /* otherwise SIGPIPE kills us */ SIGUSR1, /* dump stats */ SIGUSR2, /* go to loglevel debug */ SIGHUP, /* to reload config, retry conns, etc */ #ifdef SIGXFSZ SIGXFSZ, /* handle file-too-big resource exhaustion */ #endif SIGCHLD, /* handle dns/cpu workers that exit */ -1 }; static struct event *signal_events[16]; /* bigger than it has to be. */ if (is_parent) { for (i = 0; signals[i] >= 0; ++i) { signal_events[i] = tor_evsignal_new( tor_libevent_get_base(), signals[i], signal_callback, (void*)(uintptr_t)signals[i]); if (event_add(signal_events[i], NULL)) log_warn(LD_BUG, "Error from libevent when adding event for signal %d", signals[i]); } } else { struct sigaction action; action.sa_flags = 0; sigemptyset(&action.sa_mask); action.sa_handler = SIG_IGN; sigaction(SIGINT, &action, NULL); sigaction(SIGTERM, &action, NULL); sigaction(SIGPIPE, &action, NULL); sigaction(SIGUSR1, &action, NULL); sigaction(SIGUSR2, &action, NULL); sigaction(SIGHUP, &action, NULL); #ifdef SIGXFSZ sigaction(SIGXFSZ, &action, NULL); #endif } #else /* MS windows */ (void)is_parent; #endif /* signal stuff */ } /** Main entry point for the Tor command-line client. */ /* static */ int tor_init(int argc, char *argv[]) { char buf[256]; int i, quiet = 0; time_of_process_start = time(NULL); if (!connection_array) connection_array = smartlist_new(); if (!closeable_connection_lst) closeable_connection_lst = smartlist_new(); if (!active_linked_connection_lst) active_linked_connection_lst = smartlist_new(); /* Have the log set up with our application name. */ tor_snprintf(buf, sizeof(buf), "Tor %s", get_version()); log_set_application_name(buf); /* Initialize the history structures. */ rep_hist_init(); /* Initialize the service cache. */ rend_cache_init(); addressmap_init(); /* Init the client dns cache. Do it always, since it's * cheap. */ /* We search for the "quiet" option first, since it decides whether we * will log anything at all to the command line. */ for (i=1;iHardwareAccel, get_options()->AccelName, get_options()->AccelDir)) { log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } stream_choice_seed_weak_rng(); return 0; } /** A lockfile structure, used to prevent two Tors from messing with the * data directory at once. If this variable is non-NULL, we're holding * the lockfile. */ static tor_lockfile_t *lockfile = NULL; /** Try to grab the lock file described in options, if we do not * already have it. If err_if_locked is true, warn if somebody else is * holding the lock, and exit if we can't get it after waiting. Otherwise, * return -1 if we can't get the lockfile. Return 0 on success. */ int try_locking(const or_options_t *options, int err_if_locked) { if (lockfile) return 0; else { char *fname = options_get_datadir_fname2_suffix(options, "lock",NULL,NULL); int already_locked = 0; tor_lockfile_t *lf = tor_lockfile_lock(fname, 0, &already_locked); tor_free(fname); if (!lf) { if (err_if_locked && already_locked) { int r; log_warn(LD_GENERAL, "It looks like another Tor process is running " "with the same data directory. Waiting 5 seconds to see " "if it goes away."); #ifndef _WIN32 sleep(5); #else Sleep(5000); #endif r = try_locking(options, 0); if (r<0) { log_err(LD_GENERAL, "No, it's still there. Exiting."); exit(0); } return r; } return -1; } lockfile = lf; return 0; } } /** Return true iff we've successfully acquired the lock file. */ int have_lockfile(void) { return lockfile != NULL; } /** If we have successfully acquired the lock file, release it. */ void release_lockfile(void) { if (lockfile) { tor_lockfile_unlock(lockfile); lockfile = NULL; } } /** Free all memory that we might have allocated somewhere. * If postfork, we are a worker process and we want to free * only the parts of memory that we won't touch. If !postfork, * Tor is shutting down and we should free everything. * * Helps us find the real leaks with dmalloc and the like. Also valgrind * should then report 0 reachable in its leak report (in an ideal world -- * in practice libevent, SSL, libc etc never quite free everything). */ void tor_free_all(int postfork) { if (!postfork) { evdns_shutdown(1); } geoip_free_all(); dirvote_free_all(); routerlist_free_all(); networkstatus_free_all(); addressmap_free_all(); dirserv_free_all(); rend_service_free_all(); rend_cache_free_all(); rend_service_authorization_free_all(); rep_hist_free_all(); dns_free_all(); clear_pending_onions(); circuit_free_all(); entry_guards_free_all(); pt_free_all(); channel_tls_free_all(); channel_free_all(); connection_free_all(); buf_shrink_freelists(1); memarea_clear_freelist(); nodelist_free_all(); microdesc_free_all(); if (!postfork) { config_free_all(); or_state_free_all(); router_free_all(); policies_free_all(); } free_cell_pool(); if (!postfork) { tor_tls_free_all(); } /* stuff in main.c */ smartlist_free(connection_array); smartlist_free(closeable_connection_lst); smartlist_free(active_linked_connection_lst); periodic_timer_free(second_timer); #ifndef USE_BUFFEREVENTS periodic_timer_free(refill_timer); #endif if (!postfork) { release_lockfile(); } /* Stuff in util.c and address.c*/ if (!postfork) { escaped(NULL); esc_router_info(NULL); logs_free_all(); /* free log strings. do this last so logs keep working. */ } } /** Do whatever cleanup is necessary before shutting Tor down. */ void tor_cleanup(void) { const or_options_t *options = get_options(); if (options->command == CMD_RUN_TOR) { time_t now = time(NULL); /* Remove our pid file. We don't care if there was an error when we * unlink, nothing we could do about it anyways. */ if (options->PidFile) unlink(options->PidFile); if (options->ControlPortWriteToFile) unlink(options->ControlPortWriteToFile); if (accounting_is_enabled(options)) accounting_record_bandwidth_usage(now, get_or_state()); or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */ or_state_save(now); if (authdir_mode_tests_reachability(options)) rep_hist_record_mtbf_data(now, 0); } #ifdef USE_DMALLOC dmalloc_log_stats(); #endif tor_free_all(0); /* We could move tor_free_all back into the ifdef below later, if it makes shutdown unacceptably slow. But for now, leave it here: it's helped us catch bugs in the past. */ crypto_global_cleanup(); #ifdef USE_DMALLOC dmalloc_log_unfreed(); dmalloc_shutdown(); #endif } /** Read/create keys as needed, and echo our fingerprint to stdout. */ /* static */ int do_list_fingerprint(void) { char buf[FINGERPRINT_LEN+1]; crypto_pk_t *k; const char *nickname = get_options()->Nickname; if (!server_mode(get_options())) { log_err(LD_GENERAL, "Clients don't have long-term identity keys. Exiting.\n"); return -1; } tor_assert(nickname); if (init_keys() < 0) { log_err(LD_BUG,"Error initializing keys; can't display fingerprint"); return -1; } if (!(k = get_server_identity_key())) { log_err(LD_GENERAL,"Error: missing identity key."); return -1; } if (crypto_pk_get_fingerprint(k, buf, 1)<0) { log_err(LD_BUG, "Error computing fingerprint"); return -1; } printf("%s %s\n", nickname, buf); return 0; } /** Entry point for password hashing: take the desired password from * the command line, and print its salted hash to stdout. **/ /* static */ void do_hash_password(void) { char output[256]; char key[S2K_SPECIFIER_LEN+DIGEST_LEN]; crypto_rand(key, S2K_SPECIFIER_LEN-1); key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */ secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN, get_options()->command_arg, strlen(get_options()->command_arg), key); base16_encode(output, sizeof(output), key, sizeof(key)); printf("16:%s\n",output); } #if defined (WINCE) int find_flashcard_path(PWCHAR path, size_t size) { WIN32_FIND_DATA d = {0}; HANDLE h = NULL; if (!path) return -1; h = FindFirstFlashCard(&d); if (h == INVALID_HANDLE_VALUE) return -1; if (wcslen(d.cFileName) == 0) { FindClose(h); return -1; } wcsncpy(path,d.cFileName,size); FindClose(h); return 0; } #endif /** Main entry point for the Tor process. Called from main(). */ /* This function is distinct from main() only so we can link main.c into * the unittest binary without conflicting with the unittests' main. */ int tor_main(int argc, char *argv[]) { int result = 0; #if defined (WINCE) WCHAR path [MAX_PATH] = {0}; WCHAR fullpath [MAX_PATH] = {0}; PWCHAR p = NULL; FILE* redir = NULL; FILE* redirdbg = NULL; // this is to facilitate debugging by opening // a file on a folder shared by the wm emulator. // if no flashcard (real or emulated) is present, // log files will be written in the root folder if (find_flashcard_path(path,MAX_PATH) == -1) { redir = _wfreopen( L"\\stdout.log", L"w", stdout ); redirdbg = _wfreopen( L"\\stderr.log", L"w", stderr ); } else { swprintf(fullpath,L"\\%s\\tor",path); CreateDirectory(fullpath,NULL); swprintf(fullpath,L"\\%s\\tor\\stdout.log",path); redir = _wfreopen( fullpath, L"w", stdout ); swprintf(fullpath,L"\\%s\\tor\\stderr.log",path); redirdbg = _wfreopen( fullpath, L"w", stderr ); } #endif #ifdef _WIN32 /* Call SetProcessDEPPolicy to permanently enable DEP. The function will not resolve on earlier versions of Windows, and failure is not dangerous. */ HMODULE hMod = GetModuleHandleA("Kernel32.dll"); if (hMod) { typedef BOOL (WINAPI *PSETDEP)(DWORD); PSETDEP setdeppolicy = (PSETDEP)GetProcAddress(hMod, "SetProcessDEPPolicy"); if (setdeppolicy) setdeppolicy(1); /* PROCESS_DEP_ENABLE */ } #endif update_approx_time(time(NULL)); tor_threads_init(); init_logging(); #ifdef USE_DMALLOC { /* Instruct OpenSSL to use our internal wrappers for malloc, realloc and free. */ int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_); tor_assert(r); } #endif #ifdef NT_SERVICE { int done = 0; result = nt_service_parse_options(argc, argv, &done); if (done) return result; } #endif if (tor_init(argc, argv)<0) return -1; switch (get_options()->command) { case CMD_RUN_TOR: #ifdef NT_SERVICE nt_service_set_state(SERVICE_RUNNING); #endif result = do_main_loop(); break; case CMD_LIST_FINGERPRINT: result = do_list_fingerprint(); break; case CMD_HASH_PASSWORD: do_hash_password(); result = 0; break; case CMD_VERIFY_CONFIG: printf("Configuration was valid\n"); result = 0; break; case CMD_RUN_UNITTESTS: /* only set by test.c */ default: log_warn(LD_BUG,"Illegal command number %d: internal error.", get_options()->command); result = -1; } tor_cleanup(); return result; } tor-0.2.4.20/src/or/circuitlist.h0000644000175000017500000000604512255745673013425 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file circuitlist.h * \brief Header file for circuitlist.c. **/ #ifndef TOR_CIRCUITLIST_H #define TOR_CIRCUITLIST_H circuit_t * circuit_get_global_list_(void); const char *circuit_state_to_string(int state); const char *circuit_purpose_to_controller_string(uint8_t purpose); const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose); const char *circuit_purpose_to_string(uint8_t purpose); void circuit_dump_by_conn(connection_t *conn, int severity); void circuit_dump_by_chan(channel_t *chan, int severity); void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id, channel_t *chan); void circuit_set_n_circid_chan(circuit_t *circ, circid_t id, channel_t *chan); void circuit_set_state(circuit_t *circ, uint8_t state); void circuit_close_all_marked(void); int32_t circuit_initial_package_window(void); origin_circuit_t *origin_circuit_new(void); or_circuit_t *or_circuit_new(circid_t p_circ_id, channel_t *p_chan); circuit_t *circuit_get_by_circid_channel(circid_t circ_id, channel_t *chan); circuit_t * circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, channel_t *chan); int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan); circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn); void circuit_unlink_all_from_channel(channel_t *chan, int reason); origin_circuit_t *circuit_get_by_global_id(uint32_t id); origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data( const rend_data_t *rend_data); origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, const char *digest, uint8_t purpose); or_circuit_t *circuit_get_rendezvous(const char *cookie); or_circuit_t *circuit_get_intro_point(const char *digest); origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags); void circuit_mark_all_unused_circs(void); void circuit_mark_all_dirty_circs_as_unusable(void); void circuit_mark_for_close_(circuit_t *circ, int reason, int line, const char *file); int circuit_get_cpath_len(origin_circuit_t *circ); crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum); void circuit_get_all_pending_on_channel(smartlist_t *out, channel_t *chan); int circuit_count_pending_on_channel(channel_t *chan); #define circuit_mark_for_close(c, reason) \ circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__) void assert_cpath_layer_ok(const crypt_path_t *cp); void assert_circuit_ok(const circuit_t *c); void circuit_free_all(void); void circuits_handle_oom(size_t current_allocation); #endif tor-0.2.4.20/src/or/routerset.h0000644000175000017500000000400012166112777013102 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file routerlist.h * \brief Header file for routerset.c **/ #ifndef TOR_ROUTERSET_H #define TOR_ROUTERSET_H routerset_t *routerset_new(void); void routerset_refresh_countries(routerset_t *rs); int routerset_parse(routerset_t *target, const char *s, const char *description); void routerset_union(routerset_t *target, const routerset_t *source); int routerset_is_list(const routerset_t *set); int routerset_needs_geoip(const routerset_t *set); int routerset_is_empty(const routerset_t *set); int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri, country_t country); int routerset_contains_routerstatus(const routerset_t *set, const routerstatus_t *rs, country_t country); int routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei); int routerset_contains_node(const routerset_t *set, const node_t *node); void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset, const routerset_t *excludeset, int running_only); int routerset_add_unknown_ccs(routerset_t **setp, int only_if_some_cc_set); #if 0 void routersets_get_node_disjunction(smartlist_t *target, const smartlist_t *source, const routerset_t *include, const routerset_t *exclude, int running_only); #endif void routerset_subtract_nodes(smartlist_t *out, const routerset_t *routerset); char *routerset_to_string(const routerset_t *routerset); int routerset_equal(const routerset_t *old, const routerset_t *new); void routerset_free(routerset_t *routerset); #endif tor-0.2.4.20/src/or/circuitstats.c0000644000175000017500000014070012255745673013600 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITSTATS_PRIVATE #include "or.h" #include "circuitbuild.h" #include "circuitstats.h" #include "config.h" #include "confparse.h" #include "control.h" #include "networkstatus.h" #include "statefile.h" #undef log #include #define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2)) /** Global list of circuit build times */ // XXXX: Add this as a member for entry_guard_t instead of global? // Then we could do per-guard statistics, as guards are likely to // vary in their own latency. The downside of this is that guards // can change frequently, so we'd be building a lot more circuits // most likely. /* XXXX024 Make this static; add accessor functions. */ circuit_build_times_t circ_times; /** If set, we're running the unit tests: we should avoid clobbering * our state file or accessing get_options() or get_or_state() */ static int unit_tests = 0; /** * This function decides if CBT learning should be disabled. It returns * true if one or more of the following four conditions are met: * * 1. If the cbtdisabled consensus parameter is set. * 2. If the torrc option LearnCircuitBuildTimeout is false. * 3. If we are a directory authority * 4. If we fail to write circuit build time history to our state file. */ int circuit_build_times_disabled(void) { if (unit_tests) { return 0; } else { int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled", 0, 0, 1); int config_disabled = !get_options()->LearnCircuitBuildTimeout; int dirauth_disabled = get_options()->AuthoritativeDir; int state_disabled = did_last_state_file_write_fail() ? 1 : 0; if (consensus_disabled || config_disabled || dirauth_disabled || state_disabled) { log_debug(LD_CIRC, "CircuitBuildTime learning is disabled. " "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", consensus_disabled, config_disabled, dirauth_disabled, state_disabled); return 1; } else { log_debug(LD_CIRC, "CircuitBuildTime learning is not disabled. " "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", consensus_disabled, config_disabled, dirauth_disabled, state_disabled); return 0; } } } /** * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter. * * Effect: When this many timeouts happen in the last 'cbtrecentcount' * circuit attempts, the client should discard all of its history and * begin learning a fresh timeout value. */ static int32_t circuit_build_times_max_timeouts(void) { int32_t cbt_maxtimeouts; cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts", CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT, CBT_MIN_MAX_RECENT_TIMEOUT_COUNT, CBT_MAX_MAX_RECENT_TIMEOUT_COUNT); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is" " %d", cbt_maxtimeouts); } return cbt_maxtimeouts; } /** * Retrieve and bounds-check the cbtnummodes consensus paramter. * * Effect: This value governs how many modes to use in the weighted * average calculation of Pareto parameter Xm. A value of 3 introduces * some bias (2-5% of CDF) under ideal conditions, but allows for better * performance in the event that a client chooses guard nodes of radically * different performance characteristics. */ static int32_t circuit_build_times_default_num_xm_modes(void) { int32_t num = networkstatus_get_param(NULL, "cbtnummodes", CBT_DEFAULT_NUM_XM_MODES, CBT_MIN_NUM_XM_MODES, CBT_MAX_NUM_XM_MODES); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_default_num_xm_modes() called, cbtnummodes" " is %d", num); } return num; } /** * Retrieve and bounds-check the cbtmincircs consensus paramter. * * Effect: This is the minimum number of circuits to build before * computing a timeout. */ static int32_t circuit_build_times_min_circs_to_observe(void) { int32_t num = networkstatus_get_param(NULL, "cbtmincircs", CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE, CBT_MIN_MIN_CIRCUITS_TO_OBSERVE, CBT_MAX_MIN_CIRCUITS_TO_OBSERVE); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_min_circs_to_observe() called, cbtmincircs" " is %d", num); } return num; } /** Return true iff cbt has recorded enough build times that we * want to start acting on the timeout it implies. */ int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt) { return cbt->total_build_times >= circuit_build_times_min_circs_to_observe(); } /** * Retrieve and bounds-check the cbtquantile consensus paramter. * * Effect: This is the position on the quantile curve to use to set the * timeout value. It is a percent (10-99). */ double circuit_build_times_quantile_cutoff(void) { int32_t num = networkstatus_get_param(NULL, "cbtquantile", CBT_DEFAULT_QUANTILE_CUTOFF, CBT_MIN_QUANTILE_CUTOFF, CBT_MAX_QUANTILE_CUTOFF); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_quantile_cutoff() called, cbtquantile" " is %d", num); } return num/100.0; } /** * Retrieve and bounds-check the cbtclosequantile consensus paramter. * * Effect: This is the position on the quantile curve to use to set the * timeout value to use to actually close circuits. It is a percent * (0-99). */ static double circuit_build_times_close_quantile(void) { int32_t param; /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */ int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff()); param = networkstatus_get_param(NULL, "cbtclosequantile", CBT_DEFAULT_CLOSE_QUANTILE, CBT_MIN_CLOSE_QUANTILE, CBT_MAX_CLOSE_QUANTILE); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_close_quantile() called, cbtclosequantile" " is %d", param); } if (param < min) { log_warn(LD_DIR, "Consensus parameter cbtclosequantile is " "too small, raising to %d", min); param = min; } return param / 100.0; } /** * Retrieve and bounds-check the cbttestfreq consensus paramter. * * Effect: Describes how often in seconds to build a test circuit to * gather timeout values. Only applies if less than 'cbtmincircs' * have been recorded. */ static int32_t circuit_build_times_test_frequency(void) { int32_t num = networkstatus_get_param(NULL, "cbttestfreq", CBT_DEFAULT_TEST_FREQUENCY, CBT_MIN_TEST_FREQUENCY, CBT_MAX_TEST_FREQUENCY); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_test_frequency() called, cbttestfreq is %d", num); } return num; } /** * Retrieve and bounds-check the cbtmintimeout consensus parameter. * * Effect: This is the minimum allowed timeout value in milliseconds. * The minimum is to prevent rounding to 0 (we only check once * per second). */ static int32_t circuit_build_times_min_timeout(void) { int32_t num = networkstatus_get_param(NULL, "cbtmintimeout", CBT_DEFAULT_TIMEOUT_MIN_VALUE, CBT_MIN_TIMEOUT_MIN_VALUE, CBT_MAX_TIMEOUT_MIN_VALUE); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_min_timeout() called, cbtmintimeout is %d", num); } return num; } /** * Retrieve and bounds-check the cbtinitialtimeout consensus paramter. * * Effect: This is the timeout value to use before computing a timeout, * in milliseconds. */ int32_t circuit_build_times_initial_timeout(void) { int32_t min = circuit_build_times_min_timeout(); int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout", CBT_DEFAULT_TIMEOUT_INITIAL_VALUE, CBT_MIN_TIMEOUT_INITIAL_VALUE, CBT_MAX_TIMEOUT_INITIAL_VALUE); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_initial_timeout() called, " "cbtinitialtimeout is %d", param); } if (param < min) { log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, " "raising to %d", min); param = min; } return param; } /** * Retrieve and bounds-check the cbtrecentcount consensus paramter. * * Effect: This is the number of circuit build times to keep track of * for deciding if we hit cbtmaxtimeouts and need to reset our state * and learn a new timeout. */ static int32_t circuit_build_times_recent_circuit_count(networkstatus_t *ns) { int32_t num; num = networkstatus_get_param(ns, "cbtrecentcount", CBT_DEFAULT_RECENT_CIRCUITS, CBT_MIN_RECENT_CIRCUITS, CBT_MAX_RECENT_CIRCUITS); if (!(get_options()->LearnCircuitBuildTimeout)) { log_debug(LD_BUG, "circuit_build_times_recent_circuit_count() called, " "cbtrecentcount is %d", num); } return num; } /** * This function is called when we get a consensus update. * * It checks to see if we have changed any consensus parameters * that require reallocation or discard of previous stats. */ void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, networkstatus_t *ns) { int32_t num; /* * First check if we're doing adaptive timeouts at all; nothing to * update if we aren't. */ if (!circuit_build_times_disabled()) { num = circuit_build_times_recent_circuit_count(ns); if (num > 0) { if (num != cbt->liveness.num_recent_circs) { int8_t *recent_circs; log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many " "circuits we must track to detect network failures from %d " "to %d.", cbt->liveness.num_recent_circs, num); tor_assert(cbt->liveness.timeouts_after_firsthop || cbt->liveness.num_recent_circs == 0); /* * Technically this is a circular array that we are reallocating * and memcopying. However, since it only consists of either 1s * or 0s, and is only used in a statistical test to determine when * we should discard our history after a sufficient number of 1's * have been reached, it is fine if order is not preserved or * elements are lost. * * cbtrecentcount should only be changing in cases of severe network * distress anyway, so memory correctness here is paramount over * doing acrobatics to preserve the array. */ recent_circs = tor_malloc_zero(sizeof(int8_t)*num); if (cbt->liveness.timeouts_after_firsthop && cbt->liveness.num_recent_circs > 0) { memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs)); } // Adjust the index if it needs it. if (num < cbt->liveness.num_recent_circs) { cbt->liveness.after_firsthop_idx = MIN(num-1, cbt->liveness.after_firsthop_idx); } tor_free(cbt->liveness.timeouts_after_firsthop); cbt->liveness.timeouts_after_firsthop = recent_circs; cbt->liveness.num_recent_circs = num; } /* else no change, nothing to do */ } else { /* num == 0 */ /* * Weird. This probably shouldn't happen, so log a warning, but try * to do something sensible anyway. */ log_warn(LD_CIRC, "The cbtrecentcircs consensus parameter came back zero! " "This disables adaptive timeouts since we can't keep track of " "any recent circuits."); circuit_build_times_free_timeouts(cbt); } } else { /* * Adaptive timeouts are disabled; this might be because of the * LearnCircuitBuildTimes config parameter, and hence permanent, or * the cbtdisabled consensus parameter, so it may be a new condition. * Treat it like getting num == 0 above and free the circuit history * if we have any. */ circuit_build_times_free_timeouts(cbt); } } /** * Return the initial default or configured timeout in milliseconds */ static double circuit_build_times_get_initial_timeout(void) { double timeout; /* * Check if we have LearnCircuitBuildTimeout, and if we don't, * always use CircuitBuildTimeout, no questions asked. */ if (!unit_tests && get_options()->CircuitBuildTimeout) { timeout = get_options()->CircuitBuildTimeout*1000; if (get_options()->LearnCircuitBuildTimeout && timeout < circuit_build_times_min_timeout()) { log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", circuit_build_times_min_timeout()/1000); timeout = circuit_build_times_min_timeout(); } } else { timeout = circuit_build_times_initial_timeout(); } return timeout; } /** * Reset the build time state. * * Leave estimated parameters, timeout and network liveness intact * for future use. */ void circuit_build_times_reset(circuit_build_times_t *cbt) { memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times)); cbt->total_build_times = 0; cbt->build_times_idx = 0; cbt->have_computed_timeout = 0; } /** * Initialize the buildtimes structure for first use. * * Sets the initial timeout values based on either the config setting, * the consensus param, or the default (CBT_DEFAULT_TIMEOUT_INITIAL_VALUE). */ void circuit_build_times_init(circuit_build_times_t *cbt) { memset(cbt, 0, sizeof(*cbt)); /* * Check if we really are using adaptive timeouts, and don't keep * track of this stuff if not. */ if (!circuit_build_times_disabled()) { cbt->liveness.num_recent_circs = circuit_build_times_recent_circuit_count(NULL); cbt->liveness.timeouts_after_firsthop = tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs); } else { cbt->liveness.num_recent_circs = 0; cbt->liveness.timeouts_after_firsthop = NULL; } cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); } /** * Free the saved timeouts, if the cbtdisabled consensus parameter got turned * on or something. */ void circuit_build_times_free_timeouts(circuit_build_times_t *cbt) { if (!cbt) return; if (cbt->liveness.timeouts_after_firsthop) { tor_free(cbt->liveness.timeouts_after_firsthop); } cbt->liveness.num_recent_circs = 0; } #if 0 /** * Rewind our build time history by n positions. */ static void circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n) { int i = 0; cbt->build_times_idx -= n; cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE; for (i = 0; i < n; i++) { cbt->circuit_build_times[(i+cbt->build_times_idx) %CBT_NCIRCUITS_TO_OBSERVE]=0; } if (cbt->total_build_times > n) { cbt->total_build_times -= n; } else { cbt->total_build_times = 0; } log_info(LD_CIRC, "Rewound history by %d places. Current index: %d. " "Total: %d", n, cbt->build_times_idx, cbt->total_build_times); } #endif /** * Add a new build time value time to the set of build times. Time * units are milliseconds. * * circuit_build_times cbt is a circular array, so loop around when * array is full. */ int circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) { if (time <= 0 || time > CBT_BUILD_TIME_MAX) { log_warn(LD_BUG, "Circuit build time is too large (%u)." "This is probably a bug.", time); tor_fragile_assert(); return -1; } log_debug(LD_CIRC, "Adding circuit build time %u", time); cbt->circuit_build_times[cbt->build_times_idx] = time; cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE; if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) cbt->total_build_times++; if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) { /* Save state every n circuit builds */ if (!unit_tests && !get_options()->AvoidDiskWrites) or_state_mark_dirty(get_or_state(), 0); } return 0; } /** * Return maximum circuit build time */ static build_time_t circuit_build_times_max(circuit_build_times_t *cbt) { int i = 0; build_time_t max_build_time = 0; for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] > max_build_time && cbt->circuit_build_times[i] != CBT_BUILD_ABANDONED) max_build_time = cbt->circuit_build_times[i]; } return max_build_time; } #if 0 /** Return minimum circuit build time */ build_time_t circuit_build_times_min(circuit_build_times_t *cbt) { int i = 0; build_time_t min_build_time = CBT_BUILD_TIME_MAX; for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */ cbt->circuit_build_times[i] < min_build_time) min_build_time = cbt->circuit_build_times[i]; } if (min_build_time == CBT_BUILD_TIME_MAX) { log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!"); } return min_build_time; } #endif /** * Calculate and return a histogram for the set of build times. * * Returns an allocated array of histrogram bins representing * the frequency of index*CBT_BIN_WIDTH millisecond * build times. Also outputs the number of bins in nbins. * * The return value must be freed by the caller. */ static uint32_t * circuit_build_times_create_histogram(circuit_build_times_t *cbt, build_time_t *nbins) { uint32_t *histogram; build_time_t max_build_time = circuit_build_times_max(cbt); int i, c; *nbins = 1 + (max_build_time / CBT_BIN_WIDTH); histogram = tor_malloc_zero(*nbins * sizeof(build_time_t)); // calculate histogram for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] == 0 || cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) continue; /* 0 <-> uninitialized */ c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH); histogram[c]++; } return histogram; } /** * Return the Pareto start-of-curve parameter Xm. * * Because we are not a true Pareto curve, we compute this as the * weighted average of the N most frequent build time bins. N is either * 1 if we don't have enough circuit build time data collected, or * determined by the consensus parameter cbtnummodes (default 3). */ static build_time_t circuit_build_times_get_xm(circuit_build_times_t *cbt) { build_time_t i, nbins; build_time_t *nth_max_bin; int32_t bin_counts=0; build_time_t ret = 0; uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins); int n=0; int num_modes = circuit_build_times_default_num_xm_modes(); tor_assert(nbins > 0); tor_assert(num_modes > 0); // Only use one mode if < 1000 buildtimes. Not enough data // for multiple. if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) num_modes = 1; nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t)); /* Determine the N most common build times */ for (i = 0; i < nbins; i++) { if (histogram[i] >= histogram[nth_max_bin[0]]) { nth_max_bin[0] = i; } for (n = 1; n < num_modes; n++) { if (histogram[i] >= histogram[nth_max_bin[n]] && (!histogram[nth_max_bin[n-1]] || histogram[i] < histogram[nth_max_bin[n-1]])) { nth_max_bin[n] = i; } } } for (n = 0; n < num_modes; n++) { bin_counts += histogram[nth_max_bin[n]]; ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]]; log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]), histogram[nth_max_bin[n]]); } /* The following assert is safe, because we don't get called when we * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */ tor_assert(bin_counts > 0); ret /= bin_counts; tor_free(histogram); tor_free(nth_max_bin); return ret; } /** * Output a histogram of current circuit build times to * the or_state_t state structure. */ void circuit_build_times_update_state(circuit_build_times_t *cbt, or_state_t *state) { uint32_t *histogram; build_time_t i = 0; build_time_t nbins = 0; config_line_t **next, *line; histogram = circuit_build_times_create_histogram(cbt, &nbins); // write to state config_free_lines(state->BuildtimeHistogram); next = &state->BuildtimeHistogram; *next = NULL; state->TotalBuildTimes = cbt->total_build_times; state->CircuitBuildAbandonedCount = 0; for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) state->CircuitBuildAbandonedCount++; } for (i = 0; i < nbins; i++) { // compress the histogram by skipping the blanks if (histogram[i] == 0) continue; *next = line = tor_malloc_zero(sizeof(config_line_t)); line->key = tor_strdup("CircuitBuildTimeBin"); tor_asprintf(&line->value, "%d %d", CBT_BIN_TO_MS(i), histogram[i]); next = &(line->next); } if (!unit_tests) { if (!get_options()->AvoidDiskWrites) or_state_mark_dirty(get_or_state(), 0); } tor_free(histogram); } /** * Shuffle the build times array. * * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle */ static void circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, build_time_t *raw_times, uint32_t num_times) { uint32_t n = num_times; if (num_times > CBT_NCIRCUITS_TO_OBSERVE) { log_notice(LD_CIRC, "The number of circuit times that this Tor version " "uses to calculate build times is less than the number stored " "in your state file. Decreasing the circuit time history from " "%lu to %d.", (unsigned long)num_times, CBT_NCIRCUITS_TO_OBSERVE); } if (n > INT_MAX-1) { log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build " "observations in your state file. That's far too many; probably " "there's a bug here.", (unsigned long)n); n = INT_MAX-1; } /* This code can only be run on a compact array */ while (n-- > 1) { int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */ build_time_t tmp = raw_times[k]; raw_times[k] = raw_times[n]; raw_times[n] = tmp; } /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */ for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) { circuit_build_times_add_time(cbt, raw_times[n]); } } /** * Filter old synthetic timeouts that were created before the * new right-censored Pareto calculation was deployed. * * Once all clients before 0.2.1.13-alpha are gone, this code * will be unused. */ static int circuit_build_times_filter_timeouts(circuit_build_times_t *cbt) { int num_filtered=0, i=0; double timeout_rate = 0; build_time_t max_timeout = 0; timeout_rate = circuit_build_times_timeout_rate(cbt); max_timeout = (build_time_t)cbt->close_ms; for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] > max_timeout) { build_time_t replaced = cbt->circuit_build_times[i]; num_filtered++; cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED; log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced, cbt->circuit_build_times[i]); } } log_info(LD_CIRC, "We had %d timeouts out of %d build times, " "and filtered %d above the max of %u", (int)(cbt->total_build_times*timeout_rate), cbt->total_build_times, num_filtered, max_timeout); return num_filtered; } /** * Load histogram from state, shuffling the resulting array * after we do so. Use this result to estimate parameters and * calculate the timeout. * * Return -1 on error. */ int circuit_build_times_parse_state(circuit_build_times_t *cbt, or_state_t *state) { int tot_values = 0; uint32_t loaded_cnt = 0, N = 0; config_line_t *line; unsigned int i; build_time_t *loaded_times; int err = 0; circuit_build_times_init(cbt); if (circuit_build_times_disabled()) { return 0; } /* build_time_t 0 means uninitialized */ loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes); for (line = state->BuildtimeHistogram; line; line = line->next) { smartlist_t *args = smartlist_new(); smartlist_split_string(args, line->value, " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (smartlist_len(args) < 2) { log_warn(LD_GENERAL, "Unable to parse circuit build times: " "Too few arguments to CircuitBuildTime"); err = 1; SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); break; } else { const char *ms_str = smartlist_get(args,0); const char *count_str = smartlist_get(args,1); uint32_t count, k; build_time_t ms; int ok; ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0, CBT_BUILD_TIME_MAX, &ok, NULL); if (!ok) { log_warn(LD_GENERAL, "Unable to parse circuit build times: " "Unparsable bin number"); err = 1; SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); break; } count = (uint32_t)tor_parse_ulong(count_str, 0, 0, UINT32_MAX, &ok, NULL); if (!ok) { log_warn(LD_GENERAL, "Unable to parse circuit build times: " "Unparsable bin count"); err = 1; SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); break; } if (loaded_cnt+count+state->CircuitBuildAbandonedCount > state->TotalBuildTimes) { log_warn(LD_CIRC, "Too many build times in state file. " "Stopping short before %d", loaded_cnt+count); SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); break; } for (k = 0; k < count; k++) { loaded_times[loaded_cnt++] = ms; } N++; SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); } } log_info(LD_CIRC, "Adding %d timeouts.", state->CircuitBuildAbandonedCount); for (i=0; i < state->CircuitBuildAbandonedCount; i++) { loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED; } if (loaded_cnt != state->TotalBuildTimes) { log_warn(LD_CIRC, "Corrupt state file? Build times count mismatch. " "Read %d times, but file says %d", loaded_cnt, state->TotalBuildTimes); err = 1; circuit_build_times_reset(cbt); goto done; } circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt); /* Verify that we didn't overwrite any indexes */ for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (!cbt->circuit_build_times[i]) break; tot_values++; } log_info(LD_CIRC, "Loaded %d/%d values from %d lines in circuit time histogram", tot_values, cbt->total_build_times, N); if (cbt->total_build_times != tot_values || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) { log_warn(LD_CIRC, "Corrupt state file? Shuffled build times mismatch. " "Read %d times, but file says %d", tot_values, state->TotalBuildTimes); err = 1; circuit_build_times_reset(cbt); goto done; } circuit_build_times_set_timeout(cbt); if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) { circuit_build_times_filter_timeouts(cbt); } done: tor_free(loaded_times); return err ? -1 : 0; } /** * Estimates the Xm and Alpha parameters using * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation * * The notable difference is that we use mode instead of min to estimate Xm. * This is because our distribution is frechet-like. We claim this is * an acceptable approximation because we are only concerned with the * accuracy of the CDF of the tail. */ int circuit_build_times_update_alpha(circuit_build_times_t *cbt) { build_time_t *x=cbt->circuit_build_times; double a = 0; int n=0,i=0,abandoned_count=0; build_time_t max_time=0; /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */ /* We sort of cheat here and make our samples slightly more pareto-like * and less frechet-like. */ cbt->Xm = circuit_build_times_get_xm(cbt); tor_assert(cbt->Xm > 0); for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) { if (!x[i]) { continue; } if (x[i] < cbt->Xm) { a += tor_mathlog(cbt->Xm); } else if (x[i] == CBT_BUILD_ABANDONED) { abandoned_count++; } else { a += tor_mathlog(x[i]); if (x[i] > max_time) max_time = x[i]; } n++; } /* * We are erring and asserting here because this can only happen * in codepaths other than startup. The startup state parsing code * performs this same check, and resets state if it hits it. If we * hit it at runtime, something serious has gone wrong. */ if (n!=cbt->total_build_times) { log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n, cbt->total_build_times); } tor_assert(n==cbt->total_build_times); if (max_time <= 0) { /* This can happen if Xm is actually the *maximum* value in the set. * It can also happen if we've abandoned every single circuit somehow. * In either case, tell the caller not to compute a new build timeout. */ log_warn(LD_BUG, "Could not determine largest build time (%d). " "Xm is %dms and we've abandoned %d out of %d circuits.", max_time, cbt->Xm, abandoned_count, n); return 0; } a += abandoned_count*tor_mathlog(max_time); a -= n*tor_mathlog(cbt->Xm); // Estimator comes from Eq #4 in: // "Bayesian estimation based on trimmed samples from Pareto populations" // by Arturo J. Fernández. We are right-censored only. a = (n-abandoned_count)/a; cbt->alpha = a; return 1; } /** * This is the Pareto Quantile Function. It calculates the point x * in the distribution such that F(x) = quantile (ie quantile*100% * of the mass of the density function is below x on the curve). * * We use it to calculate the timeout and also to generate synthetic * values of time for circuits that timeout before completion. * * See http://en.wikipedia.org/wiki/Quantile_function, * http://en.wikipedia.org/wiki/Inverse_transform_sampling and * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_ * random_sample_from_Pareto_distribution * That's right. I'll cite wikipedia all day long. * * Return value is in milliseconds. */ double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, double quantile) { double ret; tor_assert(quantile >= 0); tor_assert(1.0-quantile > 0); tor_assert(cbt->Xm > 0); ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha); if (ret > INT32_MAX) { ret = INT32_MAX; } tor_assert(ret > 0); return ret; } /** Pareto CDF */ double circuit_build_times_cdf(circuit_build_times_t *cbt, double x) { double ret; tor_assert(cbt->Xm > 0); ret = 1.0-pow(cbt->Xm/x,cbt->alpha); tor_assert(0 <= ret && ret <= 1.0); return ret; } /** * Generate a synthetic time using our distribution parameters. * * The return value will be within the [q_lo, q_hi) quantile points * on the CDF. */ build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt, double q_lo, double q_hi) { double randval = crypto_rand_double(); build_time_t ret; double u; /* Generate between [q_lo, q_hi) */ /*XXXX This is what nextafter is supposed to be for; we should use it on the * platforms that support it. */ q_hi -= 1.0/(INT32_MAX); tor_assert(q_lo >= 0); tor_assert(q_hi < 1); tor_assert(q_lo < q_hi); u = q_lo + (q_hi-q_lo)*randval; tor_assert(0 <= u && u < 1.0); /* circuit_build_times_calculate_timeout returns <= INT32_MAX */ ret = (build_time_t) tor_lround(circuit_build_times_calculate_timeout(cbt, u)); tor_assert(ret > 0); return ret; } /** * Estimate an initial alpha parameter by solving the quantile * function with a quantile point and a specific timeout value. */ void circuit_build_times_initial_alpha(circuit_build_times_t *cbt, double quantile, double timeout_ms) { // Q(u) = Xm/((1-u)^(1/a)) // Q(0.8) = Xm/((1-0.8))^(1/a)) = CircBuildTimeout // CircBuildTimeout = Xm/((1-0.8))^(1/a)) // CircBuildTimeout = Xm*((1-0.8))^(-1/a)) // ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a) // -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a tor_assert(quantile >= 0); tor_assert(cbt->Xm > 0); cbt->alpha = tor_mathlog(1.0-quantile)/ (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms)); tor_assert(cbt->alpha > 0); } /** * Returns true if we need circuits to be built */ int circuit_build_times_needs_circuits(circuit_build_times_t *cbt) { /* Return true if < MIN_CIRCUITS_TO_OBSERVE */ return !circuit_build_times_enough_to_compute(cbt); } /** * Returns true if we should build a timeout test circuit * right now. */ int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt) { return circuit_build_times_needs_circuits(cbt) && approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency(); } /** * Called to indicate that the network showed some signs of liveness, * i.e. we received a cell. * * This is used by circuit_build_times_network_check_live() to decide * if we should record the circuit build timeout or not. * * This function is called every time we receive a cell. Avoid * syscalls, events, and other high-intensity work. */ void circuit_build_times_network_is_live(circuit_build_times_t *cbt) { time_t now = approx_time(); if (cbt->liveness.nonlive_timeouts > 0) { log_notice(LD_CIRC, "Tor now sees network activity. Restoring circuit build " "timeout recording. Network was down for %d seconds " "during %d circuit attempts.", (int)(now - cbt->liveness.network_last_live), cbt->liveness.nonlive_timeouts); } cbt->liveness.network_last_live = now; cbt->liveness.nonlive_timeouts = 0; } /** * Called to indicate that we completed a circuit. Because this circuit * succeeded, it doesn't count as a timeout-after-the-first-hop. * * This is used by circuit_build_times_network_check_changed() to determine * if we had too many recent timeouts and need to reset our learned timeout * to something higher. */ void circuit_build_times_network_circ_success(circuit_build_times_t *cbt) { /* Check for NULLness because we might not be using adaptive timeouts */ if (cbt->liveness.timeouts_after_firsthop && cbt->liveness.num_recent_circs > 0) { cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] = 0; cbt->liveness.after_firsthop_idx++; cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; } } /** * A circuit just timed out. If it failed after the first hop, record it * in our history for later deciding if the network speed has changed. * * This is used by circuit_build_times_network_check_changed() to determine * if we had too many recent timeouts and need to reset our learned timeout * to something higher. */ static void circuit_build_times_network_timeout(circuit_build_times_t *cbt, int did_onehop) { /* Check for NULLness because we might not be using adaptive timeouts */ if (cbt->liveness.timeouts_after_firsthop && cbt->liveness.num_recent_circs > 0) { if (did_onehop) { cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] = 1; cbt->liveness.after_firsthop_idx++; cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; } } } /** * A circuit was just forcibly closed. If there has been no recent network * activity at all, but this circuit was launched back when we thought the * network was live, increment the number of "nonlive" circuit timeouts. * * This is used by circuit_build_times_network_check_live() to decide * if we should record the circuit build timeout or not. */ static void circuit_build_times_network_close(circuit_build_times_t *cbt, int did_onehop, time_t start_time) { time_t now = time(NULL); /* * Check if this is a timeout that was for a circuit that spent its * entire existence during a time where we have had no network activity. */ if (cbt->liveness.network_last_live < start_time) { if (did_onehop) { char last_live_buf[ISO_TIME_LEN+1]; char start_time_buf[ISO_TIME_LEN+1]; char now_buf[ISO_TIME_LEN+1]; format_local_iso_time(last_live_buf, cbt->liveness.network_last_live); format_local_iso_time(start_time_buf, start_time); format_local_iso_time(now_buf, now); log_notice(LD_CIRC, "A circuit somehow completed a hop while the network was " "not live. The network was last live at %s, but the circuit " "launched at %s. It's now %s. This could mean your clock " "changed.", last_live_buf, start_time_buf, now_buf); } cbt->liveness.nonlive_timeouts++; if (cbt->liveness.nonlive_timeouts == 1) { log_notice(LD_CIRC, "Tor has not observed any network activity for the past %d " "seconds. Disabling circuit build timeout recording.", (int)(now - cbt->liveness.network_last_live)); } else { log_info(LD_CIRC, "Got non-live timeout. Current count is: %d", cbt->liveness.nonlive_timeouts); } } } /** * When the network is not live, we do not record circuit build times. * * The network is considered not live if there has been at least one * circuit build that began and ended (had its close_ms measurement * period expire) since we last received a cell. * * Also has the side effect of rewinding the circuit time history * in the case of recent liveness changes. */ int circuit_build_times_network_check_live(circuit_build_times_t *cbt) { if (cbt->liveness.nonlive_timeouts > 0) { return 0; } return 1; } /** * Returns true if we have seen more than MAX_RECENT_TIMEOUT_COUNT of * the past RECENT_CIRCUITS time out after the first hop. Used to detect * if the network connection has changed significantly, and if so, * resets our circuit build timeout to the default. * * Also resets the entire timeout history in this case and causes us * to restart the process of building test circuits and estimating a * new timeout. */ int circuit_build_times_network_check_changed(circuit_build_times_t *cbt) { int total_build_times = cbt->total_build_times; int timeout_count=0; int i; if (cbt->liveness.timeouts_after_firsthop && cbt->liveness.num_recent_circs > 0) { /* how many of our recent circuits made it to the first hop but then * timed out? */ for (i = 0; i < cbt->liveness.num_recent_circs; i++) { timeout_count += cbt->liveness.timeouts_after_firsthop[i]; } } /* If 80% of our recent circuits are timing out after the first hop, * we need to re-estimate a new initial alpha and timeout. */ if (timeout_count < circuit_build_times_max_timeouts()) { return 0; } circuit_build_times_reset(cbt); if (cbt->liveness.timeouts_after_firsthop && cbt->liveness.num_recent_circs > 0) { memset(cbt->liveness.timeouts_after_firsthop, 0, sizeof(*cbt->liveness.timeouts_after_firsthop)* cbt->liveness.num_recent_circs); } cbt->liveness.after_firsthop_idx = 0; /* Check to see if this has happened before. If so, double the timeout * to give people on abysmally bad network connections a shot at access */ if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) { if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) { log_warn(LD_CIRC, "Insanely large circuit build timeout value. " "(timeout = %fmsec, close = %fmsec)", cbt->timeout_ms, cbt->close_ms); } else { cbt->timeout_ms *= 2; cbt->close_ms *= 2; } } else { cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); } control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); log_notice(LD_CIRC, "Your network connection speed appears to have changed. Resetting " "timeout to %lds after %d timeouts and %d buildtimes.", tor_lround(cbt->timeout_ms/1000), timeout_count, total_build_times); return 1; } /** * Count the number of timeouts in a set of cbt data. */ double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt) { int i=0,timeouts=0; for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] >= cbt->timeout_ms) { timeouts++; } } if (!cbt->total_build_times) return 0; return ((double)timeouts)/cbt->total_build_times; } /** * Count the number of closed circuits in a set of cbt data. */ double circuit_build_times_close_rate(const circuit_build_times_t *cbt) { int i=0,closed=0; for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) { closed++; } } if (!cbt->total_build_times) return 0; return ((double)closed)/cbt->total_build_times; } /** * Store a timeout as a synthetic value. * * Returns true if the store was successful and we should possibly * update our timeout estimate. */ int circuit_build_times_count_close(circuit_build_times_t *cbt, int did_onehop, time_t start_time) { if (circuit_build_times_disabled()) { cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); return 0; } /* Record this force-close to help determine if the network is dead */ circuit_build_times_network_close(cbt, did_onehop, start_time); /* Only count timeouts if network is live.. */ if (!circuit_build_times_network_check_live(cbt)) { return 0; } circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED); return 1; } /** * Update timeout counts to determine if we need to expire * our build time history due to excessive timeouts. * * We do not record any actual time values at this stage; * we are only interested in recording the fact that a timeout * happened. We record the time values via * circuit_build_times_count_close() and circuit_build_times_add_time(). */ void circuit_build_times_count_timeout(circuit_build_times_t *cbt, int did_onehop) { if (circuit_build_times_disabled()) { cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); return; } /* Register the fact that a timeout just occurred. */ circuit_build_times_network_timeout(cbt, did_onehop); /* If there are a ton of timeouts, we should reset * the circuit build timeout. */ circuit_build_times_network_check_changed(cbt); } /** * Estimate a new timeout based on history and set our timeout * variable accordingly. */ static int circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt) { build_time_t max_time; if (!circuit_build_times_enough_to_compute(cbt)) return 0; if (!circuit_build_times_update_alpha(cbt)) return 0; cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt, circuit_build_times_quantile_cutoff()); cbt->close_ms = circuit_build_times_calculate_timeout(cbt, circuit_build_times_close_quantile()); max_time = circuit_build_times_max(cbt); if (cbt->timeout_ms > max_time) { log_info(LD_CIRC, "Circuit build timeout of %dms is beyond the maximum build " "time we have ever observed. Capping it to %dms.", (int)cbt->timeout_ms, max_time); cbt->timeout_ms = max_time; } if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) { log_info(LD_CIRC, "Circuit build measurement period of %dms is more than twice " "the maximum build time we have ever observed. Capping it to " "%dms.", (int)cbt->close_ms, 2*max_time); cbt->close_ms = 2*max_time; } /* Sometimes really fast guard nodes give us such a steep curve * that this ends up being not that much greater than timeout_ms. * Make it be at least 1 min to handle this case. */ cbt->close_ms = MAX(cbt->close_ms, circuit_build_times_initial_timeout()); cbt->have_computed_timeout = 1; return 1; } /** * Exposed function to compute a new timeout. Dispatches events and * also filters out extremely high timeout values. */ void circuit_build_times_set_timeout(circuit_build_times_t *cbt) { long prev_timeout = tor_lround(cbt->timeout_ms/1000); double timeout_rate; /* * Just return if we aren't using adaptive timeouts */ if (circuit_build_times_disabled()) return; if (!circuit_build_times_set_timeout_worker(cbt)) return; if (cbt->timeout_ms < circuit_build_times_min_timeout()) { log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms", cbt->timeout_ms, circuit_build_times_min_timeout()); cbt->timeout_ms = circuit_build_times_min_timeout(); if (cbt->close_ms < cbt->timeout_ms) { /* This shouldn't happen because of MAX() in timeout_worker above, * but doing it just in case */ cbt->close_ms = circuit_build_times_initial_timeout(); } } control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED); timeout_rate = circuit_build_times_timeout_rate(cbt); if (prev_timeout > tor_lround(cbt->timeout_ms/1000)) { log_info(LD_CIRC, "Based on %d circuit times, it looks like we don't need to " "wait so long for circuits to finish. We will now assume a " "circuit is too slow to use after waiting %ld seconds.", cbt->total_build_times, tor_lround(cbt->timeout_ms/1000)); log_info(LD_CIRC, "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate); } else if (prev_timeout < tor_lround(cbt->timeout_ms/1000)) { log_info(LD_CIRC, "Based on %d circuit times, it looks like we need to wait " "longer for circuits to finish. We will now assume a " "circuit is too slow to use after waiting %ld seconds.", cbt->total_build_times, tor_lround(cbt->timeout_ms/1000)); log_info(LD_CIRC, "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate); } else { log_info(LD_CIRC, "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f," " r: %f) based on %d circuit times", tor_lround(cbt->timeout_ms/1000), cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate, cbt->total_build_times); } } /** Make a note that we're running unit tests (rather than running Tor * itself), so we avoid clobbering our state file. */ void circuitbuild_running_unit_tests(void) { unit_tests = 1; } tor-0.2.4.20/src/or/rendcommon.h0000644000175000017500000000536312166112777013224 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file rendcommon.h * \brief Header file for rendcommon.c. **/ #ifndef TOR_RENDCOMMON_H #define TOR_RENDCOMMON_H /** Free all storage associated with data */ static INLINE void rend_data_free(rend_data_t *data) { tor_free(data); } int rend_cmp_service_ids(const char *one, const char *two); void rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, int command, size_t length, const uint8_t *payload); void rend_service_descriptor_free(rend_service_descriptor_t *desc); rend_service_descriptor_t *rend_parse_service_descriptor(const char *str, size_t len); int rend_get_service_id(crypto_pk_t *pk, char *out); void rend_encoded_v2_service_descriptor_free( rend_encoded_v2_service_descriptor_t *desc); void rend_intro_point_free(rend_intro_point_t *intro); void rend_cache_init(void); void rend_cache_clean(time_t now); void rend_cache_clean_v2_descs_as_dir(time_t now); void rend_cache_purge(void); void rend_cache_free_all(void); int rend_valid_service_id(const char *query); int rend_cache_lookup_desc(const char *query, int version, const char **desc, size_t *desc_len); int rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **entry_out); int rend_cache_lookup_v2_desc_as_dir(const char *query, const char **desc); int rend_cache_store(const char *desc, size_t desc_len, int published, const char *service_id); int rend_cache_store_v2_desc_as_client(const char *desc, const rend_data_t *rend_query); int rend_cache_store_v2_desc_as_dir(const char *desc); int rend_encode_v2_descriptors(smartlist_t *descs_out, rend_service_descriptor_t *desc, time_t now, uint8_t period, rend_auth_type_t auth_type, crypto_pk_t *client_key, smartlist_t *client_cookies); int rend_compute_v2_desc_id(char *desc_id_out, const char *service_id, const char *descriptor_cookie, time_t now, uint8_t replica); int rend_id_is_in_interval(const char *a, const char *b, const char *c); void rend_get_descriptor_id_bytes(char *descriptor_id_out, const char *service_id, const char *secret_id_part); #endif tor-0.2.4.20/src/or/hibernate.c0000644000175000017500000010462112255745673013022 00000000000000/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file hibernate.c * \brief Functions to close listeners, stop allowing new circuits, * etc in preparation for closing down or going dormant; and to track * bandwidth and time intervals to know when to hibernate and when to * stop hibernating. **/ /* hibernating, phase 1: - send destroy in response to create cells - send end (policy failed) in response to begin cells - close an OR conn when it has no circuits hibernating, phase 2: (entered when bandwidth hard limit reached) - close all OR/AP/exit conns) */ #define HIBERNATE_PRIVATE #include "or.h" #include "channel.h" #include "channeltls.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "hibernate.h" #include "main.h" #include "router.h" #include "statefile.h" extern long stats_n_seconds_working; /* published uptime */ /** Are we currently awake, asleep, running out of bandwidth, or shutting * down? */ static hibernate_state_t hibernate_state = HIBERNATE_STATE_INITIAL; /** If are hibernating, when do we plan to wake up? Set to 0 if we * aren't hibernating. */ static time_t hibernate_end_time = 0; /** If we are shutting down, when do we plan finally exit? Set to 0 if * we aren't shutting down. */ static time_t shutdown_time = 0; /** Possible accounting periods. */ typedef enum { UNIT_MONTH=1, UNIT_WEEK=2, UNIT_DAY=3, } time_unit_t; /* Fields for accounting logic. Accounting overview: * * Accounting is designed to ensure that no more than N bytes are sent in * either direction over a given interval (currently, one month, one week, or * one day) We could * try to do this by choking our bandwidth to a trickle, but that * would make our streams useless. Instead, we estimate what our * bandwidth usage will be, and guess how long we'll be able to * provide that much bandwidth before hitting our limit. We then * choose a random time within the accounting interval to come up (so * that we don't get 50 Tors running on the 1st of the month and none * on the 30th). * * Each interval runs as follows: * * 1. We guess our bandwidth usage, based on how much we used * last time. We choose a "wakeup time" within the interval to come up. * 2. Until the chosen wakeup time, we hibernate. * 3. We come up at the wakeup time, and provide bandwidth until we are * "very close" to running out. * 4. Then we go into low-bandwidth mode, and stop accepting new * connections, but provide bandwidth until we run out. * 5. Then we hibernate until the end of the interval. * * If the interval ends before we run out of bandwidth, we go back to * step one. */ /** How many bytes have we read in this accounting interval? */ static uint64_t n_bytes_read_in_interval = 0; /** How many bytes have we written in this accounting interval? */ static uint64_t n_bytes_written_in_interval = 0; /** How many seconds have we been running this interval? */ static uint32_t n_seconds_active_in_interval = 0; /** How many seconds were we active in this interval before we hit our soft * limit? */ static int n_seconds_to_hit_soft_limit = 0; /** When in this interval was the soft limit hit. */ static time_t soft_limit_hit_at = 0; /** How many bytes had we read/written when we hit the soft limit? */ static uint64_t n_bytes_at_soft_limit = 0; /** When did this accounting interval start? */ static time_t interval_start_time = 0; /** When will this accounting interval end? */ static time_t interval_end_time = 0; /** How far into the accounting interval should we hibernate? */ static time_t interval_wakeup_time = 0; /** How much bandwidth do we 'expect' to use per minute? (0 if we have no * info from the last period.) */ static uint64_t expected_bandwidth_usage = 0; /** What unit are we using for our accounting? */ static time_unit_t cfg_unit = UNIT_MONTH; /** How many days,hours,minutes into each unit does our accounting interval * start? */ /** @{ */ static int cfg_start_day = 0, cfg_start_hour = 0, cfg_start_min = 0; /** @} */ static void reset_accounting(time_t now); static int read_bandwidth_usage(void); static time_t start_of_accounting_period_after(time_t now); static time_t start_of_accounting_period_containing(time_t now); static void accounting_set_wakeup_time(void); /* ************ * Functions for bandwidth accounting. * ************/ /** Configure accounting start/end time settings based on * options->AccountingStart. Return 0 on success, -1 on failure. If * validate_only is true, do not change the current settings. */ int accounting_parse_options(const or_options_t *options, int validate_only) { time_unit_t unit; int ok, idx; long d,h,m; smartlist_t *items; const char *v = options->AccountingStart; const char *s; char *cp; if (!v) { if (!validate_only) { cfg_unit = UNIT_MONTH; cfg_start_day = 1; cfg_start_hour = 0; cfg_start_min = 0; } return 0; } items = smartlist_new(); smartlist_split_string(items, v, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0); if (smartlist_len(items)<2) { log_warn(LD_CONFIG, "Too few arguments to AccountingStart"); goto err; } s = smartlist_get(items,0); if (0==strcasecmp(s, "month")) { unit = UNIT_MONTH; } else if (0==strcasecmp(s, "week")) { unit = UNIT_WEEK; } else if (0==strcasecmp(s, "day")) { unit = UNIT_DAY; } else { log_warn(LD_CONFIG, "Unrecognized accounting unit '%s': only 'month', 'week'," " and 'day' are supported.", s); goto err; } switch (unit) { case UNIT_WEEK: d = tor_parse_long(smartlist_get(items,1), 10, 1, 7, &ok, NULL); if (!ok) { log_warn(LD_CONFIG, "Weekly accounting must begin on a day between " "1 (Monday) and 7 (Sunday)"); goto err; } break; case UNIT_MONTH: d = tor_parse_long(smartlist_get(items,1), 10, 1, 28, &ok, NULL); if (!ok) { log_warn(LD_CONFIG, "Monthly accounting must begin on a day between " "1 and 28"); goto err; } break; case UNIT_DAY: d = 0; break; /* Coverity dislikes unreachable default cases; some compilers warn on * switch statements missing a case. Tell Coverity not to worry. */ /* coverity[dead_error_begin] */ default: tor_assert(0); } idx = unit==UNIT_DAY?1:2; if (smartlist_len(items) != (idx+1)) { log_warn(LD_CONFIG,"Accounting unit '%s' requires %d argument%s.", s, idx, (idx>1)?"s":""); goto err; } s = smartlist_get(items, idx); h = tor_parse_long(s, 10, 0, 23, &ok, &cp); if (!ok) { log_warn(LD_CONFIG,"Accounting start time not parseable: bad hour."); goto err; } if (!cp || *cp!=':') { log_warn(LD_CONFIG, "Accounting start time not parseable: not in HH:MM format"); goto err; } m = tor_parse_long(cp+1, 10, 0, 59, &ok, &cp); if (!ok) { log_warn(LD_CONFIG, "Accounting start time not parseable: bad minute"); goto err; } if (!cp || *cp!='\0') { log_warn(LD_CONFIG, "Accounting start time not parseable: not in HH:MM format"); goto err; } if (!validate_only) { cfg_unit = unit; cfg_start_day = (int)d; cfg_start_hour = (int)h; cfg_start_min = (int)m; } SMARTLIST_FOREACH(items, char *, item, tor_free(item)); smartlist_free(items); return 0; err: SMARTLIST_FOREACH(items, char *, item, tor_free(item)); smartlist_free(items); return -1; } /** If we want to manage the accounting system and potentially * hibernate, return 1, else return 0. */ int accounting_is_enabled(const or_options_t *options) { if (options->AccountingMax) return 1; return 0; } /** If accounting is enabled, return how long (in seconds) this * interval lasts. */ int accounting_get_interval_length(void) { return (int)(interval_end_time - interval_start_time); } /** Called from main.c to tell us that seconds seconds have * passed, n_read bytes have been read, and n_written * bytes have been written. */ void accounting_add_bytes(size_t n_read, size_t n_written, int seconds) { n_bytes_read_in_interval += n_read; n_bytes_written_in_interval += n_written; /* If we haven't been called in 10 seconds, we're probably jumping * around in time. */ n_seconds_active_in_interval += (seconds < 10) ? seconds : 0; } /** If get_end, return the end of the accounting period that contains * the time now. Else, return the start of the accounting * period that contains the time now */ static time_t edge_of_accounting_period_containing(time_t now, int get_end) { int before; struct tm tm; tor_localtime_r(&now, &tm); /* Set 'before' to true iff the current time is before the hh:mm * changeover time for today. */ before = tm.tm_hour < cfg_start_hour || (tm.tm_hour == cfg_start_hour && tm.tm_min < cfg_start_min); /* Dispatch by unit. First, find the start day of the given period; * then, if get_end is true, increment to the end day. */ switch (cfg_unit) { case UNIT_MONTH: { /* If this is before the Nth, we want the Nth of last month. */ if (tm.tm_mday < cfg_start_day || (tm.tm_mday < cfg_start_day && before)) { --tm.tm_mon; } /* Otherwise, the month is correct. */ tm.tm_mday = cfg_start_day; if (get_end) ++tm.tm_mon; break; } case UNIT_WEEK: { /* What is the 'target' day of the week in struct tm format? (We say Sunday==7; struct tm says Sunday==0.) */ int wday = cfg_start_day % 7; /* How many days do we subtract from today to get to the right day? */ int delta = (7+tm.tm_wday-wday)%7; /* If we are on the right day, but the changeover hasn't happened yet, * then subtract a whole week. */ if (delta == 0 && before) delta = 7; tm.tm_mday -= delta; if (get_end) tm.tm_mday += 7; break; } case UNIT_DAY: if (before) --tm.tm_mday; if (get_end) ++tm.tm_mday; break; default: tor_assert(0); } tm.tm_hour = cfg_start_hour; tm.tm_min = cfg_start_min; tm.tm_sec = 0; tm.tm_isdst = -1; /* Autodetect DST */ return mktime(&tm); } /** Return the start of the accounting period containing the time * now. */ static time_t start_of_accounting_period_containing(time_t now) { return edge_of_accounting_period_containing(now, 0); } /** Return the start of the accounting period that comes after the one * containing the time now. */ static time_t start_of_accounting_period_after(time_t now) { return edge_of_accounting_period_containing(now, 1); } /** Return the length of the accounting period containing the time * now. */ static long length_of_accounting_period_containing(time_t now) { return edge_of_accounting_period_containing(now, 1) - edge_of_accounting_period_containing(now, 0); } /** Initialize the accounting subsystem. */ void configure_accounting(time_t now) { time_t s_now; /* Try to remember our recorded usage. */ if (!interval_start_time) read_bandwidth_usage(); /* If we fail, we'll leave values at zero, and * reset below.*/ s_now = start_of_accounting_period_containing(now); if (!interval_start_time) { /* We didn't have recorded usage; Start a new interval. */ log_info(LD_ACCT, "Starting new accounting interval."); reset_accounting(now); } else if (s_now == interval_start_time) { log_info(LD_ACCT, "Continuing accounting interval."); /* We are in the interval we thought we were in. Do nothing.*/ interval_end_time = start_of_accounting_period_after(interval_start_time); } else { long duration = length_of_accounting_period_containing(interval_start_time); double delta = ((double)(s_now - interval_start_time)) / duration; if (-0.50 <= delta && delta <= 0.50) { /* The start of the period is now a little later or earlier than we * remembered. That's fine; we might lose some bytes we could otherwise * have written, but better to err on the side of obeying people's * accounting settings. */ log_info(LD_ACCT, "Accounting interval moved by %.02f%%; " "that's fine.", delta*100); interval_end_time = start_of_accounting_period_after(now); } else if (delta >= 0.99) { /* This is the regular time-moved-forward case; don't be too noisy * about it or people will complain */ log_info(LD_ACCT, "Accounting interval elapsed; starting a new one"); reset_accounting(now); } else { log_warn(LD_ACCT, "Mismatched accounting interval: moved by %.02f%%. " "Starting a fresh one.", delta*100); reset_accounting(now); } } accounting_set_wakeup_time(); } /** Set expected_bandwidth_usage based on how much we sent/received * per minute last interval (if we were up for at least 30 minutes), * or based on our declared bandwidth otherwise. */ static void update_expected_bandwidth(void) { uint64_t expected; const or_options_t *options= get_options(); uint64_t max_configured = (options->RelayBandwidthRate > 0 ? options->RelayBandwidthRate : options->BandwidthRate) * 60; #define MIN_TIME_FOR_MEASUREMENT (1800) if (soft_limit_hit_at > interval_start_time && n_bytes_at_soft_limit && (soft_limit_hit_at - interval_start_time) > MIN_TIME_FOR_MEASUREMENT) { /* If we hit our soft limit last time, only count the bytes up to that * time. This is a better predictor of our actual bandwidth than * considering the entirety of the last interval, since we likely started * using bytes very slowly once we hit our soft limit. */ expected = n_bytes_at_soft_limit / (soft_limit_hit_at - interval_start_time); expected /= 60; } else if (n_seconds_active_in_interval >= MIN_TIME_FOR_MEASUREMENT) { /* Otherwise, we either measured enough time in the last interval but * never hit our soft limit, or we're using a state file from a Tor that * doesn't know to store soft-limit info. Just take rate at which * we were reading/writing in the last interval as our expected rate. */ uint64_t used = MAX(n_bytes_written_in_interval, n_bytes_read_in_interval); expected = used / (n_seconds_active_in_interval / 60); } else { /* If we haven't gotten enough data last interval, set 'expected' * to 0. This will set our wakeup to the start of the interval. * Next interval, we'll choose our starting time based on how much * we sent this interval. */ expected = 0; } if (expected > max_configured) expected = max_configured; expected_bandwidth_usage = expected; } /** Called at the start of a new accounting interval: reset our * expected bandwidth usage based on what happened last time, set up * the start and end of the interval, and clear byte/time totals. */ static void reset_accounting(time_t now) { log_info(LD_ACCT, "Starting new accounting interval."); update_expected_bandwidth(); interval_start_time = start_of_accounting_period_containing(now); interval_end_time = start_of_accounting_period_after(interval_start_time); n_bytes_read_in_interval = 0; n_bytes_written_in_interval = 0; n_seconds_active_in_interval = 0; n_bytes_at_soft_limit = 0; soft_limit_hit_at = 0; n_seconds_to_hit_soft_limit = 0; } /** Return true iff we should save our bandwidth usage to disk. */ static INLINE int time_to_record_bandwidth_usage(time_t now) { /* Note every 600 sec */ #define NOTE_INTERVAL (600) /* Or every 20 megabytes */ #define NOTE_BYTES 20*(1024*1024) static uint64_t last_read_bytes_noted = 0; static uint64_t last_written_bytes_noted = 0; static time_t last_time_noted = 0; if (last_time_noted + NOTE_INTERVAL <= now || last_read_bytes_noted + NOTE_BYTES <= n_bytes_read_in_interval || last_written_bytes_noted + NOTE_BYTES <= n_bytes_written_in_interval || (interval_end_time && interval_end_time <= now)) { last_time_noted = now; last_read_bytes_noted = n_bytes_read_in_interval; last_written_bytes_noted = n_bytes_written_in_interval; return 1; } return 0; } /** Invoked once per second. Checks whether it is time to hibernate, * record bandwidth used, etc. */ void accounting_run_housekeeping(time_t now) { if (now >= interval_end_time) { configure_accounting(now); } if (time_to_record_bandwidth_usage(now)) { if (accounting_record_bandwidth_usage(now, get_or_state())) { log_warn(LD_FS, "Couldn't record bandwidth usage to disk."); } } } /** Based on our interval and our estimated bandwidth, choose a * deterministic (but random-ish) time to wake up. */ static void accounting_set_wakeup_time(void) { char digest[DIGEST_LEN]; crypto_digest_t *d_env; uint64_t time_to_exhaust_bw; int time_to_consider; if (! server_identity_key_is_set()) { if (init_keys() < 0) { log_err(LD_BUG, "Error initializing keys"); tor_assert(0); } } if (server_identity_key_is_set()) { char buf[ISO_TIME_LEN+1]; format_iso_time(buf, interval_start_time); crypto_pk_get_digest(get_server_identity_key(), digest); d_env = crypto_digest_new(); crypto_digest_add_bytes(d_env, buf, ISO_TIME_LEN); crypto_digest_add_bytes(d_env, digest, DIGEST_LEN); crypto_digest_get_digest(d_env, digest, DIGEST_LEN); crypto_digest_free(d_env); } else { crypto_rand(digest, DIGEST_LEN); } if (!expected_bandwidth_usage) { char buf1[ISO_TIME_LEN+1]; char buf2[ISO_TIME_LEN+1]; format_local_iso_time(buf1, interval_start_time); format_local_iso_time(buf2, interval_end_time); interval_wakeup_time = interval_start_time; log_notice(LD_ACCT, "Configured hibernation. This interval begins at %s " "and ends at %s. We have no prior estimate for bandwidth, so " "we will start out awake and hibernate when we exhaust our quota.", buf1, buf2); return; } time_to_exhaust_bw = (get_options()->AccountingMax/expected_bandwidth_usage)*60; if (time_to_exhaust_bw > INT_MAX) { time_to_exhaust_bw = INT_MAX; time_to_consider = 0; } else { time_to_consider = accounting_get_interval_length() - (int)time_to_exhaust_bw; } if (time_to_consider<=0) { interval_wakeup_time = interval_start_time; } else { /* XXX can we simplify this just by picking a random (non-deterministic) * time to be up? If we go down and come up, then we pick a new one. Is * that good enough? -RD */ /* This is not a perfectly unbiased conversion, but it is good enough: * in the worst case, the first half of the day is 0.06 percent likelier * to be chosen than the last half. */ interval_wakeup_time = interval_start_time + (get_uint32(digest) % time_to_consider); } { char buf1[ISO_TIME_LEN+1]; char buf2[ISO_TIME_LEN+1]; char buf3[ISO_TIME_LEN+1]; char buf4[ISO_TIME_LEN+1]; time_t down_time; if (interval_wakeup_time+time_to_exhaust_bw > TIME_MAX) down_time = TIME_MAX; else down_time = (time_t)(interval_wakeup_time+time_to_exhaust_bw); if (down_time>interval_end_time) down_time = interval_end_time; format_local_iso_time(buf1, interval_start_time); format_local_iso_time(buf2, interval_wakeup_time); format_local_iso_time(buf3, down_time); format_local_iso_time(buf4, interval_end_time); log_notice(LD_ACCT, "Configured hibernation. This interval began at %s; " "the scheduled wake-up time %s %s; " "we expect%s to exhaust our quota for this interval around %s; " "the next interval begins at %s (all times local)", buf1, time(NULL)AccountingIntervalStart = interval_start_time; state->AccountingBytesReadInInterval = ROUND_UP(n_bytes_read_in_interval); state->AccountingBytesWrittenInInterval = ROUND_UP(n_bytes_written_in_interval); state->AccountingSecondsActive = n_seconds_active_in_interval; state->AccountingExpectedUsage = expected_bandwidth_usage; state->AccountingSecondsToReachSoftLimit = n_seconds_to_hit_soft_limit; state->AccountingSoftLimitHitAt = soft_limit_hit_at; state->AccountingBytesAtSoftLimit = n_bytes_at_soft_limit; or_state_mark_dirty(state, now+(get_options()->AvoidDiskWrites ? 7200 : 60)); return 0; } #undef ROUND_UP /** Read stored accounting information from disk. Return 0 on success; * return -1 and change nothing on failure. */ static int read_bandwidth_usage(void) { or_state_t *state = get_or_state(); { char *fname = get_datadir_fname("bw_accounting"); unlink(fname); tor_free(fname); } if (!state) return -1; log_info(LD_ACCT, "Reading bandwidth accounting data from state file"); n_bytes_read_in_interval = state->AccountingBytesReadInInterval; n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval; n_seconds_active_in_interval = state->AccountingSecondsActive; interval_start_time = state->AccountingIntervalStart; expected_bandwidth_usage = state->AccountingExpectedUsage; /* Older versions of Tor (before 0.2.2.17-alpha or so) didn't generate these * fields. If you switch back and forth, you might get an * AccountingSoftLimitHitAt value from long before the most recent * interval_start_time. If that's so, then ignore the softlimit-related * values. */ if (state->AccountingSoftLimitHitAt > interval_start_time) { soft_limit_hit_at = state->AccountingSoftLimitHitAt; n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit; n_seconds_to_hit_soft_limit = state->AccountingSecondsToReachSoftLimit; } else { soft_limit_hit_at = 0; n_bytes_at_soft_limit = 0; n_seconds_to_hit_soft_limit = 0; } { char tbuf1[ISO_TIME_LEN+1]; char tbuf2[ISO_TIME_LEN+1]; format_iso_time(tbuf1, state->LastWritten); format_iso_time(tbuf2, state->AccountingIntervalStart); log_info(LD_ACCT, "Successfully read bandwidth accounting info from state written at %s " "for interval starting at %s. We have been active for %lu seconds in " "this interval. At the start of the interval, we expected to use " "about %lu KB per second. ("U64_FORMAT" bytes read so far, " U64_FORMAT" bytes written so far)", tbuf1, tbuf2, (unsigned long)n_seconds_active_in_interval, (unsigned long)(expected_bandwidth_usage*1024/60), U64_PRINTF_ARG(n_bytes_read_in_interval), U64_PRINTF_ARG(n_bytes_written_in_interval)); } return 0; } /** Return true iff we have sent/received all the bytes we are willing * to send/receive this interval. */ static int hibernate_hard_limit_reached(void) { uint64_t hard_limit = get_options()->AccountingMax; if (!hard_limit) return 0; return n_bytes_read_in_interval >= hard_limit || n_bytes_written_in_interval >= hard_limit; } /** Return true iff we have sent/received almost all the bytes we are willing * to send/receive this interval. */ static int hibernate_soft_limit_reached(void) { const uint64_t acct_max = get_options()->AccountingMax; #define SOFT_LIM_PCT (.95) #define SOFT_LIM_BYTES (500*1024*1024) #define SOFT_LIM_MINUTES (3*60) /* The 'soft limit' is a fair bit more complicated now than once it was. * We want to stop accepting connections when ALL of the following are true: * - We expect to use up the remaining bytes in under 3 hours * - We have used up 95% of our bytes. * - We have less than 500MB of bytes left. */ uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(acct_max) * SOFT_LIM_PCT); if (acct_max > SOFT_LIM_BYTES && acct_max - SOFT_LIM_BYTES > soft_limit) { soft_limit = acct_max - SOFT_LIM_BYTES; } if (expected_bandwidth_usage) { const uint64_t expected_usage = expected_bandwidth_usage * SOFT_LIM_MINUTES; if (acct_max > expected_usage && acct_max - expected_usage > soft_limit) soft_limit = acct_max - expected_usage; } if (!soft_limit) return 0; return n_bytes_read_in_interval >= soft_limit || n_bytes_written_in_interval >= soft_limit; } /** Called when we get a SIGINT, or when bandwidth soft limit is * reached. Puts us into "loose hibernation": we don't accept new * connections, but we continue handling old ones. */ static void hibernate_begin(hibernate_state_t new_state, time_t now) { const or_options_t *options = get_options(); if (new_state == HIBERNATE_STATE_EXITING && hibernate_state != HIBERNATE_STATE_LIVE) { log_notice(LD_GENERAL,"SIGINT received %s; exiting now.", hibernate_state == HIBERNATE_STATE_EXITING ? "a second time" : "while hibernating"); tor_cleanup(); exit(0); } if (new_state == HIBERNATE_STATE_LOWBANDWIDTH && hibernate_state == HIBERNATE_STATE_LIVE) { soft_limit_hit_at = now; n_seconds_to_hit_soft_limit = n_seconds_active_in_interval; n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval, n_bytes_written_in_interval); } /* close listeners. leave control listener(s). */ connection_mark_all_noncontrol_listeners(); /* XXX kill intro point circs */ /* XXX upload rendezvous service descriptors with no intro points */ if (new_state == HIBERNATE_STATE_EXITING) { log_notice(LD_GENERAL,"Interrupt: we have stopped accepting new " "connections, and will shut down in %d seconds. Interrupt " "again to exit now.", options->ShutdownWaitLength); shutdown_time = time(NULL) + options->ShutdownWaitLength; } else { /* soft limit reached */ hibernate_end_time = interval_end_time; } hibernate_state = new_state; accounting_record_bandwidth_usage(now, get_or_state()); or_state_mark_dirty(get_or_state(), get_options()->AvoidDiskWrites ? now+600 : 0); } /** Called when we've been hibernating and our timeout is reached. */ static void hibernate_end(hibernate_state_t new_state) { tor_assert(hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH || hibernate_state == HIBERNATE_STATE_DORMANT || hibernate_state == HIBERNATE_STATE_INITIAL); /* listeners will be relaunched in run_scheduled_events() in main.c */ if (hibernate_state != HIBERNATE_STATE_INITIAL) log_notice(LD_ACCT,"Hibernation period ended. Resuming normal activity."); hibernate_state = new_state; hibernate_end_time = 0; /* no longer hibernating */ stats_n_seconds_working = 0; /* reset published uptime */ } /** A wrapper around hibernate_begin, for when we get SIGINT. */ void hibernate_begin_shutdown(void) { hibernate_begin(HIBERNATE_STATE_EXITING, time(NULL)); } /** Return true iff we are currently hibernating. */ int we_are_hibernating(void) { return hibernate_state != HIBERNATE_STATE_LIVE; } /** If we aren't currently dormant, close all connections and become * dormant. */ static void hibernate_go_dormant(time_t now) { connection_t *conn; if (hibernate_state == HIBERNATE_STATE_DORMANT) return; else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) hibernate_state = HIBERNATE_STATE_DORMANT; else hibernate_begin(HIBERNATE_STATE_DORMANT, now); log_notice(LD_ACCT,"Going dormant. Blowing away remaining connections."); /* Close all OR/AP/exit conns. Leave dir conns because we still want * to be able to upload server descriptors so people know we're still * running, and download directories so we can detect if we're obsolete. * Leave control conns because we still want to be controllable. */ while ((conn = connection_get_by_type(CONN_TYPE_OR)) || (conn = connection_get_by_type(CONN_TYPE_AP)) || (conn = connection_get_by_type(CONN_TYPE_EXIT))) { if (CONN_IS_EDGE(conn)) connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_HIBERNATING); log_info(LD_NET,"Closing conn type %d", conn->type); if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */ connection_mark_unattached_ap(TO_ENTRY_CONN(conn), END_STREAM_REASON_HIBERNATING); else if (conn->type == CONN_TYPE_OR) { if (TO_OR_CONN(conn)->chan) { channel_mark_for_close(TLS_CHAN_TO_BASE(TO_OR_CONN(conn)->chan)); } else { connection_mark_for_close(conn); } } else connection_mark_for_close(conn); } if (now < interval_wakeup_time) hibernate_end_time = interval_wakeup_time; else hibernate_end_time = interval_end_time; accounting_record_bandwidth_usage(now, get_or_state()); or_state_mark_dirty(get_or_state(), get_options()->AvoidDiskWrites ? now+600 : 0); } /** Called when hibernate_end_time has arrived. */ static void hibernate_end_time_elapsed(time_t now) { char buf[ISO_TIME_LEN+1]; /* The interval has ended, or it is wakeup time. Find out which. */ accounting_run_housekeeping(now); if (interval_wakeup_time <= now) { /* The interval hasn't changed, but interval_wakeup_time has passed. * It's time to wake up and start being a server. */ hibernate_end(HIBERNATE_STATE_LIVE); return; } else { /* The interval has changed, and it isn't time to wake up yet. */ hibernate_end_time = interval_wakeup_time; format_iso_time(buf,interval_wakeup_time); if (hibernate_state != HIBERNATE_STATE_DORMANT) { /* We weren't sleeping before; we should sleep now. */ log_notice(LD_ACCT, "Accounting period ended. Commencing hibernation until " "%s UTC", buf); hibernate_go_dormant(now); } else { log_notice(LD_ACCT, "Accounting period ended. This period, we will hibernate" " until %s UTC",buf); } } } /** Consider our environment and decide if it's time * to start/stop hibernating. */ void consider_hibernation(time_t now) { int accounting_enabled = get_options()->AccountingMax != 0; char buf[ISO_TIME_LEN+1]; /* If we're in 'exiting' mode, then we just shut down after the interval * elapses. */ if (hibernate_state == HIBERNATE_STATE_EXITING) { tor_assert(shutdown_time); if (shutdown_time <= now) { log_notice(LD_GENERAL, "Clean shutdown finished. Exiting."); tor_cleanup(); exit(0); } return; /* if exiting soon, don't worry about bandwidth limits */ } if (hibernate_state == HIBERNATE_STATE_DORMANT) { /* We've been hibernating because of bandwidth accounting. */ tor_assert(hibernate_end_time); if (hibernate_end_time > now && accounting_enabled) { /* If we're hibernating, don't wake up until it's time, regardless of * whether we're in a new interval. */ return ; } else { hibernate_end_time_elapsed(now); } } /* Else, we aren't hibernating. See if it's time to start hibernating, or to * go dormant. */ if (hibernate_state == HIBERNATE_STATE_LIVE || hibernate_state == HIBERNATE_STATE_INITIAL) { if (hibernate_soft_limit_reached()) { log_notice(LD_ACCT, "Bandwidth soft limit reached; commencing hibernation. " "No new connections will be accepted"); hibernate_begin(HIBERNATE_STATE_LOWBANDWIDTH, now); } else if (accounting_enabled && now < interval_wakeup_time) { format_local_iso_time(buf,interval_wakeup_time); log_notice(LD_ACCT, "Commencing hibernation. We will wake up at %s local time.", buf); hibernate_go_dormant(now); } else if (hibernate_state == HIBERNATE_STATE_INITIAL) { hibernate_end(HIBERNATE_STATE_LIVE); } } if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) { if (!accounting_enabled) { hibernate_end_time_elapsed(now); } else if (hibernate_hard_limit_reached()) { hibernate_go_dormant(now); } else if (hibernate_end_time <= now) { /* The hibernation period ended while we were still in lowbandwidth.*/ hibernate_end_time_elapsed(now); } } } /** Helper function: called when we get a GETINFO request for an * accounting-related key on the control connection conn. If we can * answer the request for question, then set *answer to a newly * allocated string holding the result. Otherwise, set *answer to * NULL. */ int getinfo_helper_accounting(control_connection_t *conn, const char *question, char **answer, const char **errmsg) { (void) conn; (void) errmsg; if (!strcmp(question, "accounting/enabled")) { *answer = tor_strdup(accounting_is_enabled(get_options()) ? "1" : "0"); } else if (!strcmp(question, "accounting/hibernating")) { if (hibernate_state == HIBERNATE_STATE_DORMANT) *answer = tor_strdup("hard"); else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) *answer = tor_strdup("soft"); else *answer = tor_strdup("awake"); } else if (!strcmp(question, "accounting/bytes")) { tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, U64_PRINTF_ARG(n_bytes_read_in_interval), U64_PRINTF_ARG(n_bytes_written_in_interval)); } else if (!strcmp(question, "accounting/bytes-left")) { uint64_t limit = get_options()->AccountingMax; uint64_t read_left = 0, write_left = 0; if (n_bytes_read_in_interval < limit) read_left = limit - n_bytes_read_in_interval; if (n_bytes_written_in_interval < limit) write_left = limit - n_bytes_written_in_interval; tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left)); } else if (!strcmp(question, "accounting/interval-start")) { *answer = tor_malloc(ISO_TIME_LEN+1); format_iso_time(*answer, interval_start_time); } else if (!strcmp(question, "accounting/interval-wake")) { *answer = tor_malloc(ISO_TIME_LEN+1); format_iso_time(*answer, interval_wakeup_time); } else if (!strcmp(question, "accounting/interval-end")) { *answer = tor_malloc(ISO_TIME_LEN+1); format_iso_time(*answer, interval_end_time); } else { *answer = NULL; } return 0; } /** * Manually change the hibernation state. Private; used only by the unit * tests. */ void hibernate_set_state_for_testing_(hibernate_state_t newstate) { hibernate_state = newstate; } tor-0.2.4.20/src/or/dirvote.h0000644000175000017500000001357312255745673012547 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file dirvote.h * \brief Header file for dirvote.c. **/ #ifndef TOR_DIRVOTE_H #define TOR_DIRVOTE_H /** Lowest allowable value for VoteSeconds. */ #define MIN_VOTE_SECONDS 20 /** Lowest allowable value for DistSeconds. */ #define MIN_DIST_SECONDS 20 /** Smallest allowable voting interval. */ #define MIN_VOTE_INTERVAL 300 /** The highest consensus method that we currently support. */ #define MAX_SUPPORTED_CONSENSUS_METHOD 17 /** Lowest consensus method that contains a 'directory-footer' marker */ #define MIN_METHOD_FOR_FOOTER 9 /** Lowest consensus method that contains bandwidth weights */ #define MIN_METHOD_FOR_BW_WEIGHTS 9 /** Lowest consensus method that contains consensus params */ #define MIN_METHOD_FOR_PARAMS 7 /** Lowest consensus method that generates microdescriptors */ #define MIN_METHOD_FOR_MICRODESC 8 /** Lowest consensus method that doesn't count bad exits as exits for weight */ #define MIN_METHOD_TO_CUT_BADEXIT_WEIGHT 11 /** Lowest consensus method that ensures a majority of authorities voted * for a param. */ #define MIN_METHOD_FOR_MAJORITY_PARAMS 12 /** Lowest consensus method where microdesc consensuses omit any entry * with no microdesc. */ #define MIN_METHOD_FOR_MANDATORY_MICRODESC 13 /** Lowest consensus method that contains "a" lines. */ #define MIN_METHOD_FOR_A_LINES 14 /** Lowest consensus method where microdescs may include a "p6" line. */ #define MIN_METHOD_FOR_P6_LINES 15 /** Lowest consensus method where microdescs may include an onion-key-ntor * line */ #define MIN_METHOD_FOR_NTOR_KEY 16 /** Lowest consensus method that ensures that authorities output an * Unmeasured=1 flag for unmeasured bandwidths */ #define MIN_METHOD_TO_CLIP_UNMEASURED_BW 17 /** Default bandwidth to clip unmeasured bandwidths to using method >= * MIN_METHOD_TO_CLIP_UNMEASURED_BW */ #define DEFAULT_MAX_UNMEASURED_BW_KB 20 void dirvote_free_all(void); /* vote manipulation */ char *networkstatus_compute_consensus(smartlist_t *votes, int total_authorities, crypto_pk_t *identity_key, crypto_pk_t *signing_key, const char *legacy_identity_key_digest, crypto_pk_t *legacy_signing_key, consensus_flavor_t flavor); int networkstatus_add_detached_signatures(networkstatus_t *target, ns_detached_signatures_t *sigs, const char *source, int severity, const char **msg_out); char *networkstatus_get_detached_signatures(smartlist_t *consensuses); void ns_detached_signatures_free(ns_detached_signatures_t *s); /* cert manipulation */ authority_cert_t *authority_cert_dup(authority_cert_t *cert); /* vote scheduling */ void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); time_t dirvote_get_start_of_next_interval(time_t now, int interval); void dirvote_recalculate_timing(const or_options_t *options, time_t now); void dirvote_act(const or_options_t *options, time_t now); /* invoked on timers and by outside triggers. */ struct pending_vote_t * dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out); int dirvote_add_signatures(const char *detached_signatures_body, const char *source, const char **msg_out); /* Item access */ const char *dirvote_get_pending_consensus(consensus_flavor_t flav); const char *dirvote_get_pending_detached_signatures(void); #define DGV_BY_ID 1 #define DGV_INCLUDE_PENDING 2 #define DGV_INCLUDE_PREVIOUS 4 const cached_dir_t *dirvote_get_vote(const char *fp, int flags); void set_routerstatus_from_routerinfo(routerstatus_t *rs, node_t *node, routerinfo_t *ri, time_t now, int naming, int listbadexits, int listbaddirs, int vote_on_hsdirs); networkstatus_t * dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, authority_cert_t *cert); microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method); ssize_t dirvote_format_microdesc_vote_line(char *out, size_t out_len, const microdesc_t *md, int consensus_method_low, int consensus_method_high); vote_microdesc_hash_t *dirvote_format_all_microdesc_vote_lines( const routerinfo_t *ri, time_t now, smartlist_t *microdescriptors_out); int vote_routerstatus_find_microdesc_hash(char *digest256_out, const vote_routerstatus_t *vrs, int method, digest_algorithm_t alg); document_signature_t *voter_get_sig_by_algorithm( const networkstatus_voter_info_t *voter, digest_algorithm_t alg); #ifdef DIRVOTE_PRIVATE char *format_networkstatus_vote(crypto_pk_t *private_key, networkstatus_t *v3_ns); char *dirvote_compute_params(smartlist_t *votes, int method, int total_authorities); #endif #endif tor-0.2.4.20/src/or/routerparse.c0000644000175000017500000053222612255745673013442 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file routerparse.c * \brief Code to parse and validate router descriptors and directories. **/ #include "or.h" #include "config.h" #include "circuitstats.h" #include "dirserv.h" #include "dirvote.h" #include "policies.h" #include "rendcommon.h" #include "router.h" #include "routerlist.h" #include "memarea.h" #include "microdesc.h" #include "networkstatus.h" #include "rephist.h" #include "routerparse.h" #undef log #include /****************************************************************************/ /** Enumeration of possible token types. The ones starting with K_ correspond * to directory 'keywords'. ERR_ is an error in the tokenizing process, EOF_ * is an end-of-file marker, and NIL_ is used to encode not-a-token. */ typedef enum { K_ACCEPT = 0, K_ACCEPT6, K_DIRECTORY_SIGNATURE, K_RECOMMENDED_SOFTWARE, K_REJECT, K_REJECT6, K_ROUTER, K_SIGNED_DIRECTORY, K_SIGNING_KEY, K_ONION_KEY, K_ONION_KEY_NTOR, K_ROUTER_SIGNATURE, K_PUBLISHED, K_RUNNING_ROUTERS, K_ROUTER_STATUS, K_PLATFORM, K_OPT, K_BANDWIDTH, K_CONTACT, K_NETWORK_STATUS, K_UPTIME, K_DIR_SIGNING_KEY, K_FAMILY, K_FINGERPRINT, K_HIBERNATING, K_READ_HISTORY, K_WRITE_HISTORY, K_NETWORK_STATUS_VERSION, K_DIR_SOURCE, K_DIR_OPTIONS, K_CLIENT_VERSIONS, K_SERVER_VERSIONS, K_OR_ADDRESS, K_P, K_P6, K_R, K_A, K_S, K_V, K_W, K_M, K_EXTRA_INFO, K_EXTRA_INFO_DIGEST, K_CACHES_EXTRA_INFO, K_HIDDEN_SERVICE_DIR, K_ALLOW_SINGLE_HOP_EXITS, K_IPV6_POLICY, K_DIRREQ_END, K_DIRREQ_V2_IPS, K_DIRREQ_V3_IPS, K_DIRREQ_V2_REQS, K_DIRREQ_V3_REQS, K_DIRREQ_V2_SHARE, K_DIRREQ_V3_SHARE, K_DIRREQ_V2_RESP, K_DIRREQ_V3_RESP, K_DIRREQ_V2_DIR, K_DIRREQ_V3_DIR, K_DIRREQ_V2_TUN, K_DIRREQ_V3_TUN, K_ENTRY_END, K_ENTRY_IPS, K_CELL_END, K_CELL_PROCESSED, K_CELL_QUEUED, K_CELL_TIME, K_CELL_CIRCS, K_EXIT_END, K_EXIT_WRITTEN, K_EXIT_READ, K_EXIT_OPENED, K_DIR_KEY_CERTIFICATE_VERSION, K_DIR_IDENTITY_KEY, K_DIR_KEY_PUBLISHED, K_DIR_KEY_EXPIRES, K_DIR_KEY_CERTIFICATION, K_DIR_KEY_CROSSCERT, K_DIR_ADDRESS, K_VOTE_STATUS, K_VALID_AFTER, K_FRESH_UNTIL, K_VALID_UNTIL, K_VOTING_DELAY, K_KNOWN_FLAGS, K_PARAMS, K_BW_WEIGHTS, K_VOTE_DIGEST, K_CONSENSUS_DIGEST, K_ADDITIONAL_DIGEST, K_ADDITIONAL_SIGNATURE, K_CONSENSUS_METHODS, K_CONSENSUS_METHOD, K_LEGACY_DIR_KEY, K_DIRECTORY_FOOTER, A_PURPOSE, A_LAST_LISTED, A_UNKNOWN_, R_RENDEZVOUS_SERVICE_DESCRIPTOR, R_VERSION, R_PERMANENT_KEY, R_SECRET_ID_PART, R_PUBLICATION_TIME, R_PROTOCOL_VERSIONS, R_INTRODUCTION_POINTS, R_SIGNATURE, R_IPO_IDENTIFIER, R_IPO_IP_ADDRESS, R_IPO_ONION_PORT, R_IPO_ONION_KEY, R_IPO_SERVICE_KEY, C_CLIENT_NAME, C_DESCRIPTOR_COOKIE, C_CLIENT_KEY, ERR_, EOF_, NIL_ } directory_keyword; #define MIN_ANNOTATION A_PURPOSE #define MAX_ANNOTATION A_UNKNOWN_ /** Structure to hold a single directory token. * * We parse a directory by breaking it into "tokens", each consisting * of a keyword, a line full of arguments, and a binary object. The * arguments and object are both optional, depending on the keyword * type. * * This structure is only allocated in memareas; do not allocate it on * the heap, or token_clear() won't work. */ typedef struct directory_token_t { directory_keyword tp; /**< Type of the token. */ int n_args:30; /**< Number of elements in args */ char **args; /**< Array of arguments from keyword line. */ char *object_type; /**< -----BEGIN [object_type]-----*/ size_t object_size; /**< Bytes in object_body */ char *object_body; /**< Contents of object, base64-decoded. */ crypto_pk_t *key; /**< For public keys only. Heap-allocated. */ char *error; /**< For ERR_ tokens only. */ } directory_token_t; /* ********************************************************************** */ /** We use a table of rules to decide how to parse each token type. */ /** Rules for whether the keyword needs an object. */ typedef enum { NO_OBJ, /**< No object, ever. */ NEED_OBJ, /**< Object is required. */ NEED_SKEY_1024,/**< Object is required, and must be a 1024 bit private key */ NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */ NEED_KEY, /**< Object is required, and must be a public key. */ OBJ_OK, /**< Object is optional. */ } obj_syntax; #define AT_START 1 #define AT_END 2 /** Determines the parsing rules for a single token type. */ typedef struct token_rule_t { /** The string value of the keyword identifying the type of item. */ const char *t; /** The corresponding directory_keyword enum. */ directory_keyword v; /** Minimum number of arguments for this item */ int min_args; /** Maximum number of arguments for this item */ int max_args; /** If true, we concatenate all arguments for this item into a single * string. */ int concat_args; /** Requirements on object syntax for this item. */ obj_syntax os; /** Lowest number of times this item may appear in a document. */ int min_cnt; /** Highest number of times this item may appear in a document. */ int max_cnt; /** One or more of AT_START/AT_END to limit where the item may appear in a * document. */ int pos; /** True iff this token is an annotation. */ int is_annotation; } token_rule_t; /* * Helper macros to define token tables. 's' is a string, 't' is a * directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an * object syntax. * */ /** Appears to indicate the end of a table. */ #define END_OF_TABLE { NULL, NIL_, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 } /** An item with no restrictions: used for obsolete document types */ #define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 } /** An item with no restrictions on multiplicity or location. */ #define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 } /** An item that must appear exactly once */ #define T1(s,t,a,o) { s, t, a, o, 1, 1, 0, 0 } /** An item that must appear exactly once, at the start of the document */ #define T1_START(s,t,a,o) { s, t, a, o, 1, 1, AT_START, 0 } /** An item that must appear exactly once, at the end of the document */ #define T1_END(s,t,a,o) { s, t, a, o, 1, 1, AT_END, 0 } /** An item that must appear one or more times */ #define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0, 0 } /** An item that must appear no more than once */ #define T01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 } /** An annotation that must appear no more than once */ #define A01(s,t,a,o) { s, t, a, o, 0, 1, 0, 1 } /* Argument multiplicity: any number of arguments. */ #define ARGS 0,INT_MAX,0 /* Argument multiplicity: no arguments. */ #define NO_ARGS 0,0,0 /* Argument multiplicity: concatenate all arguments. */ #define CONCAT_ARGS 1,1,1 /* Argument multiplicity: at least n arguments. */ #define GE(n) n,INT_MAX,0 /* Argument multiplicity: exactly n arguments. */ #define EQ(n) n,n,0 /** List of tokens recognized in router descriptors */ static token_rule_t routerdesc_token_table[] = { T0N("reject", K_REJECT, ARGS, NO_OBJ ), T0N("accept", K_ACCEPT, ARGS, NO_OBJ ), T0N("reject6", K_REJECT6, ARGS, NO_OBJ ), T0N("accept6", K_ACCEPT6, ARGS, NO_OBJ ), T1_START( "router", K_ROUTER, GE(5), NO_OBJ ), T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ), T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ), T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ), T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ), T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ), T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), T01("uptime", K_UPTIME, GE(1), NO_OBJ ), T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ ), T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ), T01("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ), T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ), T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ), T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), NO_OBJ ), T01("hidden-service-dir", K_HIDDEN_SERVICE_DIR, NO_ARGS, NO_OBJ ), T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS, NO_ARGS, NO_OBJ ), T01("family", K_FAMILY, ARGS, NO_OBJ ), T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ), T0N("or-address", K_OR_ADDRESS, GE(1), NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T1( "bandwidth", K_BANDWIDTH, GE(3), NO_OBJ ), A01("@purpose", A_PURPOSE, GE(1), NO_OBJ ), END_OF_TABLE }; /** List of tokens recognized in extra-info documents. */ static token_rule_t extrainfo_token_table[] = { T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ), T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ), T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ), T01("dirreq-stats-end", K_DIRREQ_END, ARGS, NO_OBJ ), T01("dirreq-v2-ips", K_DIRREQ_V2_IPS, ARGS, NO_OBJ ), T01("dirreq-v3-ips", K_DIRREQ_V3_IPS, ARGS, NO_OBJ ), T01("dirreq-v2-reqs", K_DIRREQ_V2_REQS, ARGS, NO_OBJ ), T01("dirreq-v3-reqs", K_DIRREQ_V3_REQS, ARGS, NO_OBJ ), T01("dirreq-v2-share", K_DIRREQ_V2_SHARE, ARGS, NO_OBJ ), T01("dirreq-v3-share", K_DIRREQ_V3_SHARE, ARGS, NO_OBJ ), T01("dirreq-v2-resp", K_DIRREQ_V2_RESP, ARGS, NO_OBJ ), T01("dirreq-v3-resp", K_DIRREQ_V3_RESP, ARGS, NO_OBJ ), T01("dirreq-v2-direct-dl", K_DIRREQ_V2_DIR, ARGS, NO_OBJ ), T01("dirreq-v3-direct-dl", K_DIRREQ_V3_DIR, ARGS, NO_OBJ ), T01("dirreq-v2-tunneled-dl", K_DIRREQ_V2_TUN, ARGS, NO_OBJ ), T01("dirreq-v3-tunneled-dl", K_DIRREQ_V3_TUN, ARGS, NO_OBJ ), T01("entry-stats-end", K_ENTRY_END, ARGS, NO_OBJ ), T01("entry-ips", K_ENTRY_IPS, ARGS, NO_OBJ ), T01("cell-stats-end", K_CELL_END, ARGS, NO_OBJ ), T01("cell-processed-cells", K_CELL_PROCESSED, ARGS, NO_OBJ ), T01("cell-queued-cells", K_CELL_QUEUED, ARGS, NO_OBJ ), T01("cell-time-in-queue", K_CELL_TIME, ARGS, NO_OBJ ), T01("cell-circuits-per-decile", K_CELL_CIRCS, ARGS, NO_OBJ ), T01("exit-stats-end", K_EXIT_END, ARGS, NO_OBJ ), T01("exit-kibibytes-written", K_EXIT_WRITTEN, ARGS, NO_OBJ ), T01("exit-kibibytes-read", K_EXIT_READ, ARGS, NO_OBJ ), T01("exit-streams-opened", K_EXIT_OPENED, ARGS, NO_OBJ ), T1_START( "extra-info", K_EXTRA_INFO, GE(2), NO_OBJ ), END_OF_TABLE }; /** List of tokens recognized in the body part of v2 and v3 networkstatus * documents. */ static token_rule_t rtrstatus_token_table[] = { T01("p", K_P, CONCAT_ARGS, NO_OBJ ), T1( "r", K_R, GE(7), NO_OBJ ), T0N("a", K_A, GE(1), NO_OBJ ), T1( "s", K_S, ARGS, NO_OBJ ), T01("v", K_V, CONCAT_ARGS, NO_OBJ ), T01("w", K_W, ARGS, NO_OBJ ), T0N("m", K_M, CONCAT_ARGS, NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), END_OF_TABLE }; /** List of tokens recognized in the header part of v2 networkstatus documents. */ static token_rule_t netstatus_token_table[] = { T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ), T1( "dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ), T1( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), T1_START("network-status-version", K_NETWORK_STATUS_VERSION, GE(1), NO_OBJ ), T1( "dir-source", K_DIR_SOURCE, GE(3), NO_OBJ ), T01("dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ ), T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ), T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ), END_OF_TABLE }; /** List of tokens recognized in the footer of v1/v2 directory/networkstatus * footers. */ static token_rule_t dir_footer_token_table[] = { T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ), END_OF_TABLE }; /** List of tokens common to V3 authority certificates and V3 consensuses. */ #define CERTIFICATE_MEMBERS \ T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \ GE(1), NO_OBJ ), \ T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),\ T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), \ T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), \ T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\ T01("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),\ T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, \ NO_ARGS, NEED_OBJ), \ T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ), /** List of tokens recognized in V3 authority certificates. */ static token_rule_t dir_key_certificate_table[] = { CERTIFICATE_MEMBERS T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), END_OF_TABLE }; /** List of tokens recognized in rendezvous service descriptors */ static token_rule_t desc_token_table[] = { T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR, EQ(1), NO_OBJ), T1("version", R_VERSION, EQ(1), NO_OBJ), T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024), T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ), T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ), T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ), T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ), T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ), END_OF_TABLE }; /** List of tokens recognized in the (encrypted) list of introduction points of * rendezvous service descriptors */ static token_rule_t ipo_token_table[] = { T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ), T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ), T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ), T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024), T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024), END_OF_TABLE }; /** List of tokens recognized in the (possibly encrypted) list of introduction * points of rendezvous service descriptors */ static token_rule_t client_keys_token_table[] = { T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ), T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ), T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024), END_OF_TABLE }; /** List of tokens recognized in V3 networkstatus votes. */ static token_rule_t networkstatus_token_table[] = { T1_START("network-status-version", K_NETWORK_STATUS_VERSION, GE(1), NO_OBJ ), T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ), T1("published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ), T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ), T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ), T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ), T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ), T01("params", K_PARAMS, ARGS, NO_OBJ ), T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), CERTIFICATE_MEMBERS T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ), T1( "dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ), T01("legacy-dir-key", K_LEGACY_DIR_KEY, GE(1), NO_OBJ ), T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ), T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ), T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ), T1( "consensus-methods", K_CONSENSUS_METHODS, GE(1), NO_OBJ ), END_OF_TABLE }; /** List of tokens recognized in V3 networkstatus consensuses. */ static token_rule_t networkstatus_consensus_token_table[] = { T1_START("network-status-version", K_NETWORK_STATUS_VERSION, GE(1), NO_OBJ ), T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ), T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ), T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ), T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ), T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T1N("dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ), T1N("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ), T1N("vote-digest", K_VOTE_DIGEST, GE(1), NO_OBJ ), T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ), T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ), T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ), T01("consensus-method", K_CONSENSUS_METHOD, EQ(1), NO_OBJ), T01("params", K_PARAMS, ARGS, NO_OBJ ), END_OF_TABLE }; /** List of tokens recognized in the footer of v1/v2 directory/networkstatus * footers. */ static token_rule_t networkstatus_vote_footer_token_table[] = { T01("directory-footer", K_DIRECTORY_FOOTER, NO_ARGS, NO_OBJ ), T01("bandwidth-weights", K_BW_WEIGHTS, ARGS, NO_OBJ ), T( "directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ), END_OF_TABLE }; /** List of tokens recognized in detached networkstatus signature documents. */ static token_rule_t networkstatus_detached_signature_token_table[] = { T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1), NO_OBJ ), T("additional-digest", K_ADDITIONAL_DIGEST,GE(3), NO_OBJ ), T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ), T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ), T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ), T("additional-signature", K_ADDITIONAL_SIGNATURE, GE(4), NEED_OBJ ), T1N("directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ), END_OF_TABLE }; /** List of tokens recognized in microdescriptors */ static token_rule_t microdesc_token_table[] = { T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024), T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ), T0N("a", K_A, GE(1), NO_OBJ ), T01("family", K_FAMILY, ARGS, NO_OBJ ), T01("p", K_P, CONCAT_ARGS, NO_OBJ ), T01("p6", K_P6, CONCAT_ARGS, NO_OBJ ), A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ), END_OF_TABLE }; #undef T /* static function prototypes */ static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok); static addr_policy_t *router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags); static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok); static int router_get_hash_impl(const char *s, size_t s_len, char *digest, const char *start_str, const char *end_str, char end_char, digest_algorithm_t alg); static int router_get_hashes_impl(const char *s, size_t s_len, digests_t *digests, const char *start_str, const char *end_str, char end_char); static void token_clear(directory_token_t *tok); static smartlist_t *find_all_by_keyword(smartlist_t *s, directory_keyword k); static smartlist_t *find_all_exitpolicy(smartlist_t *s); static directory_token_t *find_by_keyword_(smartlist_t *s, directory_keyword keyword, const char *keyword_str); #define find_by_keyword(s, keyword) find_by_keyword_((s), (keyword), #keyword) static directory_token_t *find_opt_by_keyword(smartlist_t *s, directory_keyword keyword); #define TS_ANNOTATIONS_OK 1 #define TS_NOCHECK 2 #define TS_NO_NEW_ANNOTATIONS 4 static int tokenize_string(memarea_t *area, const char *start, const char *end, smartlist_t *out, token_rule_t *table, int flags); static directory_token_t *get_next_token(memarea_t *area, const char **s, const char *eos, token_rule_t *table); #define CST_CHECK_AUTHORITY (1<<0) #define CST_NO_CHECK_OBJTYPE (1<<1) static int check_signature_token(const char *digest, ssize_t digest_len, directory_token_t *tok, crypto_pk_t *pkey, int flags, const char *doctype); #undef DEBUG_AREA_ALLOC #ifdef DEBUG_AREA_ALLOC #define DUMP_AREA(a,name) STMT_BEGIN \ size_t alloc=0, used=0; \ memarea_get_stats((a),&alloc,&used); \ log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.", \ name, (unsigned long)alloc, (unsigned long)used); \ STMT_END #else #define DUMP_AREA(a,name) STMT_NIL #endif /** Last time we dumped a descriptor to disk. */ static time_t last_desc_dumped = 0; /** For debugging purposes, dump unparseable descriptor *desc of * type *type to file $DATADIR/unparseable-desc. Do not write more * than one descriptor to disk per minute. If there is already such a * file in the data directory, overwrite it. */ static void dump_desc(const char *desc, const char *type) { time_t now = time(NULL); tor_assert(desc); tor_assert(type); if (!last_desc_dumped || last_desc_dumped + 60 < now) { char *debugfile = get_datadir_fname("unparseable-desc"); size_t filelen = 50 + strlen(type) + strlen(desc); char *content = tor_malloc_zero(filelen); tor_snprintf(content, filelen, "Unable to parse descriptor of type " "%s:\n%s", type, desc); write_str_to_file(debugfile, content, 0); log_info(LD_DIR, "Unable to parse descriptor of type %s. See file " "unparseable-desc in data directory for details.", type); tor_free(content); tor_free(debugfile); last_desc_dumped = now; } } /** Set digest to the SHA-1 digest of the hash of the directory in * s. Return 0 on success, -1 on failure. */ int router_get_dir_hash(const char *s, char *digest) { return router_get_hash_impl(s, strlen(s), digest, "signed-directory","\ndirectory-signature",'\n', DIGEST_SHA1); } /** Set digest to the SHA-1 digest of the hash of the first router in * s. Return 0 on success, -1 on failure. */ int router_get_router_hash(const char *s, size_t s_len, char *digest) { return router_get_hash_impl(s, s_len, digest, "router ","\nrouter-signature", '\n', DIGEST_SHA1); } /** Set digest to the SHA-1 digest of the hash of the running-routers * string in s. Return 0 on success, -1 on failure. */ int router_get_runningrouters_hash(const char *s, char *digest) { return router_get_hash_impl(s, strlen(s), digest, "network-status","\ndirectory-signature", '\n', DIGEST_SHA1); } /** Set digest to the SHA-1 digest of the hash of the network-status * string in s. Return 0 on success, -1 on failure. */ int router_get_networkstatus_v2_hash(const char *s, char *digest) { return router_get_hash_impl(s, strlen(s), digest, "network-status-version","\ndirectory-signature", '\n', DIGEST_SHA1); } /** Set digests to all the digests of the consensus document in * s */ int router_get_networkstatus_v3_hashes(const char *s, digests_t *digests) { return router_get_hashes_impl(s,strlen(s),digests, "network-status-version", "\ndirectory-signature", ' '); } /** Set digest to the SHA-1 digest of the hash of the s_len-byte * extrainfo string at s. Return 0 on success, -1 on failure. */ int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest) { return router_get_hash_impl(s, s_len, digest, "extra-info", "\nrouter-signature",'\n', DIGEST_SHA1); } /** Helper: used to generate signatures for routers, directories and * network-status objects. Given a digest_len-byte digest in * digest and a secret private_key, generate an PKCS1-padded * signature, BASE64-encode it, surround it with -----BEGIN/END----- pairs, * and return the new signature on success or NULL on failure. */ char * router_get_dirobj_signature(const char *digest, size_t digest_len, crypto_pk_t *private_key) { char *signature; size_t i, keysize; int siglen; char *buf = NULL; size_t buf_len; /* overestimate of BEGIN/END lines total len. */ #define BEGIN_END_OVERHEAD_LEN 64 keysize = crypto_pk_keysize(private_key); signature = tor_malloc(keysize); siglen = crypto_pk_private_sign(private_key, signature, keysize, digest, digest_len); if (siglen < 0) { log_warn(LD_BUG,"Couldn't sign digest."); goto err; } /* The *2 here is a ridiculous overestimate of base-64 overhead. */ buf_len = (siglen * 2) + BEGIN_END_OVERHEAD_LEN; buf = tor_malloc(buf_len); if (strlcpy(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len) goto truncated; i = strlen(buf); if (base64_encode(buf+i, buf_len-i, signature, siglen) < 0) { log_warn(LD_BUG,"couldn't base64-encode signature"); goto err; } if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len) goto truncated; tor_free(signature); return buf; truncated: log_warn(LD_BUG,"tried to exceed string length."); err: tor_free(signature); tor_free(buf); return NULL; } /** Helper: used to generate signatures for routers, directories and * network-status objects. Given a digest in digest and a secret * private_key, generate an PKCS1-padded signature, BASE64-encode it, * surround it with -----BEGIN/END----- pairs, and write it to the * buf_len-byte buffer at buf. Return 0 on success, -1 on * failure. */ int router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, size_t digest_len, crypto_pk_t *private_key) { size_t sig_len, s_len; char *sig = router_get_dirobj_signature(digest, digest_len, private_key); if (!sig) { log_warn(LD_BUG, "No signature generated"); return -1; } sig_len = strlen(sig); s_len = strlen(buf); if (sig_len + s_len + 1 > buf_len) { log_warn(LD_BUG, "Not enough room for signature"); tor_free(sig); return -1; } memcpy(buf+s_len, sig, sig_len+1); return 0; } /** Return VS_RECOMMENDED if myversion is contained in * versionlist. Else, return VS_EMPTY if versionlist has no * entries. Else, return VS_OLD if every member of * versionlist is newer than myversion. Else, return * VS_NEW_IN_SERIES if there is at least one member of versionlist in * the same series (major.minor.micro) as myversion, but no such member * is newer than myversion.. Else, return VS_NEW if every member of * versionlist is older than myversion. Else, return * VS_UNRECOMMENDED. * * (versionlist is a comma-separated list of version strings, * optionally prefixed with "Tor". Versions that can't be parsed are * ignored.) */ version_status_t tor_version_is_obsolete(const char *myversion, const char *versionlist) { tor_version_t mine, other; int found_newer = 0, found_older = 0, found_newer_in_series = 0, found_any_in_series = 0, r, same; version_status_t ret = VS_UNRECOMMENDED; smartlist_t *version_sl; log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'", myversion, versionlist); if (tor_version_parse(myversion, &mine)) { log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion); tor_assert(0); } version_sl = smartlist_new(); smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0); if (!strlen(versionlist)) { /* no authorities cared or agreed */ ret = VS_EMPTY; goto done; } SMARTLIST_FOREACH_BEGIN(version_sl, const char *, cp) { if (!strcmpstart(cp, "Tor ")) cp += 4; if (tor_version_parse(cp, &other)) { /* Couldn't parse other; it can't be a match. */ } else { same = tor_version_same_series(&mine, &other); if (same) found_any_in_series = 1; r = tor_version_compare(&mine, &other); if (r==0) { ret = VS_RECOMMENDED; goto done; } else if (r<0) { found_newer = 1; if (same) found_newer_in_series = 1; } else if (r>0) { found_older = 1; } } } SMARTLIST_FOREACH_END(cp); /* We didn't find the listed version. Is it new or old? */ if (found_any_in_series && !found_newer_in_series && found_newer) { ret = VS_NEW_IN_SERIES; } else if (found_newer && !found_older) { ret = VS_OLD; } else if (found_older && !found_newer) { ret = VS_NEW; } else { ret = VS_UNRECOMMENDED; } done: SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version)); smartlist_free(version_sl); return ret; } /** Return true iff key is allowed to sign directories. */ static int dir_signing_key_is_trusted(crypto_pk_t *key) { char digest[DIGEST_LEN]; if (!key) return 0; if (crypto_pk_get_digest(key, digest) < 0) { log_warn(LD_DIR, "Error computing dir-signing-key digest"); return 0; } if (!router_digest_is_trusted_dir(digest)) { log_warn(LD_DIR, "Listed dir-signing-key is not trusted"); return 0; } return 1; } /** Check whether the object body of the token in tok has a good * signature for digest using key pkey. If * CST_CHECK_AUTHORITY is set, make sure that pkey is the key of * a directory authority. If CST_NO_CHECK_OBJTYPE is set, do not check * the object type of the signature object. Use doctype as the type of * the document when generating log messages. Return 0 on success, negative * on failure. */ static int check_signature_token(const char *digest, ssize_t digest_len, directory_token_t *tok, crypto_pk_t *pkey, int flags, const char *doctype) { char *signed_digest; size_t keysize; const int check_authority = (flags & CST_CHECK_AUTHORITY); const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE); tor_assert(pkey); tor_assert(tok); tor_assert(digest); tor_assert(doctype); if (check_authority && !dir_signing_key_is_trusted(pkey)) { log_warn(LD_DIR, "Key on %s did not come from an authority; rejecting", doctype); return -1; } if (check_objtype) { if (strcmp(tok->object_type, "SIGNATURE")) { log_warn(LD_DIR, "Bad object type on %s signature", doctype); return -1; } } keysize = crypto_pk_keysize(pkey); signed_digest = tor_malloc(keysize); if (crypto_pk_public_checksig(pkey, signed_digest, keysize, tok->object_body, tok->object_size) < digest_len) { log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype); tor_free(signed_digest); return -1; } // log_debug(LD_DIR,"Signed %s hash starts %s", doctype, // hex_str(signed_digest,4)); if (tor_memneq(digest, signed_digest, digest_len)) { log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype); tor_free(signed_digest); return -1; } tor_free(signed_digest); return 0; } /** Helper: move *s_ptr ahead to the next router, the next extra-info, * or to the first of the annotations proceeding the next router or * extra-info---whichever comes first. Set is_extrainfo_out to true if * we found an extrainfo, or false if found a router. Do not scan beyond * eos. Return -1 if we found nothing; 0 if we found something. */ static int find_start_of_next_router_or_extrainfo(const char **s_ptr, const char *eos, int *is_extrainfo_out) { const char *annotations = NULL; const char *s = *s_ptr; s = eat_whitespace_eos(s, eos); while (s < eos-32) { /* 32 gives enough room for a the first keyword. */ /* We're at the start of a line. */ tor_assert(*s != '\n'); if (*s == '@' && !annotations) { annotations = s; } else if (*s == 'r' && !strcmpstart(s, "router ")) { *s_ptr = annotations ? annotations : s; *is_extrainfo_out = 0; return 0; } else if (*s == 'e' && !strcmpstart(s, "extra-info ")) { *s_ptr = annotations ? annotations : s; *is_extrainfo_out = 1; return 0; } if (!(s = memchr(s+1, '\n', eos-(s+1)))) break; s = eat_whitespace_eos(s, eos); } return -1; } /** Given a string *s containing a concatenated sequence of router * descriptors (or extra-info documents if is_extrainfo is set), parses * them and stores the result in dest. All routers are marked running * and valid. Advances *s to a point immediately following the last router * entry. Ignore any trailing router entries that are not complete. * * If saved_location isn't SAVED_IN_CACHE, make a local copy of each * descriptor in the signed_descriptor_body field of each routerinfo_t. If it * isn't SAVED_NOWHERE, remember the offset of each descriptor. * * Returns 0 on success and -1 on failure. */ int router_parse_list_from_string(const char **s, const char *eos, smartlist_t *dest, saved_location_t saved_location, int want_extrainfo, int allow_annotations, const char *prepend_annotations) { routerinfo_t *router; extrainfo_t *extrainfo; signed_descriptor_t *signed_desc; void *elt; const char *end, *start; int have_extrainfo; tor_assert(s); tor_assert(*s); tor_assert(dest); start = *s; if (!eos) eos = *s + strlen(*s); tor_assert(eos >= *s); while (1) { if (find_start_of_next_router_or_extrainfo(s, eos, &have_extrainfo) < 0) break; end = tor_memstr(*s, eos-*s, "\nrouter-signature"); if (end) end = tor_memstr(end, eos-end, "\n-----END SIGNATURE-----\n"); if (end) end += strlen("\n-----END SIGNATURE-----\n"); if (!end) break; elt = NULL; if (have_extrainfo && want_extrainfo) { routerlist_t *rl = router_get_routerlist(); extrainfo = extrainfo_parse_entry_from_string(*s, end, saved_location != SAVED_IN_CACHE, rl->identity_map); if (extrainfo) { signed_desc = &extrainfo->cache_info; elt = extrainfo; } } else if (!have_extrainfo && !want_extrainfo) { router = router_parse_entry_from_string(*s, end, saved_location != SAVED_IN_CACHE, allow_annotations, prepend_annotations); if (router) { log_debug(LD_DIR, "Read router '%s', purpose '%s'", router_describe(router), router_purpose_to_string(router->purpose)); signed_desc = &router->cache_info; elt = router; } } if (!elt) { *s = end; continue; } if (saved_location != SAVED_NOWHERE) { signed_desc->saved_location = saved_location; signed_desc->saved_offset = *s - start; } *s = end; smartlist_add(dest, elt); } return 0; } /* For debugging: define to count every descriptor digest we've seen so we * know if we need to try harder to avoid duplicate verifies. */ #undef COUNT_DISTINCT_DIGESTS #ifdef COUNT_DISTINCT_DIGESTS static digestmap_t *verified_digests = NULL; #endif /** Log the total count of the number of distinct router digests we've ever * verified. When compared to the number of times we've verified routerdesc * signatures in toto, this will tell us if we're doing too much * multiple-verification. */ void dump_distinct_digest_count(int severity) { #ifdef COUNT_DISTINCT_DIGESTS if (!verified_digests) verified_digests = digestmap_new(); tor_log(severity, LD_GENERAL, "%d *distinct* router digests verified", digestmap_size(verified_digests)); #else (void)severity; /* suppress "unused parameter" warning */ #endif } /** Try to find an IPv6 OR port in list of directory_token_t's * with at least one argument (use GE(1) in setup). If found, store * address and port number to addr_out and * port_out. Return number of OR ports found. */ static int find_single_ipv6_orport(const smartlist_t *list, tor_addr_t *addr_out, uint16_t *port_out) { int ret = 0; tor_assert(list != NULL); tor_assert(addr_out != NULL); tor_assert(port_out != NULL); SMARTLIST_FOREACH_BEGIN(list, directory_token_t *, t) { tor_addr_t a; maskbits_t bits; uint16_t port_min, port_max; tor_assert(t->n_args >= 1); /* XXXX Prop186 the full spec allows much more than this. */ if (tor_addr_parse_mask_ports(t->args[0], 0, &a, &bits, &port_min, &port_max) == AF_INET6 && bits == 128 && port_min == port_max) { /* Okay, this is one we can understand. Use it and ignore any potential more addresses in list. */ tor_addr_copy(addr_out, &a); *port_out = port_min; ret = 1; break; } } SMARTLIST_FOREACH_END(t); return ret; } /** Helper function: reads a single router entry from *s ... * *end. Mallocs a new router and returns it if all goes well, else * returns NULL. If cache_copy is true, duplicate the contents of * s through end into the signed_descriptor_body of the resulting * routerinfo_t. * * If end is NULL, s must be properly NUL-terminated. * * If allow_annotations, it's okay to encounter annotations in s * before the router; if it's false, reject the router if it's annotated. If * prepend_annotations is set, it should contain some annotations: * append them to the front of the router before parsing it, and keep them * around when caching the router. * * Only one of allow_annotations and prepend_annotations may be set. */ routerinfo_t * router_parse_entry_from_string(const char *s, const char *end, int cache_copy, int allow_annotations, const char *prepend_annotations) { routerinfo_t *router = NULL; char digest[128]; smartlist_t *tokens = NULL, *exit_policy_tokens = NULL; directory_token_t *tok; struct in_addr in; const char *start_of_annotations, *cp, *s_dup = s; size_t prepend_len = prepend_annotations ? strlen(prepend_annotations) : 0; int ok = 1; memarea_t *area = NULL; tor_assert(!allow_annotations || !prepend_annotations); if (!end) { end = s + strlen(s); } /* point 'end' to a point immediately after the final newline. */ while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n') --end; area = memarea_new(); tokens = smartlist_new(); if (prepend_annotations) { if (tokenize_string(area,prepend_annotations,NULL,tokens, routerdesc_token_table,TS_NOCHECK)) { log_warn(LD_DIR, "Error tokenizing router descriptor (annotations)."); goto err; } } start_of_annotations = s; cp = tor_memstr(s, end-s, "\nrouter "); if (!cp) { if (end-s < 7 || strcmpstart(s, "router ")) { log_warn(LD_DIR, "No router keyword found."); goto err; } } else { s = cp+1; } if (start_of_annotations != s) { /* We have annotations */ if (allow_annotations) { if (tokenize_string(area,start_of_annotations,s,tokens, routerdesc_token_table,TS_NOCHECK)) { log_warn(LD_DIR, "Error tokenizing router descriptor (annotations)."); goto err; } } else { log_warn(LD_DIR, "Found unexpected annotations on router descriptor not " "loaded from disk. Dropping it."); goto err; } } if (router_get_router_hash(s, end - s, digest) < 0) { log_warn(LD_DIR, "Couldn't compute router hash."); goto err; } { int flags = 0; if (allow_annotations) flags |= TS_ANNOTATIONS_OK; if (prepend_annotations) flags |= TS_ANNOTATIONS_OK|TS_NO_NEW_ANNOTATIONS; if (tokenize_string(area,s,end,tokens,routerdesc_token_table, flags)) { log_warn(LD_DIR, "Error tokenizing router descriptor."); goto err; } } if (smartlist_len(tokens) < 2) { log_warn(LD_DIR, "Impossibly short router descriptor."); goto err; } tok = find_by_keyword(tokens, K_ROUTER); tor_assert(tok->n_args >= 5); router = tor_malloc_zero(sizeof(routerinfo_t)); router->cache_info.routerlist_index = -1; router->cache_info.annotations_len = s-start_of_annotations + prepend_len; router->cache_info.signed_descriptor_len = end-s; if (cache_copy) { size_t len = router->cache_info.signed_descriptor_len + router->cache_info.annotations_len; char *cp = router->cache_info.signed_descriptor_body = tor_malloc(len+1); if (prepend_annotations) { memcpy(cp, prepend_annotations, prepend_len); cp += prepend_len; } /* This assertion will always succeed. * len == signed_desc_len + annotations_len * == end-s + s-start_of_annotations + prepend_len * == end-start_of_annotations + prepend_len * We already wrote prepend_len bytes into the buffer; now we're * writing end-start_of_annotations -NM. */ tor_assert(cp+(end-start_of_annotations) == router->cache_info.signed_descriptor_body+len); memcpy(cp, start_of_annotations, end-start_of_annotations); router->cache_info.signed_descriptor_body[len] = '\0'; tor_assert(strlen(router->cache_info.signed_descriptor_body) == len); } memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN); router->nickname = tor_strdup(tok->args[0]); if (!is_legal_nickname(router->nickname)) { log_warn(LD_DIR,"Router nickname is invalid"); goto err; } router->address = tor_strdup(tok->args[1]); if (!tor_inet_aton(router->address, &in)) { log_warn(LD_DIR,"Router address is not an IP address."); goto err; } router->addr = ntohl(in.s_addr); router->or_port = (uint16_t) tor_parse_long(tok->args[2],10,0,65535,&ok,NULL); if (!ok) { log_warn(LD_DIR,"Invalid OR port %s", escaped(tok->args[2])); goto err; } router->dir_port = (uint16_t) tor_parse_long(tok->args[4],10,0,65535,&ok,NULL); if (!ok) { log_warn(LD_DIR,"Invalid dir port %s", escaped(tok->args[4])); goto err; } tok = find_by_keyword(tokens, K_BANDWIDTH); tor_assert(tok->n_args >= 3); router->bandwidthrate = (int) tor_parse_long(tok->args[0],10,1,INT_MAX,&ok,NULL); if (!ok) { log_warn(LD_DIR, "bandwidthrate %s unreadable or 0. Failing.", escaped(tok->args[0])); goto err; } router->bandwidthburst = (int) tor_parse_long(tok->args[1],10,0,INT_MAX,&ok,NULL); if (!ok) { log_warn(LD_DIR, "Invalid bandwidthburst %s", escaped(tok->args[1])); goto err; } router->bandwidthcapacity = (int) tor_parse_long(tok->args[2],10,0,INT_MAX,&ok,NULL); if (!ok) { log_warn(LD_DIR, "Invalid bandwidthcapacity %s", escaped(tok->args[1])); goto err; } if ((tok = find_opt_by_keyword(tokens, A_PURPOSE))) { tor_assert(tok->n_args); router->purpose = router_purpose_from_string(tok->args[0]); } else { router->purpose = ROUTER_PURPOSE_GENERAL; } router->cache_info.send_unencrypted = (router->purpose == ROUTER_PURPOSE_GENERAL) ? 1 : 0; if ((tok = find_opt_by_keyword(tokens, K_UPTIME))) { tor_assert(tok->n_args >= 1); router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,&ok,NULL); if (!ok) { log_warn(LD_DIR, "Invalid uptime %s", escaped(tok->args[0])); goto err; } } if ((tok = find_opt_by_keyword(tokens, K_HIBERNATING))) { tor_assert(tok->n_args >= 1); router->is_hibernating = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0); } tok = find_by_keyword(tokens, K_PUBLISHED); tor_assert(tok->n_args == 1); if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0) goto err; tok = find_by_keyword(tokens, K_ONION_KEY); if (!crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_DIR, "Relay's onion key had invalid exponent."); goto err; } router->onion_pkey = tok->key; tok->key = NULL; /* Prevent free */ if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) { curve25519_public_key_t k; tor_assert(tok->n_args >= 1); if (curve25519_public_from_base64(&k, tok->args[0]) < 0) { log_warn(LD_DIR, "Bogus ntor-onion-key in routerinfo"); goto err; } router->onion_curve25519_pkey = tor_memdup(&k, sizeof(curve25519_public_key_t)); } tok = find_by_keyword(tokens, K_SIGNING_KEY); router->identity_pkey = tok->key; tok->key = NULL; /* Prevent free */ if (crypto_pk_get_digest(router->identity_pkey, router->cache_info.identity_digest)) { log_warn(LD_DIR, "Couldn't calculate key digest"); goto err; } if ((tok = find_opt_by_keyword(tokens, K_FINGERPRINT))) { /* If there's a fingerprint line, it must match the identity digest. */ char d[DIGEST_LEN]; tor_assert(tok->n_args == 1); tor_strstrip(tok->args[0], " "); if (base16_decode(d, DIGEST_LEN, tok->args[0], strlen(tok->args[0]))) { log_warn(LD_DIR, "Couldn't decode router fingerprint %s", escaped(tok->args[0])); goto err; } if (tor_memneq(d,router->cache_info.identity_digest, DIGEST_LEN)) { log_warn(LD_DIR, "Fingerprint '%s' does not match identity digest.", tok->args[0]); goto err; } } if ((tok = find_opt_by_keyword(tokens, K_PLATFORM))) { router->platform = tor_strdup(tok->args[0]); } if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) { router->contact_info = tor_strdup(tok->args[0]); } if (find_opt_by_keyword(tokens, K_REJECT6) || find_opt_by_keyword(tokens, K_ACCEPT6)) { log_warn(LD_DIR, "Rejecting router with reject6/accept6 line: they crash " "older Tors."); goto err; } { smartlist_t *or_addresses = find_all_by_keyword(tokens, K_OR_ADDRESS); if (or_addresses) { find_single_ipv6_orport(or_addresses, &router->ipv6_addr, &router->ipv6_orport); smartlist_free(or_addresses); } } exit_policy_tokens = find_all_exitpolicy(tokens); if (!smartlist_len(exit_policy_tokens)) { log_warn(LD_DIR, "No exit policy tokens in descriptor."); goto err; } SMARTLIST_FOREACH(exit_policy_tokens, directory_token_t *, t, if (router_add_exit_policy(router,t)<0) { log_warn(LD_DIR,"Error in exit policy"); goto err; }); policy_expand_private(&router->exit_policy); if ((tok = find_opt_by_keyword(tokens, K_IPV6_POLICY)) && tok->n_args) { router->ipv6_exit_policy = parse_short_policy(tok->args[0]); if (! router->ipv6_exit_policy) { log_warn(LD_DIR , "Error in ipv6-policy %s", escaped(tok->args[0])); goto err; } } if (policy_is_reject_star(router->exit_policy, AF_INET) && (!router->ipv6_exit_policy || short_policy_is_reject_star(router->ipv6_exit_policy))) router->policy_is_reject_star = 1; if ((tok = find_opt_by_keyword(tokens, K_FAMILY)) && tok->n_args) { int i; router->declared_family = smartlist_new(); for (i=0;in_args;++i) { if (!is_legal_nickname_or_hexdigest(tok->args[i])) { log_warn(LD_DIR, "Illegal nickname %s in family line", escaped(tok->args[i])); goto err; } smartlist_add(router->declared_family, tor_strdup(tok->args[i])); } } if (find_opt_by_keyword(tokens, K_CACHES_EXTRA_INFO)) router->caches_extra_info = 1; if (find_opt_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS)) router->allow_single_hop_exits = 1; if ((tok = find_opt_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) { tor_assert(tok->n_args >= 1); if (strlen(tok->args[0]) == HEX_DIGEST_LEN) { base16_decode(router->cache_info.extra_info_digest, DIGEST_LEN, tok->args[0], HEX_DIGEST_LEN); } else { log_warn(LD_DIR, "Invalid extra info digest %s", escaped(tok->args[0])); } } if (find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR)) { router->wants_to_be_hs_dir = 1; } tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE); note_crypto_pk_op(VERIFY_RTR); #ifdef COUNT_DISTINCT_DIGESTS if (!verified_digests) verified_digests = digestmap_new(); digestmap_set(verified_digests, signed_digest, (void*)(uintptr_t)1); #endif if (check_signature_token(digest, DIGEST_LEN, tok, router->identity_pkey, 0, "router descriptor") < 0) goto err; if (!router->or_port) { log_warn(LD_DIR,"or_port unreadable or 0. Failing."); goto err; } if (!router->platform) { router->platform = tor_strdup(""); } goto done; err: dump_desc(s_dup, "router descriptor"); routerinfo_free(router); router = NULL; done: if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); } smartlist_free(exit_policy_tokens); if (area) { DUMP_AREA(area, "routerinfo"); memarea_drop_all(area); } return router; } /** Parse a single extrainfo entry from the string s, ending at * end. (If end is NULL, parse up to the end of s.) If * cache_copy is true, make a copy of the extra-info document in the * cache_info fields of the result. If routermap is provided, use it * as a map from router identity to routerinfo_t when looking up signing keys. */ extrainfo_t * extrainfo_parse_entry_from_string(const char *s, const char *end, int cache_copy, struct digest_ri_map_t *routermap) { extrainfo_t *extrainfo = NULL; char digest[128]; smartlist_t *tokens = NULL; directory_token_t *tok; crypto_pk_t *key = NULL; routerinfo_t *router = NULL; memarea_t *area = NULL; const char *s_dup = s; if (!end) { end = s + strlen(s); } /* point 'end' to a point immediately after the final newline. */ while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n') --end; if (router_get_extrainfo_hash(s, end-s, digest) < 0) { log_warn(LD_DIR, "Couldn't compute router hash."); goto err; } tokens = smartlist_new(); area = memarea_new(); if (tokenize_string(area,s,end,tokens,extrainfo_token_table,0)) { log_warn(LD_DIR, "Error tokenizing extra-info document."); goto err; } if (smartlist_len(tokens) < 2) { log_warn(LD_DIR, "Impossibly short extra-info document."); goto err; } tok = smartlist_get(tokens,0); if (tok->tp != K_EXTRA_INFO) { log_warn(LD_DIR,"Entry does not start with \"extra-info\""); goto err; } extrainfo = tor_malloc_zero(sizeof(extrainfo_t)); extrainfo->cache_info.is_extrainfo = 1; if (cache_copy) extrainfo->cache_info.signed_descriptor_body = tor_memdup_nulterm(s,end-s); extrainfo->cache_info.signed_descriptor_len = end-s; memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN); tor_assert(tok->n_args >= 2); if (!is_legal_nickname(tok->args[0])) { log_warn(LD_DIR,"Bad nickname %s on \"extra-info\"",escaped(tok->args[0])); goto err; } strlcpy(extrainfo->nickname, tok->args[0], sizeof(extrainfo->nickname)); if (strlen(tok->args[1]) != HEX_DIGEST_LEN || base16_decode(extrainfo->cache_info.identity_digest, DIGEST_LEN, tok->args[1], HEX_DIGEST_LEN)) { log_warn(LD_DIR,"Invalid fingerprint %s on \"extra-info\"", escaped(tok->args[1])); goto err; } tok = find_by_keyword(tokens, K_PUBLISHED); if (parse_iso_time(tok->args[0], &extrainfo->cache_info.published_on)) { log_warn(LD_DIR,"Invalid published time %s on \"extra-info\"", escaped(tok->args[0])); goto err; } if (routermap && (router = digestmap_get((digestmap_t*)routermap, extrainfo->cache_info.identity_digest))) { key = router->identity_pkey; } tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE); if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size < 128 || tok->object_size > 512) { log_warn(LD_DIR, "Bad object type or length on extra-info signature"); goto err; } if (key) { note_crypto_pk_op(VERIFY_RTR); if (check_signature_token(digest, DIGEST_LEN, tok, key, 0, "extra-info") < 0) goto err; if (router) extrainfo->cache_info.send_unencrypted = router->cache_info.send_unencrypted; } else { extrainfo->pending_sig = tor_memdup(tok->object_body, tok->object_size); extrainfo->pending_sig_len = tok->object_size; } goto done; err: dump_desc(s_dup, "extra-info descriptor"); extrainfo_free(extrainfo); extrainfo = NULL; done: if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); } if (area) { DUMP_AREA(area, "extrainfo"); memarea_drop_all(area); } return extrainfo; } /** Parse a key certificate from s; point end-of-string to * the first character after the certificate. */ authority_cert_t * authority_cert_parse_from_string(const char *s, const char **end_of_string) { /** Reject any certificate at least this big; it is probably an overflow, an * attack, a bug, or some other nonsense. */ #define MAX_CERT_SIZE (128*1024) authority_cert_t *cert = NULL, *old_cert; smartlist_t *tokens = NULL; char digest[DIGEST_LEN]; directory_token_t *tok; char fp_declared[DIGEST_LEN]; char *eos; size_t len; int found; memarea_t *area = NULL; const char *s_dup = s; s = eat_whitespace(s); eos = strstr(s, "\ndir-key-certification"); if (! eos) { log_warn(LD_DIR, "No signature found on key certificate"); return NULL; } eos = strstr(eos, "\n-----END SIGNATURE-----\n"); if (! eos) { log_warn(LD_DIR, "No end-of-signature found on key certificate"); return NULL; } eos = strchr(eos+2, '\n'); tor_assert(eos); ++eos; len = eos - s; if (len > MAX_CERT_SIZE) { log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); " "rejecting", (unsigned long)len); return NULL; } tokens = smartlist_new(); area = memarea_new(); if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) { log_warn(LD_DIR, "Error tokenizing key certificate"); goto err; } if (router_get_hash_impl(s, strlen(s), digest, "dir-key-certificate-version", "\ndir-key-certification", '\n', DIGEST_SHA1) < 0) goto err; tok = smartlist_get(tokens, 0); if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) { log_warn(LD_DIR, "Key certificate does not begin with a recognized version (3)."); goto err; } cert = tor_malloc_zero(sizeof(authority_cert_t)); memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN); tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY); tor_assert(tok->key); cert->signing_key = tok->key; tok->key = NULL; if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest)) goto err; tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY); tor_assert(tok->key); cert->identity_key = tok->key; tok->key = NULL; tok = find_by_keyword(tokens, K_FINGERPRINT); tor_assert(tok->n_args); if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0], strlen(tok->args[0]))) { log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s", escaped(tok->args[0])); goto err; } if (crypto_pk_get_digest(cert->identity_key, cert->cache_info.identity_digest)) goto err; if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) { log_warn(LD_DIR, "Digest of certificate key didn't match declared " "fingerprint"); goto err; } tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS); if (tok) { struct in_addr in; char *address = NULL; tor_assert(tok->n_args); /* XXX024 use some tor_addr parse function below instead. -RD */ if (tor_addr_port_split(LOG_WARN, tok->args[0], &address, &cert->dir_port) < 0 || tor_inet_aton(address, &in) == 0) { log_warn(LD_DIR, "Couldn't parse dir-address in certificate"); tor_free(address); goto err; } cert->addr = ntohl(in.s_addr); tor_free(address); } tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED); if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) { goto err; } tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES); if (parse_iso_time(tok->args[0], &cert->expires) < 0) { goto err; } tok = smartlist_get(tokens, smartlist_len(tokens)-1); if (tok->tp != K_DIR_KEY_CERTIFICATION) { log_warn(LD_DIR, "Certificate didn't end with dir-key-certification."); goto err; } /* If we already have this cert, don't bother checking the signature. */ old_cert = authority_cert_get_by_digests( cert->cache_info.identity_digest, cert->signing_key_digest); found = 0; if (old_cert) { /* XXXX We could just compare signed_descriptor_digest, but that wouldn't * buy us much. */ if (old_cert->cache_info.signed_descriptor_len == len && old_cert->cache_info.signed_descriptor_body && tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) { log_debug(LD_DIR, "We already checked the signature on this " "certificate; no need to do so again."); found = 1; cert->is_cross_certified = old_cert->is_cross_certified; } } if (!found) { if (check_signature_token(digest, DIGEST_LEN, tok, cert->identity_key, 0, "key certificate")) { goto err; } if ((tok = find_opt_by_keyword(tokens, K_DIR_KEY_CROSSCERT))) { /* XXXX Once all authorities generate cross-certified certificates, * make this field mandatory. */ if (check_signature_token(cert->cache_info.identity_digest, DIGEST_LEN, tok, cert->signing_key, CST_NO_CHECK_OBJTYPE, "key cross-certification")) { goto err; } cert->is_cross_certified = 1; } } cert->cache_info.signed_descriptor_len = len; cert->cache_info.signed_descriptor_body = tor_malloc(len+1); memcpy(cert->cache_info.signed_descriptor_body, s, len); cert->cache_info.signed_descriptor_body[len] = 0; cert->cache_info.saved_location = SAVED_NOWHERE; if (end_of_string) { *end_of_string = eat_whitespace(eos); } SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) { DUMP_AREA(area, "authority cert"); memarea_drop_all(area); } return cert; err: dump_desc(s_dup, "authority cert"); authority_cert_free(cert); SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) { DUMP_AREA(area, "authority cert"); memarea_drop_all(area); } return NULL; } /** Helper: given a string s, return the start of the next router-status * object (starting with "r " at the start of a line). If none is found, * return the start of the directory footer, or the next directory signature. * If none is found, return the end of the string. */ static INLINE const char * find_start_of_next_routerstatus(const char *s) { const char *eos, *footer, *sig; if ((eos = strstr(s, "\nr "))) ++eos; else eos = s + strlen(s); footer = tor_memstr(s, eos-s, "\ndirectory-footer"); sig = tor_memstr(s, eos-s, "\ndirectory-signature"); if (footer && sig) return MIN(footer, sig) + 1; else if (footer) return footer+1; else if (sig) return sig+1; else return eos; } /** Given a string at *s, containing a routerstatus object, and an * empty smartlist at tokens, parse and return the first router status * object in the string, and advance *s to just after the end of the * router status. Return NULL and advance *s on error. * * If vote and vote_rs are provided, don't allocate a fresh * routerstatus but use vote_rs instead. * * If consensus_method is nonzero, this routerstatus is part of a * consensus, and we should parse it according to the method used to * make that consensus. * * Parse according to the syntax used by the consensus flavor flav. **/ static routerstatus_t * routerstatus_parse_entry_from_string(memarea_t *area, const char **s, smartlist_t *tokens, networkstatus_t *vote, vote_routerstatus_t *vote_rs, int consensus_method, consensus_flavor_t flav) { const char *eos, *s_dup = *s; routerstatus_t *rs = NULL; directory_token_t *tok; char timebuf[ISO_TIME_LEN+1]; struct in_addr in; int offset = 0; tor_assert(tokens); tor_assert(bool_eq(vote, vote_rs)); if (!consensus_method) flav = FLAV_NS; tor_assert(flav == FLAV_NS || flav == FLAV_MICRODESC); eos = find_start_of_next_routerstatus(*s); if (tokenize_string(area,*s, eos, tokens, rtrstatus_token_table,0)) { log_warn(LD_DIR, "Error tokenizing router status"); goto err; } if (smartlist_len(tokens) < 1) { log_warn(LD_DIR, "Impossibly short router status"); goto err; } tok = find_by_keyword(tokens, K_R); tor_assert(tok->n_args >= 7); /* guaranteed by GE(7) in K_R setup */ if (flav == FLAV_NS) { if (tok->n_args < 8) { log_warn(LD_DIR, "Too few arguments to r"); goto err; } } else if (flav == FLAV_MICRODESC) { offset = -1; /* There is no identity digest */ } if (vote_rs) { rs = &vote_rs->status; } else { rs = tor_malloc_zero(sizeof(routerstatus_t)); } if (!is_legal_nickname(tok->args[0])) { log_warn(LD_DIR, "Invalid nickname %s in router status; skipping.", escaped(tok->args[0])); goto err; } strlcpy(rs->nickname, tok->args[0], sizeof(rs->nickname)); if (digest_from_base64(rs->identity_digest, tok->args[1])) { log_warn(LD_DIR, "Error decoding identity digest %s", escaped(tok->args[1])); goto err; } if (flav == FLAV_NS) { if (digest_from_base64(rs->descriptor_digest, tok->args[2])) { log_warn(LD_DIR, "Error decoding descriptor digest %s", escaped(tok->args[2])); goto err; } } if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s", tok->args[3+offset], tok->args[4+offset]) < 0 || parse_iso_time(timebuf, &rs->published_on)<0) { log_warn(LD_DIR, "Error parsing time '%s %s' [%d %d]", tok->args[3+offset], tok->args[4+offset], offset, (int)flav); goto err; } if (tor_inet_aton(tok->args[5+offset], &in) == 0) { log_warn(LD_DIR, "Error parsing router address in network-status %s", escaped(tok->args[5+offset])); goto err; } rs->addr = ntohl(in.s_addr); rs->or_port = (uint16_t) tor_parse_long(tok->args[6+offset], 10,0,65535,NULL,NULL); rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset], 10,0,65535,NULL,NULL); { smartlist_t *a_lines = find_all_by_keyword(tokens, K_A); if (a_lines) { find_single_ipv6_orport(a_lines, &rs->ipv6_addr, &rs->ipv6_orport); smartlist_free(a_lines); } } tok = find_opt_by_keyword(tokens, K_S); if (tok && vote) { int i; vote_rs->flags = 0; for (i=0; i < tok->n_args; ++i) { int p = smartlist_string_pos(vote->known_flags, tok->args[i]); if (p >= 0) { vote_rs->flags |= (U64_LITERAL(1)<args[i])); goto err; } } } else if (tok) { int i; for (i=0; i < tok->n_args; ++i) { if (!strcmp(tok->args[i], "Exit")) rs->is_exit = 1; else if (!strcmp(tok->args[i], "Stable")) rs->is_stable = 1; else if (!strcmp(tok->args[i], "Fast")) rs->is_fast = 1; else if (!strcmp(tok->args[i], "Running")) rs->is_flagged_running = 1; else if (!strcmp(tok->args[i], "Named")) rs->is_named = 1; else if (!strcmp(tok->args[i], "Valid")) rs->is_valid = 1; else if (!strcmp(tok->args[i], "V2Dir")) rs->is_v2_dir = 1; else if (!strcmp(tok->args[i], "Guard")) rs->is_possible_guard = 1; else if (!strcmp(tok->args[i], "BadExit")) rs->is_bad_exit = 1; else if (!strcmp(tok->args[i], "BadDirectory")) rs->is_bad_directory = 1; else if (!strcmp(tok->args[i], "Authority")) rs->is_authority = 1; else if (!strcmp(tok->args[i], "Unnamed") && consensus_method >= 2) { /* Unnamed is computed right by consensus method 2 and later. */ rs->is_unnamed = 1; } else if (!strcmp(tok->args[i], "HSDir")) { rs->is_hs_dir = 1; } } } if ((tok = find_opt_by_keyword(tokens, K_V))) { tor_assert(tok->n_args == 1); rs->version_known = 1; if (strcmpstart(tok->args[0], "Tor ")) { rs->version_supports_microdesc_cache = 1; rs->version_supports_optimistic_data = 1; } else { rs->version_supports_microdesc_cache = tor_version_supports_microdescriptors(tok->args[0]); rs->version_supports_optimistic_data = tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha"); rs->version_supports_extend2_cells = tor_version_as_new_as(tok->args[0], "0.2.4.8-alpha"); } if (vote_rs) { vote_rs->version = tor_strdup(tok->args[0]); } } /* handle weighting/bandwidth info */ if ((tok = find_opt_by_keyword(tokens, K_W))) { int i; for (i=0; i < tok->n_args; ++i) { if (!strcmpstart(tok->args[i], "Bandwidth=")) { int ok; rs->bandwidth_kb = (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1, 10, 0, UINT32_MAX, &ok, NULL); if (!ok) { log_warn(LD_DIR, "Invalid Bandwidth %s", escaped(tok->args[i])); goto err; } rs->has_bandwidth = 1; } else if (!strcmpstart(tok->args[i], "Measured=") && vote_rs) { int ok; vote_rs->measured_bw_kb = (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1, 10, 0, UINT32_MAX, &ok, NULL); if (!ok) { log_warn(LD_DIR, "Invalid Measured Bandwidth %s", escaped(tok->args[i])); goto err; } vote_rs->has_measured_bw = 1; vote->has_measured_bws = 1; } else if (!strcmpstart(tok->args[i], "Unmeasured=1")) { rs->bw_is_unmeasured = 1; } } } /* parse exit policy summaries */ if ((tok = find_opt_by_keyword(tokens, K_P))) { tor_assert(tok->n_args == 1); if (strcmpstart(tok->args[0], "accept ") && strcmpstart(tok->args[0], "reject ")) { log_warn(LD_DIR, "Unknown exit policy summary type %s.", escaped(tok->args[0])); goto err; } /* XXX weasel: parse this into ports and represent them somehow smart, * maybe not here but somewhere on if we need it for the client. * we should still parse it here to check it's valid tho. */ rs->exitsummary = tor_strdup(tok->args[0]); rs->has_exitsummary = 1; } if (vote_rs) { SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, t) { if (t->tp == K_M && t->n_args) { vote_microdesc_hash_t *line = tor_malloc(sizeof(vote_microdesc_hash_t)); line->next = vote_rs->microdesc; line->microdesc_hash_line = tor_strdup(t->args[0]); vote_rs->microdesc = line; } } SMARTLIST_FOREACH_END(t); } else if (flav == FLAV_MICRODESC) { tok = find_opt_by_keyword(tokens, K_M); if (tok) { tor_assert(tok->n_args); if (digest256_from_base64(rs->descriptor_digest, tok->args[0])) { log_warn(LD_DIR, "Error decoding microdescriptor digest %s", escaped(tok->args[0])); goto err; } } else { log_info(LD_BUG, "Found an entry in networkstatus with no " "microdescriptor digest. (Router %s ($%s) at %s:%d.)", rs->nickname, hex_str(rs->identity_digest, DIGEST_LEN), fmt_addr32(rs->addr), rs->or_port); } } if (!strcasecmp(rs->nickname, UNNAMED_ROUTER_NICKNAME)) rs->is_named = 0; goto done; err: dump_desc(s_dup, "routerstatus entry"); if (rs && !vote_rs) routerstatus_free(rs); rs = NULL; done: SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_clear(tokens); if (area) { DUMP_AREA(area, "routerstatus entry"); memarea_clear(area); } *s = eos; return rs; } /** Helper to sort a smartlist of pointers to routerstatus_t */ int compare_routerstatus_entries(const void **_a, const void **_b) { const routerstatus_t *a = *_a, *b = *_b; return fast_memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN); } int compare_vote_routerstatus_entries(const void **_a, const void **_b) { const vote_routerstatus_t *a = *_a, *b = *_b; return fast_memcmp(a->status.identity_digest, b->status.identity_digest, DIGEST_LEN); } /** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */ static void free_duplicate_routerstatus_entry_(void *e) { log_warn(LD_DIR, "Network-status has two entries for the same router. " "Dropping one."); routerstatus_free(e); } /** Given a v2 network-status object in s, try to * parse it and return the result. Return NULL on failure. Check the * signature of the network status, but do not (yet) check the signing key for * authority. */ networkstatus_v2_t * networkstatus_v2_parse_from_string(const char *s) { const char *eos, *s_dup = s; smartlist_t *tokens = smartlist_new(); smartlist_t *footer_tokens = smartlist_new(); networkstatus_v2_t *ns = NULL; char ns_digest[DIGEST_LEN]; char tmp_digest[DIGEST_LEN]; struct in_addr in; directory_token_t *tok; int i; memarea_t *area = NULL; if (router_get_networkstatus_v2_hash(s, ns_digest)) { log_warn(LD_DIR, "Unable to compute digest of network-status"); goto err; } area = memarea_new(); eos = find_start_of_next_routerstatus(s); if (tokenize_string(area, s, eos, tokens, netstatus_token_table,0)) { log_warn(LD_DIR, "Error tokenizing network-status header."); goto err; } ns = tor_malloc_zero(sizeof(networkstatus_v2_t)); memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN); tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION); tor_assert(tok->n_args >= 1); if (strcmp(tok->args[0], "2")) { log_warn(LD_BUG, "Got a non-v2 networkstatus. Version was " "%s", escaped(tok->args[0])); goto err; } tok = find_by_keyword(tokens, K_DIR_SOURCE); tor_assert(tok->n_args >= 3); ns->source_address = tor_strdup(tok->args[0]); if (tor_inet_aton(tok->args[1], &in) == 0) { log_warn(LD_DIR, "Error parsing network-status source address %s", escaped(tok->args[1])); goto err; } ns->source_addr = ntohl(in.s_addr); ns->source_dirport = (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL); if (ns->source_dirport == 0) { log_warn(LD_DIR, "Directory source without dirport; skipping."); goto err; } tok = find_by_keyword(tokens, K_FINGERPRINT); tor_assert(tok->n_args); if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0], strlen(tok->args[0]))) { log_warn(LD_DIR, "Couldn't decode networkstatus fingerprint %s", escaped(tok->args[0])); goto err; } if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) { tor_assert(tok->n_args); ns->contact = tor_strdup(tok->args[0]); } tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY); tor_assert(tok->key); ns->signing_key = tok->key; tok->key = NULL; if (crypto_pk_get_digest(ns->signing_key, tmp_digest)<0) { log_warn(LD_DIR, "Couldn't compute signing key digest"); goto err; } if (tor_memneq(tmp_digest, ns->identity_digest, DIGEST_LEN)) { log_warn(LD_DIR, "network-status fingerprint did not match dir-signing-key"); goto err; } if ((tok = find_opt_by_keyword(tokens, K_DIR_OPTIONS))) { for (i=0; i < tok->n_args; ++i) { if (!strcmp(tok->args[i], "Names")) ns->binds_names = 1; if (!strcmp(tok->args[i], "Versions")) ns->recommends_versions = 1; if (!strcmp(tok->args[i], "BadExits")) ns->lists_bad_exits = 1; if (!strcmp(tok->args[i], "BadDirectories")) ns->lists_bad_directories = 1; } } if (ns->recommends_versions) { if (!(tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) { log_warn(LD_DIR, "Missing client-versions on versioning directory"); goto err; } ns->client_versions = tor_strdup(tok->args[0]); if (!(tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS)) || tok->n_args<1) { log_warn(LD_DIR, "Missing server-versions on versioning directory"); goto err; } ns->server_versions = tor_strdup(tok->args[0]); } tok = find_by_keyword(tokens, K_PUBLISHED); tor_assert(tok->n_args == 1); if (parse_iso_time(tok->args[0], &ns->published_on) < 0) { goto err; } ns->entries = smartlist_new(); s = eos; SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_clear(tokens); memarea_clear(area); while (!strcmpstart(s, "r ")) { routerstatus_t *rs; if ((rs = routerstatus_parse_entry_from_string(area, &s, tokens, NULL, NULL, 0, 0))) smartlist_add(ns->entries, rs); } smartlist_sort(ns->entries, compare_routerstatus_entries); smartlist_uniq(ns->entries, compare_routerstatus_entries, free_duplicate_routerstatus_entry_); if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) { log_warn(LD_DIR, "Error tokenizing network-status footer."); goto err; } if (smartlist_len(footer_tokens) < 1) { log_warn(LD_DIR, "Too few items in network-status footer."); goto err; } tok = smartlist_get(footer_tokens, smartlist_len(footer_tokens)-1); if (tok->tp != K_DIRECTORY_SIGNATURE) { log_warn(LD_DIR, "Expected network-status footer to end with a signature."); goto err; } note_crypto_pk_op(VERIFY_DIR); if (check_signature_token(ns_digest, DIGEST_LEN, tok, ns->signing_key, 0, "network-status") < 0) goto err; goto done; err: dump_desc(s_dup, "v2 networkstatus"); networkstatus_v2_free(ns); ns = NULL; done: SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t)); smartlist_free(footer_tokens); if (area) { DUMP_AREA(area, "v2 networkstatus"); memarea_drop_all(area); } return ns; } /** Verify the bandwidth weights of a network status document */ int networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) { int64_t weight_scale; int64_t G=0, M=0, E=0, D=0, T=0; double Wgg, Wgm, Wgd, Wmg, Wmm, Wme, Wmd, Weg, Wem, Wee, Wed; double Gtotal=0, Mtotal=0, Etotal=0; const char *casename = NULL; int valid = 1; weight_scale = networkstatus_get_weight_scale_param(ns); Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1); Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1); Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1); Wmg = networkstatus_get_bw_weight(ns, "Wmg", -1); Wmm = networkstatus_get_bw_weight(ns, "Wmm", -1); Wme = networkstatus_get_bw_weight(ns, "Wme", -1); Wmd = networkstatus_get_bw_weight(ns, "Wmd", -1); Weg = networkstatus_get_bw_weight(ns, "Weg", -1); Wem = networkstatus_get_bw_weight(ns, "Wem", -1); Wee = networkstatus_get_bw_weight(ns, "Wee", -1); Wed = networkstatus_get_bw_weight(ns, "Wed", -1); if (Wgg<0 || Wgm<0 || Wgd<0 || Wmg<0 || Wmm<0 || Wme<0 || Wmd<0 || Weg<0 || Wem<0 || Wee<0 || Wed<0) { log_warn(LD_BUG, "No bandwidth weights produced in consensus!"); return 0; } // First, sanity check basic summing properties that hold for all cases // We use > 1 as the check for these because they are computed as integers. // Sometimes there are rounding errors. if (fabs(Wmm - weight_scale) > 1) { log_warn(LD_BUG, "Wmm=%f != "I64_FORMAT, Wmm, I64_PRINTF_ARG(weight_scale)); valid = 0; } if (fabs(Wem - Wee) > 1) { log_warn(LD_BUG, "Wem=%f != Wee=%f", Wem, Wee); valid = 0; } if (fabs(Wgm - Wgg) > 1) { log_warn(LD_BUG, "Wgm=%f != Wgg=%f", Wgm, Wgg); valid = 0; } if (fabs(Weg - Wed) > 1) { log_warn(LD_BUG, "Wed=%f != Weg=%f", Wed, Weg); valid = 0; } if (fabs(Wgg + Wmg - weight_scale) > 0.001*weight_scale) { log_warn(LD_BUG, "Wgg=%f != "I64_FORMAT" - Wmg=%f", Wgg, I64_PRINTF_ARG(weight_scale), Wmg); valid = 0; } if (fabs(Wee + Wme - weight_scale) > 0.001*weight_scale) { log_warn(LD_BUG, "Wee=%f != "I64_FORMAT" - Wme=%f", Wee, I64_PRINTF_ARG(weight_scale), Wme); valid = 0; } if (fabs(Wgd + Wmd + Wed - weight_scale) > 0.001*weight_scale) { log_warn(LD_BUG, "Wgd=%f + Wmd=%f + Wed=%f != "I64_FORMAT, Wgd, Wmd, Wed, I64_PRINTF_ARG(weight_scale)); valid = 0; } Wgg /= weight_scale; Wgm /= weight_scale; Wgd /= weight_scale; Wmg /= weight_scale; Wmm /= weight_scale; Wme /= weight_scale; Wmd /= weight_scale; Weg /= weight_scale; Wem /= weight_scale; Wee /= weight_scale; Wed /= weight_scale; // Then, gather G, M, E, D, T to determine case SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { int is_exit = 0; if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) { /* Bug #2203: Don't count bad exits as exits for balancing */ is_exit = rs->is_exit && !rs->is_bad_exit; } else { is_exit = rs->is_exit; } if (rs->has_bandwidth) { T += rs->bandwidth_kb; if (is_exit && rs->is_possible_guard) { D += rs->bandwidth_kb; Gtotal += Wgd*rs->bandwidth_kb; Mtotal += Wmd*rs->bandwidth_kb; Etotal += Wed*rs->bandwidth_kb; } else if (is_exit) { E += rs->bandwidth_kb; Mtotal += Wme*rs->bandwidth_kb; Etotal += Wee*rs->bandwidth_kb; } else if (rs->is_possible_guard) { G += rs->bandwidth_kb; Gtotal += Wgg*rs->bandwidth_kb; Mtotal += Wmg*rs->bandwidth_kb; } else { M += rs->bandwidth_kb; Mtotal += Wmm*rs->bandwidth_kb; } } else { log_warn(LD_BUG, "Missing consensus bandwidth for router %s", routerstatus_describe(rs)); } } SMARTLIST_FOREACH_END(rs); // Finally, check equality conditions depending upon case 1, 2 or 3 // Full equality cases: 1, 3b // Partial equality cases: 2b (E=G), 3a (M=E) // Fully unknown: 2a if (3*E >= T && 3*G >= T) { // Case 1: Neither are scarce casename = "Case 1"; if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Mtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Mtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Gtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Gtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Mtotal, Gtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } } else if (3*E < T && 3*G < T) { int64_t R = MIN(E, G); int64_t S = MAX(E, G); /* * Case 2: Both Guards and Exits are scarce * Balance D between E and G, depending upon * D capacity and scarcity. Devote no extra * bandwidth to middle nodes. */ if (R+D < S) { // Subcase a double Rtotal, Stotal; if (E < G) { Rtotal = Etotal; Stotal = Gtotal; } else { Rtotal = Gtotal; Stotal = Etotal; } casename = "Case 2a"; // Rtotal < Stotal if (Rtotal > Stotal) { log_warn(LD_DIR, "Bw Weight Failure for %s: Rtotal %f > Stotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Rtotal, Stotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } // Rtotal < T/3 if (3*Rtotal > T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*Rtotal %f > T " I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT " D="I64_FORMAT" T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Rtotal*3, I64_PRINTF_ARG(T), I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } // Stotal < T/3 if (3*Stotal > T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*Stotal %f > T " I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT " D="I64_FORMAT" T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Stotal*3, I64_PRINTF_ARG(T), I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } // Mtotal > T/3 if (3*Mtotal < T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*Mtotal %f < T " I64_FORMAT". " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Mtotal*3, I64_PRINTF_ARG(T), I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } } else { // Subcase b: R+D > S casename = "Case 2b"; /* Check the rare-M redirect case. */ if (D != 0 && 3*M < T) { casename = "Case 2b (balanced)"; if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Mtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Mtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Gtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Gtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Mtotal, Gtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } } else { if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Gtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Gtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } } } } else { // if (E < T/3 || G < T/3) { int64_t S = MIN(E, G); int64_t NS = MAX(E, G); if (3*(S+D) < T) { // Subcase a: double Stotal; double NStotal; if (G < E) { casename = "Case 3a (G scarce)"; Stotal = Gtotal; NStotal = Etotal; } else { // if (G >= E) { casename = "Case 3a (E scarce)"; NStotal = Gtotal; Stotal = Etotal; } // Stotal < T/3 if (3*Stotal > T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*Stotal %f > T " I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT " D="I64_FORMAT" T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Stotal*3, I64_PRINTF_ARG(T), I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (NS >= M) { if (fabs(NStotal-Mtotal) > 0.01*MAX(NStotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: NStotal %f != Mtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, NStotal, Mtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } } else { // if NS < M, NStotal > T/3 because only one of G or E is scarce if (3*NStotal < T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*NStotal %f < T " I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, NStotal*3, I64_PRINTF_ARG(T), I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } } } else { // Subcase b: S+D >= T/3 casename = "Case 3b"; if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Mtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Mtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Gtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Gtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Mtotal, Gtotal, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } } } if (valid) log_notice(LD_DIR, "Bandwidth-weight %s is verified and valid.", casename); return valid; } /** Parse a v3 networkstatus vote, opinion, or consensus (depending on * ns_type), from s, and return the result. Return NULL on failure. */ networkstatus_t * networkstatus_parse_vote_from_string(const char *s, const char **eos_out, networkstatus_type_t ns_type) { smartlist_t *tokens = smartlist_new(); smartlist_t *rs_tokens = NULL, *footer_tokens = NULL; networkstatus_voter_info_t *voter = NULL; networkstatus_t *ns = NULL; digests_t ns_digests; const char *cert, *end_of_header, *end_of_footer, *s_dup = s; directory_token_t *tok; int ok; struct in_addr in; int i, inorder, n_signatures = 0; memarea_t *area = NULL, *rs_area = NULL; consensus_flavor_t flav = FLAV_NS; char *last_kwd=NULL; tor_assert(s); if (eos_out) *eos_out = NULL; if (router_get_networkstatus_v3_hashes(s, &ns_digests)) { log_warn(LD_DIR, "Unable to compute digest of network-status"); goto err; } area = memarea_new(); end_of_header = find_start_of_next_routerstatus(s); if (tokenize_string(area, s, end_of_header, tokens, (ns_type == NS_TYPE_CONSENSUS) ? networkstatus_consensus_token_table : networkstatus_token_table, 0)) { log_warn(LD_DIR, "Error tokenizing network-status vote header"); goto err; } ns = tor_malloc_zero(sizeof(networkstatus_t)); memcpy(&ns->digests, &ns_digests, sizeof(ns_digests)); tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION); tor_assert(tok); if (tok->n_args > 1) { int flavor = networkstatus_parse_flavor_name(tok->args[1]); if (flavor < 0) { log_warn(LD_DIR, "Can't parse document with unknown flavor %s", escaped(tok->args[1])); goto err; } ns->flavor = flav = flavor; } if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) { log_warn(LD_DIR, "Flavor found on non-consensus networkstatus."); goto err; } if (ns_type != NS_TYPE_CONSENSUS) { const char *end_of_cert = NULL; if (!(cert = strstr(s, "\ndir-key-certificate-version"))) goto err; ++cert; ns->cert = authority_cert_parse_from_string(cert, &end_of_cert); if (!ns->cert || !end_of_cert || end_of_cert > end_of_header) goto err; } tok = find_by_keyword(tokens, K_VOTE_STATUS); tor_assert(tok->n_args); if (!strcmp(tok->args[0], "vote")) { ns->type = NS_TYPE_VOTE; } else if (!strcmp(tok->args[0], "consensus")) { ns->type = NS_TYPE_CONSENSUS; } else if (!strcmp(tok->args[0], "opinion")) { ns->type = NS_TYPE_OPINION; } else { log_warn(LD_DIR, "Unrecognized vote status %s in network-status", escaped(tok->args[0])); goto err; } if (ns_type != ns->type) { log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus."); goto err; } if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) { tok = find_by_keyword(tokens, K_PUBLISHED); if (parse_iso_time(tok->args[0], &ns->published)) goto err; ns->supported_methods = smartlist_new(); tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS); if (tok) { for (i=0; i < tok->n_args; ++i) smartlist_add(ns->supported_methods, tor_strdup(tok->args[i])); } else { smartlist_add(ns->supported_methods, tor_strdup("1")); } } else { tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD); if (tok) { ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX, &ok, NULL); if (!ok) goto err; } else { ns->consensus_method = 1; } } tok = find_by_keyword(tokens, K_VALID_AFTER); if (parse_iso_time(tok->args[0], &ns->valid_after)) goto err; tok = find_by_keyword(tokens, K_FRESH_UNTIL); if (parse_iso_time(tok->args[0], &ns->fresh_until)) goto err; tok = find_by_keyword(tokens, K_VALID_UNTIL); if (parse_iso_time(tok->args[0], &ns->valid_until)) goto err; tok = find_by_keyword(tokens, K_VOTING_DELAY); tor_assert(tok->n_args >= 2); ns->vote_seconds = (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL); if (!ok) goto err; ns->dist_seconds = (int) tor_parse_long(tok->args[1], 10, 0, INT_MAX, &ok, NULL); if (!ok) goto err; if (ns->valid_after + MIN_VOTE_INTERVAL > ns->fresh_until) { log_warn(LD_DIR, "Vote/consensus freshness interval is too short"); goto err; } if (ns->valid_after + MIN_VOTE_INTERVAL*2 > ns->valid_until) { log_warn(LD_DIR, "Vote/consensus liveness interval is too short"); goto err; } if (ns->vote_seconds < MIN_VOTE_SECONDS) { log_warn(LD_DIR, "Vote seconds is too short"); goto err; } if (ns->dist_seconds < MIN_DIST_SECONDS) { log_warn(LD_DIR, "Dist seconds is too short"); goto err; } if ((tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) { ns->client_versions = tor_strdup(tok->args[0]); } if ((tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS))) { ns->server_versions = tor_strdup(tok->args[0]); } tok = find_by_keyword(tokens, K_KNOWN_FLAGS); ns->known_flags = smartlist_new(); inorder = 1; for (i = 0; i < tok->n_args; ++i) { smartlist_add(ns->known_flags, tor_strdup(tok->args[i])); if (i>0 && strcmp(tok->args[i-1], tok->args[i])>= 0) { log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]); inorder = 0; } } if (!inorder) { log_warn(LD_DIR, "known-flags not in order"); goto err; } if (ns->type != NS_TYPE_CONSENSUS && smartlist_len(ns->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) { /* If we allowed more than 64 flags in votes, then parsing them would make * us invoke undefined behavior whenever we used 1<net_params = smartlist_new(); for (i = 0; i < tok->n_args; ++i) { int ok=0; char *eq = strchr(tok->args[i], '='); size_t eq_pos; if (!eq) { log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i])); goto err; } eq_pos = eq-tok->args[i]; tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL); if (!ok) { log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i])); goto err; } if (i > 0 && strcmp(tok->args[i-1], tok->args[i]) >= 0) { log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]); inorder = 0; } if (last_kwd && eq_pos == strlen(last_kwd) && fast_memeq(last_kwd, tok->args[i], eq_pos)) { log_warn(LD_DIR, "Duplicate value for %s parameter", escaped(tok->args[i])); any_dups = 1; } tor_free(last_kwd); last_kwd = tor_strndup(tok->args[i], eq_pos); smartlist_add(ns->net_params, tor_strdup(tok->args[i])); } if (!inorder) { log_warn(LD_DIR, "params not in order"); goto err; } if (any_dups) { log_warn(LD_DIR, "Duplicate in parameters"); goto err; } } ns->voters = smartlist_new(); SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) { tok = _tok; if (tok->tp == K_DIR_SOURCE) { tor_assert(tok->n_args >= 6); if (voter) smartlist_add(ns->voters, voter); voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); voter->sigs = smartlist_new(); if (ns->type != NS_TYPE_CONSENSUS) memcpy(voter->vote_digest, ns_digests.d[DIGEST_SHA1], DIGEST_LEN); voter->nickname = tor_strdup(tok->args[0]); if (strlen(tok->args[1]) != HEX_DIGEST_LEN || base16_decode(voter->identity_digest, sizeof(voter->identity_digest), tok->args[1], HEX_DIGEST_LEN) < 0) { log_warn(LD_DIR, "Error decoding identity digest %s in " "network-status vote.", escaped(tok->args[1])); goto err; } if (ns->type != NS_TYPE_CONSENSUS && tor_memneq(ns->cert->cache_info.identity_digest, voter->identity_digest, DIGEST_LEN)) { log_warn(LD_DIR,"Mismatch between identities in certificate and vote"); goto err; } voter->address = tor_strdup(tok->args[2]); if (!tor_inet_aton(tok->args[3], &in)) { log_warn(LD_DIR, "Error decoding IP address %s in network-status.", escaped(tok->args[3])); goto err; } voter->addr = ntohl(in.s_addr); voter->dir_port = (uint16_t) tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL); if (!ok) goto err; voter->or_port = (uint16_t) tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL); if (!ok) goto err; } else if (tok->tp == K_CONTACT) { if (!voter || voter->contact) { log_warn(LD_DIR, "contact element is out of place."); goto err; } voter->contact = tor_strdup(tok->args[0]); } else if (tok->tp == K_VOTE_DIGEST) { tor_assert(ns->type == NS_TYPE_CONSENSUS); tor_assert(tok->n_args >= 1); if (!voter || ! tor_digest_is_zero(voter->vote_digest)) { log_warn(LD_DIR, "vote-digest element is out of place."); goto err; } if (strlen(tok->args[0]) != HEX_DIGEST_LEN || base16_decode(voter->vote_digest, sizeof(voter->vote_digest), tok->args[0], HEX_DIGEST_LEN) < 0) { log_warn(LD_DIR, "Error decoding vote digest %s in " "network-status consensus.", escaped(tok->args[0])); goto err; } } } SMARTLIST_FOREACH_END(_tok); if (voter) { smartlist_add(ns->voters, voter); voter = NULL; } if (smartlist_len(ns->voters) == 0) { log_warn(LD_DIR, "Missing dir-source elements in a vote networkstatus."); goto err; } else if (ns->type != NS_TYPE_CONSENSUS && smartlist_len(ns->voters) != 1) { log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus."); goto err; } if (ns->type != NS_TYPE_CONSENSUS && (tok = find_opt_by_keyword(tokens, K_LEGACY_DIR_KEY))) { int bad = 1; if (strlen(tok->args[0]) == HEX_DIGEST_LEN) { networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0); if (base16_decode(voter->legacy_id_digest, DIGEST_LEN, tok->args[0], HEX_DIGEST_LEN)<0) bad = 1; else bad = 0; } if (bad) { log_warn(LD_DIR, "Invalid legacy key digest %s on vote.", escaped(tok->args[0])); } } /* Parse routerstatus lines. */ rs_tokens = smartlist_new(); rs_area = memarea_new(); s = end_of_header; ns->routerstatus_list = smartlist_new(); while (!strcmpstart(s, "r ")) { if (ns->type != NS_TYPE_CONSENSUS) { vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t)); if (routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens, ns, rs, 0, 0)) smartlist_add(ns->routerstatus_list, rs); else { tor_free(rs->version); tor_free(rs); } } else { routerstatus_t *rs; if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens, NULL, NULL, ns->consensus_method, flav))) smartlist_add(ns->routerstatus_list, rs); } } for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) { routerstatus_t *rs1, *rs2; if (ns->type != NS_TYPE_CONSENSUS) { vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1); vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i); rs1 = &a->status; rs2 = &b->status; } else { rs1 = smartlist_get(ns->routerstatus_list, i-1); rs2 = smartlist_get(ns->routerstatus_list, i); } if (fast_memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN) >= 0) { log_warn(LD_DIR, "Vote networkstatus entries not sorted by identity " "digest"); goto err; } } /* Parse footer; check signature. */ footer_tokens = smartlist_new(); if ((end_of_footer = strstr(s, "\nnetwork-status-version "))) ++end_of_footer; else end_of_footer = s + strlen(s); if (tokenize_string(area,s, end_of_footer, footer_tokens, networkstatus_vote_footer_token_table, 0)) { log_warn(LD_DIR, "Error tokenizing network-status vote footer."); goto err; } { int found_sig = 0; SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) { tok = _tok; if (tok->tp == K_DIRECTORY_SIGNATURE) found_sig = 1; else if (found_sig) { log_warn(LD_DIR, "Extraneous token after first directory-signature"); goto err; } } SMARTLIST_FOREACH_END(_tok); } if ((tok = find_opt_by_keyword(footer_tokens, K_DIRECTORY_FOOTER))) { if (tok != smartlist_get(footer_tokens, 0)) { log_warn(LD_DIR, "Misplaced directory-footer token"); goto err; } } tok = find_opt_by_keyword(footer_tokens, K_BW_WEIGHTS); if (tok) { ns->weight_params = smartlist_new(); for (i = 0; i < tok->n_args; ++i) { int ok=0; char *eq = strchr(tok->args[i], '='); if (!eq) { log_warn(LD_DIR, "Bad element '%s' in weight params", escaped(tok->args[i])); goto err; } tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL); if (!ok) { log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i])); goto err; } smartlist_add(ns->weight_params, tor_strdup(tok->args[i])); } } SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) { char declared_identity[DIGEST_LEN]; networkstatus_voter_info_t *v; document_signature_t *sig; const char *id_hexdigest = NULL; const char *sk_hexdigest = NULL; digest_algorithm_t alg = DIGEST_SHA1; tok = _tok; if (tok->tp != K_DIRECTORY_SIGNATURE) continue; tor_assert(tok->n_args >= 2); if (tok->n_args == 2) { id_hexdigest = tok->args[0]; sk_hexdigest = tok->args[1]; } else { const char *algname = tok->args[0]; int a; id_hexdigest = tok->args[1]; sk_hexdigest = tok->args[2]; a = crypto_digest_algorithm_parse_name(algname); if (a<0) { log_warn(LD_DIR, "Unknown digest algorithm %s; skipping", escaped(algname)); continue; } alg = a; } if (!tok->object_type || strcmp(tok->object_type, "SIGNATURE") || tok->object_size < 128 || tok->object_size > 512) { log_warn(LD_DIR, "Bad object type or length on directory-signature"); goto err; } if (strlen(id_hexdigest) != HEX_DIGEST_LEN || base16_decode(declared_identity, sizeof(declared_identity), id_hexdigest, HEX_DIGEST_LEN) < 0) { log_warn(LD_DIR, "Error decoding declared identity %s in " "network-status vote.", escaped(id_hexdigest)); goto err; } if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) { log_warn(LD_DIR, "ID on signature on network-status vote does not match " "any declared directory source."); goto err; } sig = tor_malloc_zero(sizeof(document_signature_t)); memcpy(sig->identity_digest, v->identity_digest, DIGEST_LEN); sig->alg = alg; if (strlen(sk_hexdigest) != HEX_DIGEST_LEN || base16_decode(sig->signing_key_digest, sizeof(sig->signing_key_digest), sk_hexdigest, HEX_DIGEST_LEN) < 0) { log_warn(LD_DIR, "Error decoding declared signing key digest %s in " "network-status vote.", escaped(sk_hexdigest)); tor_free(sig); goto err; } if (ns->type != NS_TYPE_CONSENSUS) { if (tor_memneq(declared_identity, ns->cert->cache_info.identity_digest, DIGEST_LEN)) { log_warn(LD_DIR, "Digest mismatch between declared and actual on " "network-status vote."); tor_free(sig); goto err; } } if (voter_get_sig_by_algorithm(v, sig->alg)) { /* We already parsed a vote with this algorithm from this voter. Use the first one. */ log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus " "that contains two votes from the same voter with the same " "algorithm. Ignoring the second vote."); tor_free(sig); continue; } if (ns->type != NS_TYPE_CONSENSUS) { if (check_signature_token(ns_digests.d[DIGEST_SHA1], DIGEST_LEN, tok, ns->cert->signing_key, 0, "network-status vote")) { tor_free(sig); goto err; } sig->good_signature = 1; } else { if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) { tor_free(sig); goto err; } sig->signature = tor_memdup(tok->object_body, tok->object_size); sig->signature_len = (int) tok->object_size; } smartlist_add(v->sigs, sig); ++n_signatures; } SMARTLIST_FOREACH_END(_tok); if (! n_signatures) { log_warn(LD_DIR, "No signatures on networkstatus vote."); goto err; } else if (ns->type == NS_TYPE_VOTE && n_signatures != 1) { log_warn(LD_DIR, "Received more than one signature on a " "network-status vote."); goto err; } if (eos_out) *eos_out = end_of_footer; goto done; err: dump_desc(s_dup, "v3 networkstatus"); networkstatus_vote_free(ns); ns = NULL; done: if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); } if (voter) { if (voter->sigs) { SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig, document_signature_free(sig)); smartlist_free(voter->sigs); } tor_free(voter->nickname); tor_free(voter->address); tor_free(voter->contact); tor_free(voter); } if (rs_tokens) { SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_clear(t)); smartlist_free(rs_tokens); } if (footer_tokens) { SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t)); smartlist_free(footer_tokens); } if (area) { DUMP_AREA(area, "v3 networkstatus"); memarea_drop_all(area); } if (rs_area) memarea_drop_all(rs_area); tor_free(last_kwd); return ns; } /** Return the digests_t that holds the digests of the * flavor_name-flavored networkstatus according to the detached * signatures document sigs, allocating a new digests_t as neeeded. */ static digests_t * detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name) { digests_t *d = strmap_get(sigs->digests, flavor_name); if (!d) { d = tor_malloc_zero(sizeof(digests_t)); strmap_set(sigs->digests, flavor_name, d); } return d; } /** Return the list of signatures of the flavor_name-flavored * networkstatus according to the detached signatures document sigs, * allocating a new digests_t as neeeded. */ static smartlist_t * detached_get_signatures(ns_detached_signatures_t *sigs, const char *flavor_name) { smartlist_t *sl = strmap_get(sigs->signatures, flavor_name); if (!sl) { sl = smartlist_new(); strmap_set(sigs->signatures, flavor_name, sl); } return sl; } /** Parse a detached v3 networkstatus signature document between s and * eos and return the result. Return -1 on failure. */ ns_detached_signatures_t * networkstatus_parse_detached_signatures(const char *s, const char *eos) { /* XXXX there is too much duplicate shared between this function and * networkstatus_parse_vote_from_string(). */ directory_token_t *tok; memarea_t *area = NULL; digests_t *digests; smartlist_t *tokens = smartlist_new(); ns_detached_signatures_t *sigs = tor_malloc_zero(sizeof(ns_detached_signatures_t)); sigs->digests = strmap_new(); sigs->signatures = strmap_new(); if (!eos) eos = s + strlen(s); area = memarea_new(); if (tokenize_string(area,s, eos, tokens, networkstatus_detached_signature_token_table, 0)) { log_warn(LD_DIR, "Error tokenizing detached networkstatus signatures"); goto err; } /* Grab all the digest-like tokens. */ SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) { const char *algname; digest_algorithm_t alg; const char *flavor; const char *hexdigest; size_t expected_length; tok = _tok; if (tok->tp == K_CONSENSUS_DIGEST) { algname = "sha1"; alg = DIGEST_SHA1; flavor = "ns"; hexdigest = tok->args[0]; } else if (tok->tp == K_ADDITIONAL_DIGEST) { int a = crypto_digest_algorithm_parse_name(tok->args[1]); if (a<0) { log_warn(LD_DIR, "Unrecognized algorithm name %s", tok->args[0]); continue; } alg = (digest_algorithm_t) a; flavor = tok->args[0]; algname = tok->args[1]; hexdigest = tok->args[2]; } else { continue; } expected_length = (alg == DIGEST_SHA1) ? HEX_DIGEST_LEN : HEX_DIGEST256_LEN; if (strlen(hexdigest) != expected_length) { log_warn(LD_DIR, "Wrong length on consensus-digest in detached " "networkstatus signatures"); goto err; } digests = detached_get_digests(sigs, flavor); tor_assert(digests); if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) { log_warn(LD_DIR, "Multiple digests for %s with %s on detached " "signatures document", flavor, algname); continue; } if (base16_decode(digests->d[alg], DIGEST256_LEN, hexdigest, strlen(hexdigest)) < 0) { log_warn(LD_DIR, "Bad encoding on consensus-digest in detached " "networkstatus signatures"); goto err; } } SMARTLIST_FOREACH_END(_tok); tok = find_by_keyword(tokens, K_VALID_AFTER); if (parse_iso_time(tok->args[0], &sigs->valid_after)) { log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures"); goto err; } tok = find_by_keyword(tokens, K_FRESH_UNTIL); if (parse_iso_time(tok->args[0], &sigs->fresh_until)) { log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures"); goto err; } tok = find_by_keyword(tokens, K_VALID_UNTIL); if (parse_iso_time(tok->args[0], &sigs->valid_until)) { log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures"); goto err; } SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) { const char *id_hexdigest; const char *sk_hexdigest; const char *algname; const char *flavor; digest_algorithm_t alg; char id_digest[DIGEST_LEN]; char sk_digest[DIGEST_LEN]; smartlist_t *siglist; document_signature_t *sig; int is_duplicate; tok = _tok; if (tok->tp == K_DIRECTORY_SIGNATURE) { tor_assert(tok->n_args >= 2); flavor = "ns"; algname = "sha1"; id_hexdigest = tok->args[0]; sk_hexdigest = tok->args[1]; } else if (tok->tp == K_ADDITIONAL_SIGNATURE) { tor_assert(tok->n_args >= 4); flavor = tok->args[0]; algname = tok->args[1]; id_hexdigest = tok->args[2]; sk_hexdigest = tok->args[3]; } else { continue; } { int a = crypto_digest_algorithm_parse_name(algname); if (a<0) { log_warn(LD_DIR, "Unrecognized algorithm name %s", algname); continue; } alg = (digest_algorithm_t) a; } if (!tok->object_type || strcmp(tok->object_type, "SIGNATURE") || tok->object_size < 128 || tok->object_size > 512) { log_warn(LD_DIR, "Bad object type or length on directory-signature"); goto err; } if (strlen(id_hexdigest) != HEX_DIGEST_LEN || base16_decode(id_digest, sizeof(id_digest), id_hexdigest, HEX_DIGEST_LEN) < 0) { log_warn(LD_DIR, "Error decoding declared identity %s in " "network-status vote.", escaped(id_hexdigest)); goto err; } if (strlen(sk_hexdigest) != HEX_DIGEST_LEN || base16_decode(sk_digest, sizeof(sk_digest), sk_hexdigest, HEX_DIGEST_LEN) < 0) { log_warn(LD_DIR, "Error decoding declared signing key digest %s in " "network-status vote.", escaped(sk_hexdigest)); goto err; } siglist = detached_get_signatures(sigs, flavor); is_duplicate = 0; SMARTLIST_FOREACH(siglist, document_signature_t *, dsig, { if (dsig->alg == alg && tor_memeq(id_digest, dsig->identity_digest, DIGEST_LEN) && tor_memeq(sk_digest, dsig->signing_key_digest, DIGEST_LEN)) { is_duplicate = 1; } }); if (is_duplicate) { log_warn(LD_DIR, "Two signatures with identical keys and algorithm " "found."); continue; } sig = tor_malloc_zero(sizeof(document_signature_t)); sig->alg = alg; memcpy(sig->identity_digest, id_digest, DIGEST_LEN); memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN); if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) { tor_free(sig); goto err; } sig->signature = tor_memdup(tok->object_body, tok->object_size); sig->signature_len = (int) tok->object_size; smartlist_add(siglist, sig); } SMARTLIST_FOREACH_END(_tok); goto done; err: ns_detached_signatures_free(sigs); sigs = NULL; done: SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) { DUMP_AREA(area, "detached signatures"); memarea_drop_all(area); } return sigs; } /** Parse the addr policy in the string s and return it. If * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or * ADDR_POLICY_REJECT) for items that specify no action. * * The addr_policy_t returned by this function can have its address set to * AF_UNSPEC for '*'. Use policy_expand_unspec() to turn this into a pair * of AF_INET and AF_INET6 items. */ addr_policy_t * router_parse_addr_policy_item_from_string(const char *s, int assume_action) { directory_token_t *tok = NULL; const char *cp, *eos; /* Longest possible policy is "accept ffff:ffff:..255/ffff:...255:0-65535". * But note that there can be an arbitrary amount of space between the * accept and the address:mask/port element. */ char line[TOR_ADDR_BUF_LEN*2 + 32]; addr_policy_t *r; memarea_t *area = NULL; s = eat_whitespace(s); if ((*s == '*' || TOR_ISDIGIT(*s)) && assume_action >= 0) { if (tor_snprintf(line, sizeof(line), "%s %s", assume_action == ADDR_POLICY_ACCEPT?"accept":"reject", s)<0) { log_warn(LD_DIR, "Policy %s is too long.", escaped(s)); return NULL; } cp = line; tor_strlower(line); } else { /* assume an already well-formed address policy line */ cp = s; } eos = cp + strlen(cp); area = memarea_new(); tok = get_next_token(area, &cp, eos, routerdesc_token_table); if (tok->tp == ERR_) { log_warn(LD_DIR, "Error reading address policy: %s", tok->error); goto err; } if (tok->tp != K_ACCEPT && tok->tp != K_ACCEPT6 && tok->tp != K_REJECT && tok->tp != K_REJECT6) { log_warn(LD_DIR, "Expected 'accept' or 'reject'."); goto err; } r = router_parse_addr_policy(tok, TAPMP_EXTENDED_STAR); goto done; err: r = NULL; done: token_clear(tok); if (area) { DUMP_AREA(area, "policy item"); memarea_drop_all(area); } return r; } /** Add an exit policy stored in the token tok to the router info in * router. Return 0 on success, -1 on failure. */ static int router_add_exit_policy(routerinfo_t *router, directory_token_t *tok) { addr_policy_t *newe; newe = router_parse_addr_policy(tok, 0); if (!newe) return -1; if (! router->exit_policy) router->exit_policy = smartlist_new(); if (((tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) && tor_addr_family(&newe->addr) == AF_INET) || ((tok->tp == K_ACCEPT || tok->tp == K_REJECT) && tor_addr_family(&newe->addr) == AF_INET6)) { log_warn(LD_DIR, "Mismatch between field type and address type in exit " "policy"); addr_policy_free(newe); return -1; } smartlist_add(router->exit_policy, newe); return 0; } /** Given a K_ACCEPT or K_REJECT token and a router, create and return * a new exit_policy_t corresponding to the token. */ static addr_policy_t * router_parse_addr_policy(directory_token_t *tok, unsigned fmt_flags) { addr_policy_t newe; char *arg; tor_assert(tok->tp == K_REJECT || tok->tp == K_REJECT6 || tok->tp == K_ACCEPT || tok->tp == K_ACCEPT6); if (tok->n_args != 1) return NULL; arg = tok->args[0]; if (!strcmpstart(arg,"private")) return router_parse_addr_policy_private(tok); memset(&newe, 0, sizeof(newe)); if (tok->tp == K_REJECT || tok->tp == K_REJECT6) newe.policy_type = ADDR_POLICY_REJECT; else newe.policy_type = ADDR_POLICY_ACCEPT; if (tor_addr_parse_mask_ports(arg, fmt_flags, &newe.addr, &newe.maskbits, &newe.prt_min, &newe.prt_max) < 0) { log_warn(LD_DIR,"Couldn't parse line %s. Dropping", escaped(arg)); return NULL; } return addr_policy_get_canonical_entry(&newe); } /** Parse an exit policy line of the format "accept/reject private:...". * This didn't exist until Tor 0.1.1.15, so nobody should generate it in * router descriptors until earlier versions are obsolete. */ static addr_policy_t * router_parse_addr_policy_private(directory_token_t *tok) { const char *arg; uint16_t port_min, port_max; addr_policy_t result; arg = tok->args[0]; if (strcmpstart(arg, "private")) return NULL; arg += strlen("private"); arg = (char*) eat_whitespace(arg); if (!arg || *arg != ':') return NULL; if (parse_port_range(arg+1, &port_min, &port_max)<0) return NULL; memset(&result, 0, sizeof(result)); if (tok->tp == K_REJECT || tok->tp == K_REJECT6) result.policy_type = ADDR_POLICY_REJECT; else result.policy_type = ADDR_POLICY_ACCEPT; result.is_private = 1; result.prt_min = port_min; result.prt_max = port_max; return addr_policy_get_canonical_entry(&result); } /** Log and exit if t is malformed */ void assert_addr_policy_ok(smartlist_t *lst) { if (!lst) return; SMARTLIST_FOREACH(lst, addr_policy_t *, t, { tor_assert(t->policy_type == ADDR_POLICY_REJECT || t->policy_type == ADDR_POLICY_ACCEPT); tor_assert(t->prt_min <= t->prt_max); }); } /* * Low-level tokenizer for router descriptors and directories. */ /** Free all resources allocated for tok */ static void token_clear(directory_token_t *tok) { if (tok->key) crypto_pk_free(tok->key); } #define ALLOC_ZERO(sz) memarea_alloc_zero(area,sz) #define ALLOC(sz) memarea_alloc(area,sz) #define STRDUP(str) memarea_strdup(area,str) #define STRNDUP(str,n) memarea_strndup(area,(str),(n)) #define RET_ERR(msg) \ STMT_BEGIN \ if (tok) token_clear(tok); \ tok = ALLOC_ZERO(sizeof(directory_token_t)); \ tok->tp = ERR_; \ tok->error = STRDUP(msg); \ goto done_tokenizing; \ STMT_END /** Helper: make sure that the token tok with keyword kwd obeys * the object syntax of o_syn. Allocate all storage in area. * Return tok on success, or a new ERR_ token if the token didn't * conform to the syntax we wanted. **/ static INLINE directory_token_t * token_check_object(memarea_t *area, const char *kwd, directory_token_t *tok, obj_syntax o_syn) { char ebuf[128]; switch (o_syn) { case NO_OBJ: /* No object is allowed for this token. */ if (tok->object_body) { tor_snprintf(ebuf, sizeof(ebuf), "Unexpected object for %s", kwd); RET_ERR(ebuf); } if (tok->key) { tor_snprintf(ebuf, sizeof(ebuf), "Unexpected public key for %s", kwd); RET_ERR(ebuf); } break; case NEED_OBJ: /* There must be a (non-key) object. */ if (!tok->object_body) { tor_snprintf(ebuf, sizeof(ebuf), "Missing object for %s", kwd); RET_ERR(ebuf); } break; case NEED_KEY_1024: /* There must be a 1024-bit public key. */ case NEED_SKEY_1024: /* There must be a 1024-bit private key. */ if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) { tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits", kwd, crypto_pk_num_bits(tok->key)); RET_ERR(ebuf); } /* fall through */ case NEED_KEY: /* There must be some kind of key. */ if (!tok->key) { tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd); RET_ERR(ebuf); } if (o_syn != NEED_SKEY_1024) { if (crypto_pk_key_is_private(tok->key)) { tor_snprintf(ebuf, sizeof(ebuf), "Private key given for %s, which wants a public key", kwd); RET_ERR(ebuf); } } else { /* o_syn == NEED_SKEY_1024 */ if (!crypto_pk_key_is_private(tok->key)) { tor_snprintf(ebuf, sizeof(ebuf), "Public key given for %s, which wants a private key", kwd); RET_ERR(ebuf); } } break; case OBJ_OK: /* Anything goes with this token. */ break; } done_tokenizing: return tok; } /** Helper: parse space-separated arguments from the string s ending at * eol, and store them in the args field of tok. Store the * number of parsed elements into the n_args field of tok. Allocate * all storage in area. Return the number of arguments parsed, or * return -1 if there was an insanely high number of arguments. */ static INLINE int get_token_arguments(memarea_t *area, directory_token_t *tok, const char *s, const char *eol) { /** Largest number of arguments we'll accept to any token, ever. */ #define MAX_ARGS 512 char *mem = memarea_strndup(area, s, eol-s); char *cp = mem; int j = 0; char *args[MAX_ARGS]; while (*cp) { if (j == MAX_ARGS) return -1; args[j++] = cp; cp = (char*)find_whitespace(cp); if (!cp || !*cp) break; /* End of the line. */ *cp++ = '\0'; cp = (char*)eat_whitespace(cp); } tok->n_args = j; tok->args = memarea_memdup(area, args, j*sizeof(char*)); return j; #undef MAX_ARGS } /** Helper function: read the next token from *s, advance *s to the end of the * token, and return the parsed token. Parse *s according to the list * of tokens in table. */ static directory_token_t * get_next_token(memarea_t *area, const char **s, const char *eos, token_rule_t *table) { /** Reject any object at least this big; it is probably an overflow, an * attack, a bug, or some other nonsense. */ #define MAX_UNPARSED_OBJECT_SIZE (128*1024) /** Reject any line at least this big; it is probably an overflow, an * attack, a bug, or some other nonsense. */ #define MAX_LINE_LENGTH (128*1024) const char *next, *eol, *obstart; size_t obname_len; int i; directory_token_t *tok; obj_syntax o_syn = NO_OBJ; char ebuf[128]; const char *kwd = ""; tor_assert(area); tok = ALLOC_ZERO(sizeof(directory_token_t)); tok->tp = ERR_; /* Set *s to first token, eol to end-of-line, next to after first token */ *s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */ tor_assert(eos >= *s); eol = memchr(*s, '\n', eos-*s); if (!eol) eol = eos; if (eol - *s > MAX_LINE_LENGTH) { RET_ERR("Line far too long"); } next = find_whitespace_eos(*s, eol); if (!strcmp_len(*s, "opt", next-*s)) { /* Skip past an "opt" at the start of the line. */ *s = eat_whitespace_eos_no_nl(next, eol); next = find_whitespace_eos(*s, eol); } else if (*s == eos) { /* If no "opt", and end-of-line, line is invalid */ RET_ERR("Unexpected EOF"); } /* Search the table for the appropriate entry. (I tried a binary search * instead, but it wasn't any faster.) */ for (i = 0; table[i].t ; ++i) { if (!strcmp_len(*s, table[i].t, next-*s)) { /* We've found the keyword. */ kwd = table[i].t; tok->tp = table[i].v; o_syn = table[i].os; *s = eat_whitespace_eos_no_nl(next, eol); /* We go ahead whether there are arguments or not, so that tok->args is * always set if we want arguments. */ if (table[i].concat_args) { /* The keyword takes the line as a single argument */ tok->args = ALLOC(sizeof(char*)); tok->args[0] = STRNDUP(*s,eol-*s); /* Grab everything on line */ tok->n_args = 1; } else { /* This keyword takes multiple arguments. */ if (get_token_arguments(area, tok, *s, eol)<0) { tor_snprintf(ebuf, sizeof(ebuf),"Far too many arguments to %s", kwd); RET_ERR(ebuf); } *s = eol; } if (tok->n_args < table[i].min_args) { tor_snprintf(ebuf, sizeof(ebuf), "Too few arguments to %s", kwd); RET_ERR(ebuf); } else if (tok->n_args > table[i].max_args) { tor_snprintf(ebuf, sizeof(ebuf), "Too many arguments to %s", kwd); RET_ERR(ebuf); } break; } } if (tok->tp == ERR_) { /* No keyword matched; call it an "K_opt" or "A_unrecognized" */ if (**s == '@') tok->tp = A_UNKNOWN_; else tok->tp = K_OPT; tok->args = ALLOC(sizeof(char*)); tok->args[0] = STRNDUP(*s, eol-*s); tok->n_args = 1; o_syn = OBJ_OK; } /* Check whether there's an object present */ *s = eat_whitespace_eos(eol, eos); /* Scan from end of first line */ tor_assert(eos >= *s); eol = memchr(*s, '\n', eos-*s); if (!eol || eol-*s<11 || strcmpstart(*s, "-----BEGIN ")) /* No object. */ goto check_object; obstart = *s; /* Set obstart to start of object spec */ if (*s+16 >= eol || memchr(*s+11,'\0',eol-*s-16) || /* no short lines, */ strcmp_len(eol-5, "-----", 5) || /* nuls or invalid endings */ (eol-*s) > MAX_UNPARSED_OBJECT_SIZE) { /* name too long */ RET_ERR("Malformed object: bad begin line"); } tok->object_type = STRNDUP(*s+11, eol-*s-16); obname_len = eol-*s-16; /* store objname length here to avoid a strlen() */ *s = eol+1; /* Set *s to possible start of object data (could be eos) */ /* Go to the end of the object */ next = tor_memstr(*s, eos-*s, "-----END "); if (!next) { RET_ERR("Malformed object: missing object end line"); } tor_assert(eos >= next); eol = memchr(next, '\n', eos-next); if (!eol) /* end-of-line marker, or eos if there's no '\n' */ eol = eos; /* Validate the ending tag, which should be 9 + NAME + 5 + eol */ if ((size_t)(eol-next) != 9+obname_len+5 || strcmp_len(next+9, tok->object_type, obname_len) || strcmp_len(eol-5, "-----", 5)) { tor_snprintf(ebuf, sizeof(ebuf), "Malformed object: mismatched end tag %s", tok->object_type); ebuf[sizeof(ebuf)-1] = '\0'; RET_ERR(ebuf); } if (next - *s > MAX_UNPARSED_OBJECT_SIZE) RET_ERR("Couldn't parse object: missing footer or object much too big."); if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */ tok->key = crypto_pk_new(); if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart)) RET_ERR("Couldn't parse public key."); } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */ tok->key = crypto_pk_new(); if (crypto_pk_read_private_key_from_string(tok->key, obstart, eol-obstart)) RET_ERR("Couldn't parse private key."); } else { /* If it's something else, try to base64-decode it */ int r; tok->object_body = ALLOC(next-*s); /* really, this is too much RAM. */ r = base64_decode(tok->object_body, next-*s, *s, next-*s); if (r<0) RET_ERR("Malformed object: bad base64-encoded data"); tok->object_size = r; } *s = eol; check_object: tok = token_check_object(area, kwd, tok, o_syn); done_tokenizing: return tok; #undef RET_ERR #undef ALLOC #undef ALLOC_ZERO #undef STRDUP #undef STRNDUP } /** Read all tokens from a string between start and end, and add * them to out. Parse according to the token rules in table. * Caller must free tokens in out. If end is NULL, use the * entire string. */ static int tokenize_string(memarea_t *area, const char *start, const char *end, smartlist_t *out, token_rule_t *table, int flags) { const char **s; directory_token_t *tok = NULL; int counts[NIL_]; int i; int first_nonannotation; int prev_len = smartlist_len(out); tor_assert(area); s = &start; if (!end) { end = start+strlen(start); } else { /* it's only meaningful to check for nuls if we got an end-of-string ptr */ if (memchr(start, '\0', end-start)) { log_warn(LD_DIR, "parse error: internal NUL character."); return -1; } } for (i = 0; i < NIL_; ++i) counts[i] = 0; SMARTLIST_FOREACH(out, const directory_token_t *, t, ++counts[t->tp]); while (*s < end && (!tok || tok->tp != EOF_)) { tok = get_next_token(area, s, end, table); if (tok->tp == ERR_) { log_warn(LD_DIR, "parse error: %s", tok->error); token_clear(tok); return -1; } ++counts[tok->tp]; smartlist_add(out, tok); *s = eat_whitespace_eos(*s, end); } if (flags & TS_NOCHECK) return 0; if ((flags & TS_ANNOTATIONS_OK)) { first_nonannotation = -1; for (i = 0; i < smartlist_len(out); ++i) { tok = smartlist_get(out, i); if (tok->tp < MIN_ANNOTATION || tok->tp > MAX_ANNOTATION) { first_nonannotation = i; break; } } if (first_nonannotation < 0) { log_warn(LD_DIR, "parse error: item contains only annotations"); return -1; } for (i=first_nonannotation; i < smartlist_len(out); ++i) { tok = smartlist_get(out, i); if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) { log_warn(LD_DIR, "parse error: Annotations mixed with keywords"); return -1; } } if ((flags & TS_NO_NEW_ANNOTATIONS)) { if (first_nonannotation != prev_len) { log_warn(LD_DIR, "parse error: Unexpected annotations."); return -1; } } } else { for (i=0; i < smartlist_len(out); ++i) { tok = smartlist_get(out, i); if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) { log_warn(LD_DIR, "parse error: no annotations allowed."); return -1; } } first_nonannotation = 0; } for (i = 0; table[i].t; ++i) { if (counts[table[i].v] < table[i].min_cnt) { log_warn(LD_DIR, "Parse error: missing %s element.", table[i].t); return -1; } if (counts[table[i].v] > table[i].max_cnt) { log_warn(LD_DIR, "Parse error: too many %s elements.", table[i].t); return -1; } if (table[i].pos & AT_START) { if (smartlist_len(out) < 1 || (tok = smartlist_get(out, first_nonannotation))->tp != table[i].v) { log_warn(LD_DIR, "Parse error: first item is not %s.", table[i].t); return -1; } } if (table[i].pos & AT_END) { if (smartlist_len(out) < 1 || (tok = smartlist_get(out, smartlist_len(out)-1))->tp != table[i].v) { log_warn(LD_DIR, "Parse error: last item is not %s.", table[i].t); return -1; } } } return 0; } /** Find the first token in s whose keyword is keyword; return * NULL if no such keyword is found. */ static directory_token_t * find_opt_by_keyword(smartlist_t *s, directory_keyword keyword) { SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t); return NULL; } /** Find the first token in s whose keyword is keyword; fail * with an assert if no such keyword is found. */ static directory_token_t * find_by_keyword_(smartlist_t *s, directory_keyword keyword, const char *keyword_as_string) { directory_token_t *tok = find_opt_by_keyword(s, keyword); if (PREDICT_UNLIKELY(!tok)) { log_err(LD_BUG, "Missing %s [%d] in directory object that should have " "been validated. Internal error.", keyword_as_string, (int)keyword); tor_assert(tok); } return tok; } /** If there are any directory_token_t entries in s whose keyword is * k, return a newly allocated smartlist_t containing all such entries, * in the same order in which they occur in s. Otherwise return * NULL. */ static smartlist_t * find_all_by_keyword(smartlist_t *s, directory_keyword k) { smartlist_t *out = NULL; SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == k) { if (!out) out = smartlist_new(); smartlist_add(out, t); }); return out; } /** Return a newly allocated smartlist of all accept or reject tokens in * s. */ static smartlist_t * find_all_exitpolicy(smartlist_t *s) { smartlist_t *out = smartlist_new(); SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == K_ACCEPT || t->tp == K_ACCEPT6 || t->tp == K_REJECT || t->tp == K_REJECT6) smartlist_add(out,t)); return out; } /** Helper function for router_get_hash_impl: given s, * s_len, start_str, end_str, and end_c with the * same semantics as in that function, set *start_out (inclusive) and * *end_out (exclusive) to the boundaries of the string to be hashed. * * Return 0 on success and -1 on failure. */ static int router_get_hash_impl_helper(const char *s, size_t s_len, const char *start_str, const char *end_str, char end_c, const char **start_out, const char **end_out) { const char *start, *end; start = tor_memstr(s, s_len, start_str); if (!start) { log_warn(LD_DIR,"couldn't find start of hashed material \"%s\"",start_str); return -1; } if (start != s && *(start-1) != '\n') { log_warn(LD_DIR, "first occurrence of \"%s\" is not at the start of a line", start_str); return -1; } end = tor_memstr(start+strlen(start_str), s_len - (start-s) - strlen(start_str), end_str); if (!end) { log_warn(LD_DIR,"couldn't find end of hashed material \"%s\"",end_str); return -1; } end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str)); if (!end) { log_warn(LD_DIR,"couldn't find EOL"); return -1; } ++end; *start_out = start; *end_out = end; return 0; } /** Compute the digest of the substring of s taken from the first * occurrence of start_str through the first instance of c after the * first subsequent occurrence of end_str; store the 20-byte or 32-byte * result in digest; return 0 on success. * * If no such substring exists, return -1. */ static int router_get_hash_impl(const char *s, size_t s_len, char *digest, const char *start_str, const char *end_str, char end_c, digest_algorithm_t alg) { const char *start=NULL, *end=NULL; if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c, &start,&end)<0) return -1; if (alg == DIGEST_SHA1) { if (crypto_digest(digest, start, end-start)) { log_warn(LD_BUG,"couldn't compute digest"); return -1; } } else { if (crypto_digest256(digest, start, end-start, alg)) { log_warn(LD_BUG,"couldn't compute digest"); return -1; } } return 0; } /** As router_get_hash_impl, but compute all hashes. */ static int router_get_hashes_impl(const char *s, size_t s_len, digests_t *digests, const char *start_str, const char *end_str, char end_c) { const char *start=NULL, *end=NULL; if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c, &start,&end)<0) return -1; if (crypto_digest_all(digests, start, end-start)) { log_warn(LD_BUG,"couldn't compute digests"); return -1; } return 0; } /** Assuming that s starts with a microdesc, return the start of the * *NEXT* one. Return NULL on "not found." */ static const char * find_start_of_next_microdesc(const char *s, const char *eos) { int started_with_annotations; s = eat_whitespace_eos(s, eos); if (!s) return NULL; #define CHECK_LENGTH() STMT_BEGIN \ if (s+32 > eos) \ return NULL; \ STMT_END #define NEXT_LINE() STMT_BEGIN \ s = memchr(s, '\n', eos-s); \ if (!s || s+1 >= eos) \ return NULL; \ s++; \ STMT_END CHECK_LENGTH(); started_with_annotations = (*s == '@'); if (started_with_annotations) { /* Start by advancing to the first non-annotation line. */ while (*s == '@') NEXT_LINE(); } CHECK_LENGTH(); /* Now we should be pointed at an onion-key line. If we are, then skip * it. */ if (!strcmpstart(s, "onion-key")) NEXT_LINE(); /* Okay, now we're pointed at the first line of the microdescriptor which is not an annotation or onion-key. The next line that _is_ an annotation or onion-key is the start of the next microdescriptor. */ while (s+32 < eos) { if (*s == '@' || !strcmpstart(s, "onion-key")) return s; NEXT_LINE(); } return NULL; #undef CHECK_LENGTH #undef NEXT_LINE } /** Parse as many microdescriptors as are found from the string starting at * s and ending at eos. If allow_annotations is set, read any * annotations we recognize and ignore ones we don't. * * If saved_location isn't SAVED_IN_CACHE, make a local copy of each * descriptor in the body field of each microdesc_t. * * Return all newly * parsed microdescriptors in a newly allocated smartlist_t. */ smartlist_t * microdescs_parse_from_string(const char *s, const char *eos, int allow_annotations, saved_location_t where) { smartlist_t *tokens; smartlist_t *result; microdesc_t *md = NULL; memarea_t *area; const char *start = s; const char *start_of_next_microdesc; int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0; const int copy_body = (where != SAVED_IN_CACHE); directory_token_t *tok; if (!eos) eos = s + strlen(s); s = eat_whitespace_eos(s, eos); area = memarea_new(); result = smartlist_new(); tokens = smartlist_new(); while (s < eos) { start_of_next_microdesc = find_start_of_next_microdesc(s, eos); if (!start_of_next_microdesc) start_of_next_microdesc = eos; if (tokenize_string(area, s, start_of_next_microdesc, tokens, microdesc_token_table, flags)) { log_warn(LD_DIR, "Unparseable microdescriptor"); goto next; } md = tor_malloc_zero(sizeof(microdesc_t)); { const char *cp = tor_memstr(s, start_of_next_microdesc-s, "onion-key"); tor_assert(cp); md->bodylen = start_of_next_microdesc - cp; md->saved_location = where; if (copy_body) md->body = tor_memdup_nulterm(cp, md->bodylen); else md->body = (char*)cp; md->off = cp - start; } if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) { if (parse_iso_time(tok->args[0], &md->last_listed)) { log_warn(LD_DIR, "Bad last-listed time in microdescriptor"); goto next; } } tok = find_by_keyword(tokens, K_ONION_KEY); if (!crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_DIR, "Relay's onion key had invalid exponent."); goto next; } md->onion_pkey = tok->key; tok->key = NULL; if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) { curve25519_public_key_t k; tor_assert(tok->n_args >= 1); if (curve25519_public_from_base64(&k, tok->args[0]) < 0) { log_warn(LD_DIR, "Bogus ntor-onion-key in microdesc"); goto next; } md->onion_curve25519_pkey = tor_memdup(&k, sizeof(curve25519_public_key_t)); } { smartlist_t *a_lines = find_all_by_keyword(tokens, K_A); if (a_lines) { find_single_ipv6_orport(a_lines, &md->ipv6_addr, &md->ipv6_orport); smartlist_free(a_lines); } } if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) { int i; md->family = smartlist_new(); for (i=0;in_args;++i) { if (!is_legal_nickname_or_hexdigest(tok->args[i])) { log_warn(LD_DIR, "Illegal nickname %s in family line", escaped(tok->args[i])); goto next; } smartlist_add(md->family, tor_strdup(tok->args[i])); } } if ((tok = find_opt_by_keyword(tokens, K_P))) { md->exit_policy = parse_short_policy(tok->args[0]); } if ((tok = find_opt_by_keyword(tokens, K_P6))) { md->ipv6_exit_policy = parse_short_policy(tok->args[0]); } crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256); smartlist_add(result, md); md = NULL; next: microdesc_free(md); md = NULL; memarea_clear(area); smartlist_clear(tokens); s = start_of_next_microdesc; } memarea_drop_all(area); smartlist_free(tokens); return result; } /** Return true iff this Tor version can answer directory questions * about microdescriptors. */ int tor_version_supports_microdescriptors(const char *platform) { return tor_version_as_new_as(platform, "0.2.3.1-alpha"); } /** Parse the Tor version of the platform string platform, * and compare it to the version in cutoff. Return 1 if * the router is at least as new as the cutoff, else return 0. */ int tor_version_as_new_as(const char *platform, const char *cutoff) { tor_version_t cutoff_version, router_version; char *s, *s2, *start; char tmp[128]; tor_assert(platform); if (tor_version_parse(cutoff, &cutoff_version)<0) { log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff); return 0; } if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; be safe and say yes */ return 1; start = (char *)eat_whitespace(platform+3); if (!*start) return 0; s = (char *)find_whitespace(start); /* also finds '\0', which is fine */ s2 = (char*)eat_whitespace(s); if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-")) s = (char*)find_whitespace(s2); if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */ return 0; strlcpy(tmp, start, s-start+1); if (tor_version_parse(tmp, &router_version)<0) { log_info(LD_DIR,"Router version '%s' unparseable.",tmp); return 1; /* be safe and say yes */ } /* Here's why we don't need to do any special handling for svn revisions: * - If neither has an svn revision, we're fine. * - If the router doesn't have an svn revision, we can't assume that it * is "at least" any svn revision, so we need to return 0. * - If the target version doesn't have an svn revision, any svn revision * (or none at all) is good enough, so return 1. * - If both target and router have an svn revision, we compare them. */ return tor_version_compare(&router_version, &cutoff_version) >= 0; } /** Parse a tor version from s, and store the result in out. * Return 0 on success, -1 on failure. */ int tor_version_parse(const char *s, tor_version_t *out) { char *eos=NULL; const char *cp=NULL; /* Format is: * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ - tag ] ] */ tor_assert(s); tor_assert(out); memset(out, 0, sizeof(tor_version_t)); if (!strcasecmpstart(s, "Tor ")) s += 4; /* Get major. */ out->major = (int)strtol(s,&eos,10); if (!eos || eos==s || *eos != '.') return -1; cp = eos+1; /* Get minor */ out->minor = (int) strtol(cp,&eos,10); if (!eos || eos==cp || *eos != '.') return -1; cp = eos+1; /* Get micro */ out->micro = (int) strtol(cp,&eos,10); if (!eos || eos==cp) return -1; if (!*eos) { out->status = VER_RELEASE; out->patchlevel = 0; return 0; } cp = eos; /* Get status */ if (*cp == '.') { out->status = VER_RELEASE; ++cp; } else if (0==strncmp(cp, "pre", 3)) { out->status = VER_PRE; cp += 3; } else if (0==strncmp(cp, "rc", 2)) { out->status = VER_RC; cp += 2; } else { return -1; } /* Get patchlevel */ out->patchlevel = (int) strtol(cp,&eos,10); if (!eos || eos==cp) return -1; cp = eos; /* Get status tag. */ if (*cp == '-' || *cp == '.') ++cp; eos = (char*) find_whitespace(cp); if (eos-cp >= (int)sizeof(out->status_tag)) strlcpy(out->status_tag, cp, sizeof(out->status_tag)); else { memcpy(out->status_tag, cp, eos-cp); out->status_tag[eos-cp] = 0; } cp = eat_whitespace(eos); if (!strcmpstart(cp, "(r")) { cp += 2; out->svn_revision = (int) strtol(cp,&eos,10); } else if (!strcmpstart(cp, "(git-")) { char *close_paren = strchr(cp, ')'); int hexlen; char digest[DIGEST_LEN]; if (! close_paren) return -1; cp += 5; if (close_paren-cp > HEX_DIGEST_LEN) return -1; hexlen = (int)(close_paren-cp); memwipe(digest, 0, sizeof(digest)); if ( hexlen == 0 || (hexlen % 2) == 1) return -1; if (base16_decode(digest, hexlen/2, cp, hexlen)) return -1; memcpy(out->git_tag, digest, hexlen/2); out->git_tag_len = hexlen/2; } return 0; } /** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a > * b. */ int tor_version_compare(tor_version_t *a, tor_version_t *b) { int i; tor_assert(a); tor_assert(b); if ((i = a->major - b->major)) return i; else if ((i = a->minor - b->minor)) return i; else if ((i = a->micro - b->micro)) return i; else if ((i = a->status - b->status)) return i; else if ((i = a->patchlevel - b->patchlevel)) return i; else if ((i = strcmp(a->status_tag, b->status_tag))) return i; else if ((i = a->svn_revision - b->svn_revision)) return i; else if ((i = a->git_tag_len - b->git_tag_len)) return i; else if (a->git_tag_len) return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len); else return 0; } /** Return true iff versions a and b belong to the same series. */ int tor_version_same_series(tor_version_t *a, tor_version_t *b) { tor_assert(a); tor_assert(b); return ((a->major == b->major) && (a->minor == b->minor) && (a->micro == b->micro)); } /** Helper: Given pointers to two strings describing tor versions, return -1 * if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent. * Used to sort a list of versions. */ static int compare_tor_version_str_ptr_(const void **_a, const void **_b) { const char *a = *_a, *b = *_b; int ca, cb; tor_version_t va, vb; ca = tor_version_parse(a, &va); cb = tor_version_parse(b, &vb); /* If they both parse, compare them. */ if (!ca && !cb) return tor_version_compare(&va,&vb); /* If one parses, it comes first. */ if (!ca && cb) return -1; if (ca && !cb) return 1; /* If neither parses, compare strings. Also, the directory server admin ** needs to be smacked upside the head. But Tor is tolerant and gentle. */ return strcmp(a,b); } /** Sort a list of string-representations of versions in ascending order. */ void sort_version_list(smartlist_t *versions, int remove_duplicates) { smartlist_sort(versions, compare_tor_version_str_ptr_); if (remove_duplicates) smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_); } /** Parse and validate the ASCII-encoded v2 descriptor in desc, * write the parsed descriptor to the newly allocated *parsed_out, the * binary descriptor ID of length DIGEST_LEN to desc_id_out, the * encrypted introduction points to the newly allocated * *intro_points_encrypted_out, their encrypted size to * *intro_points_encrypted_size_out, the size of the encoded descriptor * to *encoded_size_out, and a pointer to the possibly next * descriptor to *next_out; return 0 for success (including validation) * and -1 for failure. */ int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, char *desc_id_out, char **intro_points_encrypted_out, size_t *intro_points_encrypted_size_out, size_t *encoded_size_out, const char **next_out, const char *desc) { rend_service_descriptor_t *result = tor_malloc_zero(sizeof(rend_service_descriptor_t)); char desc_hash[DIGEST_LEN]; const char *eos; smartlist_t *tokens = smartlist_new(); directory_token_t *tok; char secret_id_part[DIGEST_LEN]; int i, version, num_ok=1; smartlist_t *versions; char public_key_hash[DIGEST_LEN]; char test_desc_id[DIGEST_LEN]; memarea_t *area = NULL; tor_assert(desc); /* Check if desc starts correctly. */ if (strncmp(desc, "rendezvous-service-descriptor ", strlen("rendezvous-service-descriptor "))) { log_info(LD_REND, "Descriptor does not start correctly."); goto err; } /* Compute descriptor hash for later validation. */ if (router_get_hash_impl(desc, strlen(desc), desc_hash, "rendezvous-service-descriptor ", "\nsignature", '\n', DIGEST_SHA1) < 0) { log_warn(LD_REND, "Couldn't compute descriptor hash."); goto err; } /* Determine end of string. */ eos = strstr(desc, "\nrendezvous-service-descriptor "); if (!eos) eos = desc + strlen(desc); else eos = eos + 1; /* Check length. */ if (eos-desc > REND_DESC_MAX_SIZE) { /* XXX023 If we are parsing this descriptor as a server, this * should be a protocol warning. */ log_warn(LD_REND, "Descriptor length is %d which exceeds " "maximum rendezvous descriptor size of %d bytes.", (int)(eos-desc), REND_DESC_MAX_SIZE); goto err; } /* Tokenize descriptor. */ area = memarea_new(); if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) { log_warn(LD_REND, "Error tokenizing descriptor."); goto err; } /* Set next to next descriptor, if available. */ *next_out = eos; /* Set length of encoded descriptor. */ *encoded_size_out = eos - desc; /* Check min allowed length of token list. */ if (smartlist_len(tokens) < 7) { log_warn(LD_REND, "Impossibly short descriptor."); goto err; } /* Parse base32-encoded descriptor ID. */ tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR); tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok->n_args == 1); if (strlen(tok->args[0]) != REND_DESC_ID_V2_LEN_BASE32 || strspn(tok->args[0], BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) { log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]); goto err; } if (base32_decode(desc_id_out, DIGEST_LEN, tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) { log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", tok->args[0]); goto err; } /* Parse descriptor version. */ tok = find_by_keyword(tokens, R_VERSION); tor_assert(tok->n_args == 1); result->version = (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL); if (result->version != 2 || !num_ok) { /* If it's <2, it shouldn't be under this format. If the number * is greater than 2, we bumped it because we broke backward * compatibility. See how version numbers in our other formats * work. */ log_warn(LD_REND, "Unrecognized descriptor version: %s", escaped(tok->args[0])); goto err; } /* Parse public key. */ tok = find_by_keyword(tokens, R_PERMANENT_KEY); result->pk = tok->key; tok->key = NULL; /* Prevent free */ /* Parse secret ID part. */ tok = find_by_keyword(tokens, R_SECRET_ID_PART); tor_assert(tok->n_args == 1); if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 || strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) { log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]); goto err; } if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) { log_warn(LD_REND, "Secret ID part contains illegal characters: %s", tok->args[0]); goto err; } /* Parse publication time -- up-to-date check is done when storing the * descriptor. */ tok = find_by_keyword(tokens, R_PUBLICATION_TIME); tor_assert(tok->n_args == 1); if (parse_iso_time(tok->args[0], &result->timestamp) < 0) { log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]); goto err; } /* Parse protocol versions. */ tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS); tor_assert(tok->n_args == 1); versions = smartlist_new(); smartlist_split_string(versions, tok->args[0], ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); for (i = 0; i < smartlist_len(versions); i++) { version = (int) tor_parse_long(smartlist_get(versions, i), 10, 0, INT_MAX, &num_ok, NULL); if (!num_ok) /* It's a string; let's ignore it. */ continue; if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH) /* Avoid undefined left-shift behaviour. */ continue; result->protocols |= 1 << version; } SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp)); smartlist_free(versions); /* Parse encrypted introduction points. Don't verify. */ tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS); if (tok) { if (strcmp(tok->object_type, "MESSAGE")) { log_warn(LD_DIR, "Bad object type: introduction points should be of " "type MESSAGE"); goto err; } *intro_points_encrypted_out = tor_memdup(tok->object_body, tok->object_size); *intro_points_encrypted_size_out = tok->object_size; } else { *intro_points_encrypted_out = NULL; *intro_points_encrypted_size_out = 0; } /* Parse and verify signature. */ tok = find_by_keyword(tokens, R_SIGNATURE); note_crypto_pk_op(VERIFY_RTR); if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0, "v2 rendezvous service descriptor") < 0) goto err; /* Verify that descriptor ID belongs to public key and secret ID part. */ crypto_pk_get_digest(result->pk, public_key_hash); rend_get_descriptor_id_bytes(test_desc_id, public_key_hash, secret_id_part); if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) { log_warn(LD_REND, "Parsed descriptor ID does not match " "computed descriptor ID."); goto err; } goto done; err: rend_service_descriptor_free(result); result = NULL; done: if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); } if (area) memarea_drop_all(area); *parsed_out = result; if (result) return 0; return -1; } /** Decrypt the encrypted introduction points in ipos_encrypted of * length ipos_encrypted_size using descriptor_cookie and * write the result to a newly allocated string that is pointed to by * ipos_decrypted and its length to ipos_decrypted_size. * Return 0 if decryption was successful and -1 otherwise. */ int rend_decrypt_introduction_points(char **ipos_decrypted, size_t *ipos_decrypted_size, const char *descriptor_cookie, const char *ipos_encrypted, size_t ipos_encrypted_size) { tor_assert(ipos_encrypted); tor_assert(descriptor_cookie); if (ipos_encrypted_size < 2) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) { char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN], session_key[CIPHER_KEY_LEN], *dec; int declen, client_blocks; size_t pos = 0, len, client_entries_len; crypto_digest_t *digest; crypto_cipher_t *cipher; client_blocks = (int) ipos_encrypted[1]; client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE * REND_BASIC_AUTH_CLIENT_ENTRY_LEN; if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN); digest = crypto_digest_new(); crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN); crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN); crypto_digest_get_digest(digest, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN); crypto_digest_free(digest); for (pos = 2; pos < 2 + client_entries_len; pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) { if (tor_memeq(ipos_encrypted + pos, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN)) { /* Attempt to decrypt introduction points. */ cipher = crypto_cipher_new(descriptor_cookie); if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted + pos + REND_BASIC_AUTH_CLIENT_ID_LEN, CIPHER_KEY_LEN) < 0) { log_warn(LD_REND, "Could not decrypt session key for client."); crypto_cipher_free(cipher); return -1; } crypto_cipher_free(cipher); len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN; dec = tor_malloc(len); declen = crypto_cipher_decrypt_with_iv(session_key, dec, len, ipos_encrypted + 2 + client_entries_len, ipos_encrypted_size - 2 - client_entries_len); if (declen < 0) { log_warn(LD_REND, "Could not decrypt introduction point string."); tor_free(dec); return -1; } if (fast_memcmpstart(dec, declen, "introduction-point ")) { log_warn(LD_REND, "Decrypted introduction points don't " "look like we could parse them."); tor_free(dec); continue; } *ipos_decrypted = dec; *ipos_decrypted_size = declen; return 0; } } log_warn(LD_REND, "Could not decrypt introduction points. Please " "check your authorization for this service!"); return -1; } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) { char *dec; int declen; if (ipos_encrypted_size < CIPHER_IV_LEN + 2) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1); declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec, ipos_encrypted_size - CIPHER_IV_LEN - 1, ipos_encrypted + 1, ipos_encrypted_size - 1); if (declen < 0) { log_warn(LD_REND, "Decrypting introduction points failed!"); tor_free(dec); return -1; } *ipos_decrypted = dec; *ipos_decrypted_size = declen; return 0; } else { log_warn(LD_REND, "Unknown authorization type number: %d", ipos_encrypted[0]); return -1; } } /** Parse the encoded introduction points in intro_points_encoded of * length intro_points_encoded_size and write the result to the * descriptor in parsed; return the number of successfully parsed * introduction points or -1 in case of a failure. */ int rend_parse_introduction_points(rend_service_descriptor_t *parsed, const char *intro_points_encoded, size_t intro_points_encoded_size) { const char *current_ipo, *end_of_intro_points; smartlist_t *tokens; directory_token_t *tok; rend_intro_point_t *intro; extend_info_t *info; int result, num_ok=1; memarea_t *area = NULL; tor_assert(parsed); /** Function may only be invoked once. */ tor_assert(!parsed->intro_nodes); tor_assert(intro_points_encoded); tor_assert(intro_points_encoded_size > 0); /* Consider one intro point after the other. */ current_ipo = intro_points_encoded; end_of_intro_points = intro_points_encoded + intro_points_encoded_size; tokens = smartlist_new(); parsed->intro_nodes = smartlist_new(); area = memarea_new(); while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo, "introduction-point ")) { /* Determine end of string. */ const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo, "\nintroduction-point "); if (!eos) eos = end_of_intro_points; else eos = eos+1; tor_assert(eos <= intro_points_encoded+intro_points_encoded_size); /* Free tokens and clear token list. */ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_clear(tokens); memarea_clear(area); /* Tokenize string. */ if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) { log_warn(LD_REND, "Error tokenizing introduction point"); goto err; } /* Advance to next introduction point, if available. */ current_ipo = eos; /* Check minimum allowed length of introduction point. */ if (smartlist_len(tokens) < 5) { log_warn(LD_REND, "Impossibly short introduction point."); goto err; } /* Allocate new intro point and extend info. */ intro = tor_malloc_zero(sizeof(rend_intro_point_t)); info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t)); /* Parse identifier. */ tok = find_by_keyword(tokens, R_IPO_IDENTIFIER); if (base32_decode(info->identity_digest, DIGEST_LEN, tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) { log_warn(LD_REND, "Identity digest contains illegal characters: %s", tok->args[0]); rend_intro_point_free(intro); goto err; } /* Write identifier to nickname. */ info->nickname[0] = '$'; base16_encode(info->nickname + 1, sizeof(info->nickname) - 1, info->identity_digest, DIGEST_LEN); /* Parse IP address. */ tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS); if (tor_addr_parse(&info->addr, tok->args[0])<0) { log_warn(LD_REND, "Could not parse introduction point address."); rend_intro_point_free(intro); goto err; } if (tor_addr_family(&info->addr) != AF_INET) { log_warn(LD_REND, "Introduction point address was not ipv4."); rend_intro_point_free(intro); goto err; } /* Parse onion port. */ tok = find_by_keyword(tokens, R_IPO_ONION_PORT); info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535, &num_ok,NULL); if (!info->port || !num_ok) { log_warn(LD_REND, "Introduction point onion port %s is invalid", escaped(tok->args[0])); rend_intro_point_free(intro); goto err; } /* Parse onion key. */ tok = find_by_keyword(tokens, R_IPO_ONION_KEY); if (!crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_REND, "Introduction point's onion key had invalid exponent."); rend_intro_point_free(intro); goto err; } info->onion_key = tok->key; tok->key = NULL; /* Prevent free */ /* Parse service key. */ tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY); if (!crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_REND, "Introduction point key had invalid exponent."); rend_intro_point_free(intro); goto err; } intro->intro_key = tok->key; tok->key = NULL; /* Prevent free */ /* Add extend info to list of introduction points. */ smartlist_add(parsed->intro_nodes, intro); } result = smartlist_len(parsed->intro_nodes); goto done; err: result = -1; done: /* Free tokens and clear token list. */ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) memarea_drop_all(area); return result; } /** Parse the content of a client_key file in ckstr and add * rend_authorized_client_t's for each parsed client to * parsed_clients. Return the number of parsed clients as result * or -1 for failure. */ int rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr) { int result = -1; smartlist_t *tokens; directory_token_t *tok; const char *current_entry = NULL; memarea_t *area = NULL; if (!ckstr || strlen(ckstr) == 0) return -1; tokens = smartlist_new(); /* Begin parsing with first entry, skipping comments or whitespace at the * beginning. */ area = memarea_new(); current_entry = eat_whitespace(ckstr); while (!strcmpstart(current_entry, "client-name ")) { rend_authorized_client_t *parsed_entry; size_t len; char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2]; /* Determine end of string. */ const char *eos = strstr(current_entry, "\nclient-name "); if (!eos) eos = current_entry + strlen(current_entry); else eos = eos + 1; /* Free tokens and clear token list. */ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_clear(tokens); memarea_clear(area); /* Tokenize string. */ if (tokenize_string(area, current_entry, eos, tokens, client_keys_token_table, 0)) { log_warn(LD_REND, "Error tokenizing client keys file."); goto err; } /* Advance to next entry, if available. */ current_entry = eos; /* Check minimum allowed length of token list. */ if (smartlist_len(tokens) < 2) { log_warn(LD_REND, "Impossibly short client key entry."); goto err; } /* Parse client name. */ tok = find_by_keyword(tokens, C_CLIENT_NAME); tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok->n_args == 1); len = strlen(tok->args[0]); if (len < 1 || len > 19 || strspn(tok->args[0], REND_LEGAL_CLIENTNAME_CHARACTERS) != len) { log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be " "between 1 and 19, and valid characters are " "[A-Za-z0-9+-_].)", tok->args[0]); goto err; } /* Check if client name is duplicate. */ if (strmap_get(parsed_clients, tok->args[0])) { log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a " "duplicate client name: '%s'. Ignoring.", tok->args[0]); goto err; } parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t)); parsed_entry->client_name = tor_strdup(tok->args[0]); strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry); /* Parse client key. */ tok = find_opt_by_keyword(tokens, C_CLIENT_KEY); if (tok) { parsed_entry->client_key = tok->key; tok->key = NULL; /* Prevent free */ } /* Parse descriptor cookie. */ tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE); tor_assert(tok->n_args == 1); if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) { log_warn(LD_REND, "Descriptor cookie has illegal length: %s", escaped(tok->args[0])); goto err; } /* The size of descriptor_cookie_tmp needs to be REND_DESC_COOKIE_LEN+2, * because a base64 encoding of length 24 does not fit into 16 bytes in all * cases. */ if (base64_decode(descriptor_cookie_tmp, sizeof(descriptor_cookie_tmp), tok->args[0], strlen(tok->args[0])) != REND_DESC_COOKIE_LEN) { log_warn(LD_REND, "Descriptor cookie contains illegal characters: " "%s", escaped(tok->args[0])); goto err; } memcpy(parsed_entry->descriptor_cookie, descriptor_cookie_tmp, REND_DESC_COOKIE_LEN); } result = strmap_size(parsed_clients); goto done; err: result = -1; done: /* Free tokens and clear token list. */ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) memarea_drop_all(area); return result; } tor-0.2.4.20/src/or/policies.h0000644000175000017500000000644712240762314012665 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file policies.h * \brief Header file for policies.c. **/ #ifndef TOR_POLICIES_H #define TOR_POLICIES_H /* (length of * "accept6 [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]/128:65535-65535\n" * plus a terminating NUL, rounded up to a nice number.) */ #define POLICY_BUF_LEN 72 int firewall_is_fascist_or(void); int fascist_firewall_allows_address_or(const tor_addr_t *addr, uint16_t port); int fascist_firewall_allows_or(const routerinfo_t *ri); int fascist_firewall_allows_node(const node_t *node); int fascist_firewall_allows_address_dir(const tor_addr_t *addr, uint16_t port); int dir_policy_permits_address(const tor_addr_t *addr); int socks_policy_permits_address(const tor_addr_t *addr); int authdir_policy_permits_address(uint32_t addr, uint16_t port); int authdir_policy_valid_address(uint32_t addr, uint16_t port); int authdir_policy_baddir_address(uint32_t addr, uint16_t port); int authdir_policy_badexit_address(uint32_t addr, uint16_t port); int validate_addr_policies(const or_options_t *options, char **msg); void policy_expand_private(smartlist_t **policy); void policy_expand_unspec(smartlist_t **policy); int policies_parse_from_options(const or_options_t *options); addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent); int cmp_addr_policies(smartlist_t *a, smartlist_t *b); addr_policy_result_t compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port, const smartlist_t *policy); addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port, const node_t *node); int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, int ipv6exit, int rejectprivate, const char *local_address, int add_default_policy); void policies_exit_policy_append_reject_star(smartlist_t **dest); void addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr); void policies_set_node_exitpolicy_to_reject_all(node_t *exitrouter); int exit_policy_is_general_exit(smartlist_t *policy); int policy_is_reject_star(const smartlist_t *policy, sa_family_t family); int getinfo_helper_policies(control_connection_t *conn, const char *question, char **answer, const char **errmsg); int policy_write_item(char *buf, size_t buflen, addr_policy_t *item, int format_for_desc); void addr_policy_list_free(smartlist_t *p); void addr_policy_free(addr_policy_t *p); void policies_free_all(void); char *policy_summarize(smartlist_t *policy, sa_family_t family); short_policy_t *parse_short_policy(const char *summary); char *write_short_policy(const short_policy_t *policy); void short_policy_free(short_policy_t *policy); int short_policy_is_reject_star(const short_policy_t *policy); addr_policy_result_t compare_tor_addr_to_short_policy( const tor_addr_t *addr, uint16_t port, const short_policy_t *policy); #endif tor-0.2.4.20/src/or/or_sha1.i0000644000175000017500000001542712255753103012413 00000000000000"7300e4301afb0f11bd3e3bbb680dcd5a4f16132b src/or/tor_main.c\n" "7873e6cc0e7e36476a73edc8b0920c5b13352085 src/or/addressmap.c\n" "8b0e2c19e236a711258902660de0a6f8f6e53ea4 src/or/buffers.c\n" "120f722f525443b29330711c73caf3b9fe058b14 src/or/channel.c\n" "907774034ecf67b511b214b23eead1d463effec3 src/or/channeltls.c\n" "690d10f5a138b3b6f5bfdb82200a0aa8d016dc63 src/or/circuitbuild.c\n" "10182132bfdffb93f1d3f9544b7aab409e1c1339 src/or/circuitlist.c\n" "db8e6e4e880a19999aa97663ae08c52972386563 src/or/circuitmux.c\n" "d4ad2888c3101581cf4544750370f2cd3cf94fdd src/or/circuitmux_ewma.c\n" "0d147a24797417d019592ee0f8dee3feccbf1318 src/or/circuitstats.c\n" "eac62ce167b3dbaea1ee00a98a9f063d7614f4fc src/or/circuituse.c\n" "fb90791ead8ce4c952212372db0444f8940c8d5a src/or/command.c\n" "9a49da73907e8594264a69587d079903a4a33505 src/or/config.c\n" "36dc692c0ddd83463722eeca9016c730b5bc654e src/or/confparse.c\n" "db9dc5fcde8b68f45cd6b8ffcff4e83ef530d62c src/or/connection.c\n" "8f5c91d0ae62ab7aac23bc2f31139fdd8fdc4730 src/or/connection_edge.c\n" "45b23f791bbaae08deaa9adaa23f021cb056a732 src/or/connection_or.c\n" "dd37d24f3da34951f5aab7cf06ed7f0af720ae11 src/or/control.c\n" "a06da0534bf2653f0c919eeb12b45911372149d9 src/or/cpuworker.c\n" "36cba941a3af51e8b89604a1432a9cf4439533d9 src/or/directory.c\n" "0833ae16c55ccff2e947bd68254b37a76ada6cc4 src/or/dirserv.c\n" "e8964aa5e0d59a47291daca873a30c2e54ed570e src/or/dirvote.c\n" "58873f9472fbd3374bb8bedf8898cd610979759d src/or/dns.c\n" "7051649c91cbb08873693d147e4c6da7e1e043e5 src/or/dnsserv.c\n" "e5c6da5c0eb4b4214e6365b83fb5483d2d234cef src/or/fp_pair.c\n" "81c3c820450cf18cc9266cc8b57433a513f8fedf src/or/geoip.c\n" "21c231afb35845cfc303614e8e976479b715ffdc src/or/entrynodes.c\n" "66f74cc610e925fa42eb4311f57d4db0ed60db49 src/or/hibernate.c\n" "18f5dea5f1b8dc6cb56eaa21e6c4fd0d38b10917 src/or/main.c\n" "0c5f95c1426ce13d5c633c30ba3a61d0a65b257d src/or/microdesc.c\n" "288cac7fd59e434bdc04158e48413e80499aad42 src/or/networkstatus.c\n" "9948d42c266b0c71a8faef363d0d77d0d5680341 src/or/nodelist.c\n" "6f437580030e374cdc059d48ce3f912ba0d56672 src/or/onion.c\n" "d5e436b3edfed71adfb9f304badae75b9ae7d95b src/or/onion_fast.c\n" "ba45a56d4cda342715a9fb81dcef3041aa9801c9 src/or/onion_tap.c\n" "e860157d25fe13db83ad138a62dd449d54d86690 src/or/transports.c\n" "857f07954edd7a226b7f0810da505df87a87582b src/or/policies.c\n" "4871aac26b19baa07dd6904c48dfd75234e114d7 src/or/reasons.c\n" "4412ee4fd017a1755cffa1afffd5b6801d05152f src/or/relay.c\n" "d77d93f47c907284eb42363a52bbc083a72a8848 src/or/rendclient.c\n" "759e931e7d4d84658ebf82cf6aa5c80c59f00a2e src/or/rendcommon.c\n" "34602ab4fa5afc5317bb576cf673137cf8cb4ab3 src/or/rendmid.c\n" "f3add05ac21d19a6e5f7e1aec1293aa4d912606a src/or/rendservice.c\n" "3d3fbc1168a430397d9182bd4be9352bfa64d47e src/or/rephist.c\n" "3654e3f8358f16bb04b24922706f2ea2b2b9b8c9 src/or/replaycache.c\n" "c278c0a175daf6639fed9731da6ef5a0cd4f3a58 src/or/router.c\n" "d4fee3f549913565df2e122847186695b76311d8 src/or/routerlist.c\n" "cae8e4f9d879575e62b7f1884f16864d33da6890 src/or/routerparse.c\n" "a1d43f45a49918eb613e13121ef85cc4405c04ca src/or/routerset.c\n" "c3f3a207c09f4a889cd0cb311978de21cca3d5f8 src/or/statefile.c\n" "40b4d2e7810e5054cf52a45736423e580ca437d5 src/or/status.c\n" "72b39812241a858e8b4da1baec851bca8bd64aa1 src/or/onion_ntor.c\n" "48ea4f809cf6b7738d5cfe9b64ee685f35552943 src/or/config_codedigest.c\n" "e357b6883dfe2c499b25b654139cc7ba40ff7b7a src/or/addressmap.h\n" "13282358b132ad10fd7b52779642fef4872504b1 src/or/buffers.h\n" "f015cd44385e4125383dff38f2bdef7cd4fd0118 src/or/channel.h\n" "9bedc13da7a1844e6faf7a66dd1cc04463b2a4ce src/or/channeltls.h\n" "4461cfc43c0a15f44f9c7026d7ef9116c587b1e0 src/or/circuitbuild.h\n" "e066f2c95433e9788c3f3d483bb7bff406b4785f src/or/circuitlist.h\n" "9b1f3750a90de4bd421bc522666fe25a4a395453 src/or/circuitmux.h\n" "db0d9ba7153d05561239701002d286a1690ac761 src/or/circuitmux_ewma.h\n" "d85268907b46c4ce1c299c4edd9885ebf7aa5caa src/or/circuitstats.h\n" "3e7d60c902027551cb370135afd1048abed6ca7b src/or/circuituse.h\n" "894b11aea843a1cf3d24cd43a268dec700cf21f1 src/or/command.h\n" "5fb1ffac1fdbc4808e01756575db7b8523dcbb2e src/or/config.h\n" "8678dea04508938888264c7a538a24375661ea1c src/or/confparse.h\n" "50c1dec7145f1c3e1dccc4d16d5ca6e5db199dd1 src/or/connection.h\n" "5c3bb447d9ce989b650c34bff8a9d3a573cc0d74 src/or/connection_edge.h\n" "83d87aa1bdf7d675796e5aebc55587d679251333 src/or/connection_or.h\n" "9d6e62ab5c9ebe24f367fddc8eb2d408045ed78d src/or/control.h\n" "bd39684ad6c38bbb9f171c2cdbd7209198482a4d src/or/cpuworker.h\n" "cf4391e67a0f0f8451988b59d8cab37c91ad889a src/or/directory.h\n" "dde49cdf41e3f4723bf17630be720050107462d1 src/or/dirserv.h\n" "a5f3eae90e4941244a9443b1aa6e0824d4e34fde src/or/dirvote.h\n" "6cb1fa72a8e143182af936ca5ab975bc2510c55d src/or/dns.h\n" "92a6d02b37ccae143cead903d75856e9c1496528 src/or/dnsserv.h\n" "200339cc6238b849dc61967574448b24a6d05bc7 src/or/eventdns_tor.h\n" "56ab7d66d989746dab1fdb5fb59bc9d43315a606 src/or/fp_pair.h\n" "f16a7e8f959d47ee210e02320091f5c0fe36a82c src/or/geoip.h\n" "de9503684fd9f8885a6c14d2bf1106341c49150a src/or/entrynodes.h\n" "3b30dafe675efd8b98b89b258908c49b115e9469 src/or/hibernate.h\n" "7e195faaf27b31c282868324b94a4a60eeadda42 src/or/main.h\n" "53546547b5f37dac1e70fb176c1ff2251d5fe736 src/or/microdesc.h\n" "1e9fa59db3b0f1c96ebfbdd1bdb3d457eae0d951 src/or/networkstatus.h\n" "270f9c77590d30af3403dde990227b66882cb216 src/or/nodelist.h\n" "f1f1db751507b175587da75a16a483fc4fa76a88 src/or/ntmain.h\n" "7f6d71c21ff45f3a2dc36b7eabcb15d2a8a34c57 src/or/onion.h\n" "33245d34d6bfbc6c8c700264318c5a594716b5d8 src/or/onion_fast.h\n" "e0ccc9ed34e5f206f5ea57847c4e41a19f7ad2b3 src/or/onion_ntor.h\n" "485bf9e2effe89a3f41b28fbd9d80a57ce339cbf src/or/onion_tap.h\n" "c3b4a0a24302721f83528c9f46dab28cddef6ad4 src/or/or.h\n" "596994e0f2a4cc120c17c8b631e47f8a957228a0 src/or/transports.h\n" "03dc38b7773b45bbd8203b677cfbc776b0c0b6b7 src/or/policies.h\n" "c492ec75acc2dd3365d79b1c72f350aabdc03196 src/or/reasons.h\n" "d84ce10d78b2d6b522a59e910d4bfa5bb8b4101e src/or/relay.h\n" "478409fbaa11d514985dba23b0ab4da71a4e2d97 src/or/rendclient.h\n" "0ea91df7f1f517b6a50e8568c359e84f7be8c04a src/or/rendcommon.h\n" "c0ec958def76704f5735d71c6848d0f229db27b3 src/or/rendmid.h\n" "d5a224d7940b6ff938c4e8336106e24b5ca5756b src/or/rendservice.h\n" "fac88cddeda839dc593b037f96f789dd28709ee2 src/or/rephist.h\n" "74157f727379b3ac75d39f6752c5db789ec8b674 src/or/replaycache.h\n" "30ed07fadbfc50eac024c415868f2e9ad6bc20fc src/or/router.h\n" "98fbe2beb9b694bd3bddc509a0430aebafcf9d2e src/or/routerlist.h\n" "ac098125b79f6fba41a58b498811f60c852d562b src/or/routerset.h\n" "ee45bbe04fd8686a28901ee82c43ad6f42dccde8 src/or/routerparse.h\n" "00e61f581c3734b619af4fe1a95e940862a8f76f src/or/statefile.h\n" "1cec9dc4fff60b5569944a81db1b20e6d00066c0 src/or/status.h\n" tor-0.2.4.20/src/or/policies.c0000644000175000017500000015651112166112777012667 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file policies.c * \brief Code to parse and use address policies and exit policies. **/ #include "or.h" #include "config.h" #include "dirserv.h" #include "nodelist.h" #include "policies.h" #include "routerparse.h" #include "geoip.h" #include "ht.h" /** Policy that addresses for incoming SOCKS connections must match. */ static smartlist_t *socks_policy = NULL; /** Policy that addresses for incoming directory connections must match. */ static smartlist_t *dir_policy = NULL; /** Policy that addresses for incoming router descriptors must match in order * to be published by us. */ static smartlist_t *authdir_reject_policy = NULL; /** Policy that addresses for incoming router descriptors must match in order * to be marked as valid in our networkstatus. */ static smartlist_t *authdir_invalid_policy = NULL; /** Policy that addresses for incoming router descriptors must not * match in order to not be marked as BadDirectory. */ static smartlist_t *authdir_baddir_policy = NULL; /** Policy that addresses for incoming router descriptors must not * match in order to not be marked as BadExit. */ static smartlist_t *authdir_badexit_policy = NULL; /** Parsed addr_policy_t describing which addresses we believe we can start * circuits at. */ static smartlist_t *reachable_or_addr_policy = NULL; /** Parsed addr_policy_t describing which addresses we believe we can connect * to directories at. */ static smartlist_t *reachable_dir_addr_policy = NULL; /** Element of an exit policy summary */ typedef struct policy_summary_item_t { uint16_t prt_min; /**< Lowest port number to accept/reject. */ uint16_t prt_max; /**< Highest port number to accept/reject. */ uint64_t reject_count; /**< Number of IP-Addresses that are rejected to this port range. */ unsigned int accepted:1; /** Has this port already been accepted */ } policy_summary_item_t; /** Private networks. This list is used in two places, once to expand the * "private" keyword when parsing our own exit policy, secondly to ignore * just such networks when building exit policy summaries. It is important * that all authorities agree on that list when creating summaries, so don't * just change this without a proper migration plan and a proposal and stuff. */ static const char *private_nets[] = { "0.0.0.0/8", "169.254.0.0/16", "127.0.0.0/8", "192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12", "[::]/8", "[fc00::]/7", "[fe80::]/10", "[fec0::]/10", "[ff00::]/8", "[::]/127", NULL }; /** Replace all "private" entries in *policy with their expanded * equivalents. */ void policy_expand_private(smartlist_t **policy) { uint16_t port_min, port_max; int i; smartlist_t *tmp; if (!*policy) /*XXXX disallow NULL policies? */ return; tmp = smartlist_new(); SMARTLIST_FOREACH_BEGIN(*policy, addr_policy_t *, p) { if (! p->is_private) { smartlist_add(tmp, p); continue; } for (i = 0; private_nets[i]; ++i) { addr_policy_t newpolicy; memcpy(&newpolicy, p, sizeof(addr_policy_t)); newpolicy.is_private = 0; newpolicy.is_canonical = 0; if (tor_addr_parse_mask_ports(private_nets[i], 0, &newpolicy.addr, &newpolicy.maskbits, &port_min, &port_max)<0) { tor_assert(0); } smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy)); } addr_policy_free(p); } SMARTLIST_FOREACH_END(p); smartlist_free(*policy); *policy = tmp; } /** Expand each of the AF_UNSPEC elements in *policy (which indicate * protocol-neutral wildcards) into a pair of wildcard elements: one IPv4- * specific and one IPv6-specific. */ void policy_expand_unspec(smartlist_t **policy) { smartlist_t *tmp; if (!*policy) return; tmp = smartlist_new(); SMARTLIST_FOREACH_BEGIN(*policy, addr_policy_t *, p) { sa_family_t family = tor_addr_family(&p->addr); if (family == AF_INET6 || family == AF_INET || p->is_private) { smartlist_add(tmp, p); } else if (family == AF_UNSPEC) { addr_policy_t newpolicy_ipv4; addr_policy_t newpolicy_ipv6; memcpy(&newpolicy_ipv4, p, sizeof(addr_policy_t)); memcpy(&newpolicy_ipv6, p, sizeof(addr_policy_t)); newpolicy_ipv4.is_canonical = 0; newpolicy_ipv6.is_canonical = 0; if (p->maskbits != 0) { log_warn(LD_BUG, "AF_UNSPEC policy with maskbits==%d", p->maskbits); newpolicy_ipv4.maskbits = 0; newpolicy_ipv6.maskbits = 0; } tor_addr_from_ipv4h(&newpolicy_ipv4.addr, 0); tor_addr_from_ipv6_bytes(&newpolicy_ipv6.addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv4)); smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv6)); addr_policy_free(p); } else { log_warn(LD_BUG, "Funny-looking address policy with family %d", family); smartlist_add(tmp, p); } } SMARTLIST_FOREACH_END(p); smartlist_free(*policy); *policy = tmp; } /** * Given a linked list of config lines containing "allow" and "deny" * tokens, parse them and append the result to dest. Return -1 * if any tokens are malformed (and don't append any), else return 0. * * If assume_action is nonnegative, then insert its action * (ADDR_POLICY_ACCEPT or ADDR_POLICY_REJECT) for items that specify no * action. */ static int parse_addr_policy(config_line_t *cfg, smartlist_t **dest, int assume_action) { smartlist_t *result; smartlist_t *entries; addr_policy_t *item; int r = 0; if (!cfg) return 0; result = smartlist_new(); entries = smartlist_new(); for (; cfg; cfg = cfg->next) { smartlist_split_string(entries, cfg->value, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(entries, const char *, ent) { log_debug(LD_CONFIG,"Adding new entry '%s'",ent); item = router_parse_addr_policy_item_from_string(ent, assume_action); if (item) { smartlist_add(result, item); } else { log_warn(LD_CONFIG,"Malformed policy '%s'.", ent); r = -1; } } SMARTLIST_FOREACH_END(ent); SMARTLIST_FOREACH(entries, char *, ent, tor_free(ent)); smartlist_clear(entries); } smartlist_free(entries); if (r == -1) { addr_policy_list_free(result); } else { policy_expand_private(&result); policy_expand_unspec(&result); if (*dest) { smartlist_add_all(*dest, result); smartlist_free(result); } else { *dest = result; } } return r; } /** Helper: parse the Reachable(Dir|OR)?Addresses fields into * reachable_(or|dir)_addr_policy. The options should already have * been validated by validate_addr_policies. */ static int parse_reachable_addresses(void) { const or_options_t *options = get_options(); int ret = 0; if (options->ReachableDirAddresses && options->ReachableORAddresses && options->ReachableAddresses) { log_warn(LD_CONFIG, "Both ReachableDirAddresses and ReachableORAddresses are set. " "ReachableAddresses setting will be ignored."); } addr_policy_list_free(reachable_or_addr_policy); reachable_or_addr_policy = NULL; if (!options->ReachableORAddresses && options->ReachableAddresses) log_info(LD_CONFIG, "Using ReachableAddresses as ReachableORAddresses."); if (parse_addr_policy(options->ReachableORAddresses ? options->ReachableORAddresses : options->ReachableAddresses, &reachable_or_addr_policy, ADDR_POLICY_ACCEPT)) { log_warn(LD_CONFIG, "Error parsing Reachable%sAddresses entry; ignoring.", options->ReachableORAddresses ? "OR" : ""); ret = -1; } addr_policy_list_free(reachable_dir_addr_policy); reachable_dir_addr_policy = NULL; if (!options->ReachableDirAddresses && options->ReachableAddresses) log_info(LD_CONFIG, "Using ReachableAddresses as ReachableDirAddresses"); if (parse_addr_policy(options->ReachableDirAddresses ? options->ReachableDirAddresses : options->ReachableAddresses, &reachable_dir_addr_policy, ADDR_POLICY_ACCEPT)) { if (options->ReachableDirAddresses) log_warn(LD_CONFIG, "Error parsing ReachableDirAddresses entry; ignoring."); ret = -1; } return ret; } /** Return true iff the firewall options might block any address:port * combination. */ int firewall_is_fascist_or(void) { return reachable_or_addr_policy != NULL; } /** Return true iff policy (possibly NULL) will allow a * connection to addr:port. */ static int addr_policy_permits_tor_addr(const tor_addr_t *addr, uint16_t port, smartlist_t *policy) { addr_policy_result_t p; p = compare_tor_addr_to_addr_policy(addr, port, policy); switch (p) { case ADDR_POLICY_PROBABLY_ACCEPTED: case ADDR_POLICY_ACCEPTED: return 1; case ADDR_POLICY_PROBABLY_REJECTED: case ADDR_POLICY_REJECTED: return 0; default: log_warn(LD_BUG, "Unexpected result: %d", (int)p); return 0; } } /** Return true iff policy (possibly NULL) will allow a connection to * addr:port. addr is an IPv4 address given in host * order. */ /* XXXX deprecate when possible. */ static int addr_policy_permits_address(uint32_t addr, uint16_t port, smartlist_t *policy) { tor_addr_t a; tor_addr_from_ipv4h(&a, addr); return addr_policy_permits_tor_addr(&a, port, policy); } /** Return true iff we think our firewall will let us make an OR connection to * addr:port. */ int fascist_firewall_allows_address_or(const tor_addr_t *addr, uint16_t port) { return addr_policy_permits_tor_addr(addr, port, reachable_or_addr_policy); } /** Return true iff we think our firewall will let us make an OR connection to * ri. */ int fascist_firewall_allows_or(const routerinfo_t *ri) { /* XXXX proposal 118 */ tor_addr_t addr; tor_addr_from_ipv4h(&addr, ri->addr); return fascist_firewall_allows_address_or(&addr, ri->or_port); } /** Return true iff we think our firewall will let us make an OR connection to * node. */ int fascist_firewall_allows_node(const node_t *node) { if (node->ri) { return fascist_firewall_allows_or(node->ri); } else if (node->rs) { tor_addr_t addr; tor_addr_from_ipv4h(&addr, node->rs->addr); return fascist_firewall_allows_address_or(&addr, node->rs->or_port); } else { return 1; } } /** Return true iff we think our firewall will let us make a directory * connection to addr:port. */ int fascist_firewall_allows_address_dir(const tor_addr_t *addr, uint16_t port) { return addr_policy_permits_tor_addr(addr, port, reachable_dir_addr_policy); } /** Return 1 if addr is permitted to connect to our dir port, * based on dir_policy. Else return 0. */ int dir_policy_permits_address(const tor_addr_t *addr) { return addr_policy_permits_tor_addr(addr, 1, dir_policy); } /** Return 1 if addr is permitted to connect to our socks port, * based on socks_policy. Else return 0. */ int socks_policy_permits_address(const tor_addr_t *addr) { return addr_policy_permits_tor_addr(addr, 1, socks_policy); } /** Return true iff the address addr is in a country listed in the * case-insensitive list of country codes cc_list. */ static int addr_is_in_cc_list(uint32_t addr, const smartlist_t *cc_list) { country_t country; const char *name; tor_addr_t tar; if (!cc_list) return 0; /* XXXXipv6 */ tor_addr_from_ipv4h(&tar, addr); country = geoip_get_country_by_addr(&tar); name = geoip_get_country_name(country); return smartlist_contains_string_case(cc_list, name); } /** Return 1 if addr:port is permitted to publish to our * directory, based on authdir_reject_policy. Else return 0. */ int authdir_policy_permits_address(uint32_t addr, uint16_t port) { if (! addr_policy_permits_address(addr, port, authdir_reject_policy)) return 0; return !addr_is_in_cc_list(addr, get_options()->AuthDirRejectCCs); } /** Return 1 if addr:port is considered valid in our * directory, based on authdir_invalid_policy. Else return 0. */ int authdir_policy_valid_address(uint32_t addr, uint16_t port) { if (! addr_policy_permits_address(addr, port, authdir_invalid_policy)) return 0; return !addr_is_in_cc_list(addr, get_options()->AuthDirInvalidCCs); } /** Return 1 if addr:port should be marked as a bad dir, * based on authdir_baddir_policy. Else return 0. */ int authdir_policy_baddir_address(uint32_t addr, uint16_t port) { if (! addr_policy_permits_address(addr, port, authdir_baddir_policy)) return 1; return addr_is_in_cc_list(addr, get_options()->AuthDirBadDirCCs); } /** Return 1 if addr:port should be marked as a bad exit, * based on authdir_badexit_policy. Else return 0. */ int authdir_policy_badexit_address(uint32_t addr, uint16_t port) { if (! addr_policy_permits_address(addr, port, authdir_badexit_policy)) return 1; return addr_is_in_cc_list(addr, get_options()->AuthDirBadExitCCs); } #define REJECT(arg) \ STMT_BEGIN *msg = tor_strdup(arg); goto err; STMT_END /** Config helper: If there's any problem with the policy configuration * options in options, return -1 and set msg to a newly * allocated description of the error. Else return 0. */ int validate_addr_policies(const or_options_t *options, char **msg) { /* XXXX Maybe merge this into parse_policies_from_options, to make sure * that the two can't go out of sync. */ smartlist_t *addr_policy=NULL; *msg = NULL; if (policies_parse_exit_policy(options->ExitPolicy, &addr_policy, options->IPv6Exit, options->ExitPolicyRejectPrivate, NULL, !options->BridgeRelay)) REJECT("Error in ExitPolicy entry."); /* The rest of these calls *append* to addr_policy. So don't actually * use the results for anything other than checking if they parse! */ if (parse_addr_policy(options->DirPolicy, &addr_policy, -1)) REJECT("Error in DirPolicy entry."); if (parse_addr_policy(options->SocksPolicy, &addr_policy, -1)) REJECT("Error in SocksPolicy entry."); if (parse_addr_policy(options->AuthDirReject, &addr_policy, ADDR_POLICY_REJECT)) REJECT("Error in AuthDirReject entry."); if (parse_addr_policy(options->AuthDirInvalid, &addr_policy, ADDR_POLICY_REJECT)) REJECT("Error in AuthDirInvalid entry."); if (parse_addr_policy(options->AuthDirBadDir, &addr_policy, ADDR_POLICY_REJECT)) REJECT("Error in AuthDirBadDir entry."); if (parse_addr_policy(options->AuthDirBadExit, &addr_policy, ADDR_POLICY_REJECT)) REJECT("Error in AuthDirBadExit entry."); if (parse_addr_policy(options->ReachableAddresses, &addr_policy, ADDR_POLICY_ACCEPT)) REJECT("Error in ReachableAddresses entry."); if (parse_addr_policy(options->ReachableORAddresses, &addr_policy, ADDR_POLICY_ACCEPT)) REJECT("Error in ReachableORAddresses entry."); if (parse_addr_policy(options->ReachableDirAddresses, &addr_policy, ADDR_POLICY_ACCEPT)) REJECT("Error in ReachableDirAddresses entry."); err: addr_policy_list_free(addr_policy); return *msg ? -1 : 0; #undef REJECT } /** Parse string in the same way that the exit policy * is parsed, and put the processed version in *policy. * Ignore port specifiers. */ static int load_policy_from_option(config_line_t *config, smartlist_t **policy, int assume_action) { int r; addr_policy_list_free(*policy); *policy = NULL; r = parse_addr_policy(config, policy, assume_action); if (r < 0) { return -1; } if (*policy) { SMARTLIST_FOREACH_BEGIN(*policy, addr_policy_t *, n) { /* ports aren't used in these. */ if (n->prt_min > 1 || n->prt_max != 65535) { addr_policy_t newp, *c; memcpy(&newp, n, sizeof(newp)); newp.prt_min = 1; newp.prt_max = 65535; newp.is_canonical = 0; c = addr_policy_get_canonical_entry(&newp); SMARTLIST_REPLACE_CURRENT(*policy, n, c); addr_policy_free(n); } } SMARTLIST_FOREACH_END(n); } return 0; } /** Set all policies based on options, which should have been validated * first by validate_addr_policies. */ int policies_parse_from_options(const or_options_t *options) { int ret = 0; if (load_policy_from_option(options->SocksPolicy, &socks_policy, -1) < 0) ret = -1; if (load_policy_from_option(options->DirPolicy, &dir_policy, -1) < 0) ret = -1; if (load_policy_from_option(options->AuthDirReject, &authdir_reject_policy, ADDR_POLICY_REJECT) < 0) ret = -1; if (load_policy_from_option(options->AuthDirInvalid, &authdir_invalid_policy, ADDR_POLICY_REJECT) < 0) ret = -1; if (load_policy_from_option(options->AuthDirBadDir, &authdir_baddir_policy, ADDR_POLICY_REJECT) < 0) ret = -1; if (load_policy_from_option(options->AuthDirBadExit, &authdir_badexit_policy, ADDR_POLICY_REJECT) < 0) ret = -1; if (parse_reachable_addresses() < 0) ret = -1; return ret; } /** Compare two provided address policy items, and return -1, 0, or 1 * if the first is less than, equal to, or greater than the second. */ static int cmp_single_addr_policy(addr_policy_t *a, addr_policy_t *b) { int r; if ((r=((int)a->policy_type - (int)b->policy_type))) return r; if ((r=((int)a->is_private - (int)b->is_private))) return r; if ((r=tor_addr_compare(&a->addr, &b->addr, CMP_EXACT))) return r; if ((r=((int)a->maskbits - (int)b->maskbits))) return r; if ((r=((int)a->prt_min - (int)b->prt_min))) return r; if ((r=((int)a->prt_max - (int)b->prt_max))) return r; return 0; } /** Like cmp_single_addr_policy() above, but looks at the * whole set of policies in each case. */ int cmp_addr_policies(smartlist_t *a, smartlist_t *b) { int r, i; int len_a = a ? smartlist_len(a) : 0; int len_b = b ? smartlist_len(b) : 0; for (i = 0; i < len_a && i < len_b; ++i) { if ((r = cmp_single_addr_policy(smartlist_get(a, i), smartlist_get(b, i)))) return r; } if (i == len_a && i == len_b) return 0; if (i < len_a) return -1; else return 1; } /** Node in hashtable used to store address policy entries. */ typedef struct policy_map_ent_t { HT_ENTRY(policy_map_ent_t) node; addr_policy_t *policy; } policy_map_ent_t; /* DOCDOC policy_root */ static HT_HEAD(policy_map, policy_map_ent_t) policy_root = HT_INITIALIZER(); /** Return true iff a and b are equal. */ static INLINE int policy_eq(policy_map_ent_t *a, policy_map_ent_t *b) { return cmp_single_addr_policy(a->policy, b->policy) == 0; } /** Return a hashcode for ent */ static unsigned int policy_hash(policy_map_ent_t *ent) { addr_policy_t *a = ent->policy; unsigned int r; if (a->is_private) r = 0x1234abcd; else r = tor_addr_hash(&a->addr); r += a->prt_min << 8; r += a->prt_max << 16; r += a->maskbits; if (a->policy_type == ADDR_POLICY_REJECT) r ^= 0xffffffff; return r; } HT_PROTOTYPE(policy_map, policy_map_ent_t, node, policy_hash, policy_eq) HT_GENERATE(policy_map, policy_map_ent_t, node, policy_hash, policy_eq, 0.6, malloc, realloc, free) /** Given a pointer to an addr_policy_t, return a copy of the pointer to the * "canonical" copy of that addr_policy_t; the canonical copy is a single * reference-counted object. */ addr_policy_t * addr_policy_get_canonical_entry(addr_policy_t *e) { policy_map_ent_t search, *found; if (e->is_canonical) return e; search.policy = e; found = HT_FIND(policy_map, &policy_root, &search); if (!found) { found = tor_malloc_zero(sizeof(policy_map_ent_t)); found->policy = tor_memdup(e, sizeof(addr_policy_t)); found->policy->is_canonical = 1; found->policy->refcnt = 0; HT_INSERT(policy_map, &policy_root, found); } tor_assert(!cmp_single_addr_policy(found->policy, e)); ++found->policy->refcnt; return found->policy; } /** Helper for compare_tor_addr_to_addr_policy. Implements the case where * addr and port are both known. */ static addr_policy_result_t compare_known_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port, const smartlist_t *policy) { /* We know the address and port, and we know the policy, so we can just * compute an exact match. */ SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, tmpe) { /* Address is known */ if (!tor_addr_compare_masked(addr, &tmpe->addr, tmpe->maskbits, CMP_EXACT)) { if (port >= tmpe->prt_min && port <= tmpe->prt_max) { /* Exact match for the policy */ return tmpe->policy_type == ADDR_POLICY_ACCEPT ? ADDR_POLICY_ACCEPTED : ADDR_POLICY_REJECTED; } } } SMARTLIST_FOREACH_END(tmpe); /* accept all by default. */ return ADDR_POLICY_ACCEPTED; } /** Helper for compare_tor_addr_to_addr_policy. Implements the case where * addr is known but port is not. */ static addr_policy_result_t compare_known_tor_addr_to_addr_policy_noport(const tor_addr_t *addr, const smartlist_t *policy) { /* We look to see if there's a definite match. If so, we return that match's value, unless there's an intervening possible match that says something different. */ int maybe_accept = 0, maybe_reject = 0; SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, tmpe) { if (!tor_addr_compare_masked(addr, &tmpe->addr, tmpe->maskbits, CMP_EXACT)) { if (tmpe->prt_min <= 1 && tmpe->prt_max >= 65535) { /* Definitely matches, since it covers all ports. */ if (tmpe->policy_type == ADDR_POLICY_ACCEPT) { /* If we already hit a clause that might trigger a 'reject', than we * can't be sure of this certain 'accept'.*/ return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED; } else { return maybe_accept ? ADDR_POLICY_PROBABLY_REJECTED : ADDR_POLICY_REJECTED; } } else { /* Might match. */ if (tmpe->policy_type == ADDR_POLICY_REJECT) maybe_reject = 1; else maybe_accept = 1; } } } SMARTLIST_FOREACH_END(tmpe); /* accept all by default. */ return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED; } /** Helper for compare_tor_addr_to_addr_policy. Implements the case where * port is known but address is not. */ static addr_policy_result_t compare_unknown_tor_addr_to_addr_policy(uint16_t port, const smartlist_t *policy) { /* We look to see if there's a definite match. If so, we return that match's value, unless there's an intervening possible match that says something different. */ int maybe_accept = 0, maybe_reject = 0; SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, tmpe) { if (tmpe->prt_min <= port && port <= tmpe->prt_max) { if (tmpe->maskbits == 0) { /* Definitely matches, since it covers all addresses. */ if (tmpe->policy_type == ADDR_POLICY_ACCEPT) { /* If we already hit a clause that might trigger a 'reject', than we * can't be sure of this certain 'accept'.*/ return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED; } else { return maybe_accept ? ADDR_POLICY_PROBABLY_REJECTED : ADDR_POLICY_REJECTED; } } else { /* Might match. */ if (tmpe->policy_type == ADDR_POLICY_REJECT) maybe_reject = 1; else maybe_accept = 1; } } } SMARTLIST_FOREACH_END(tmpe); /* accept all by default. */ return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED; } /** Decide whether a given addr:port is definitely accepted, * definitely rejected, probably accepted, or probably rejected by a * given policy. If addr is 0, we don't know the IP of the * target address. If port is 0, we don't know the port of the * target address. (At least one of addr and port must be * provided. If you want to know whether a policy would definitely reject * an unknown address:port, use policy_is_reject_star().) * * We could do better by assuming that some ranges never match typical * addresses (127.0.0.1, and so on). But we'll try this for now. */ addr_policy_result_t compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port, const smartlist_t *policy) { if (!policy) { /* no policy? accept all. */ return ADDR_POLICY_ACCEPTED; } else if (addr == NULL || tor_addr_is_null(addr)) { if (port == 0) { log_info(LD_BUG, "Rejecting null address with 0 port (family %d)", addr ? tor_addr_family(addr) : -1); return ADDR_POLICY_REJECTED; } return compare_unknown_tor_addr_to_addr_policy(port, policy); } else if (port == 0) { return compare_known_tor_addr_to_addr_policy_noport(addr, policy); } else { return compare_known_tor_addr_to_addr_policy(addr, port, policy); } } /** Return true iff the address policy a covers every case that * would be covered by b, so that a,b is redundant. */ static int addr_policy_covers(addr_policy_t *a, addr_policy_t *b) { if (tor_addr_family(&a->addr) != tor_addr_family(&b->addr)) { /* You can't cover a different family. */ return 0; } /* We can ignore accept/reject, since "accept *:80, reject *:80" reduces * to "accept *:80". */ if (a->maskbits > b->maskbits) { /* a has more fixed bits than b; it can't possibly cover b. */ return 0; } if (tor_addr_compare_masked(&a->addr, &b->addr, a->maskbits, CMP_EXACT)) { /* There's a fixed bit in a that's set differently in b. */ return 0; } return (a->prt_min <= b->prt_min && a->prt_max >= b->prt_max); } /** Return true iff the address policies a and b intersect, * that is, there exists an address/port that is covered by a that * is also covered by b. */ static int addr_policy_intersects(addr_policy_t *a, addr_policy_t *b) { maskbits_t minbits; /* All the bits we care about are those that are set in both * netmasks. If they are equal in a and b's networkaddresses * then the networks intersect. If there is a difference, * then they do not. */ if (a->maskbits < b->maskbits) minbits = a->maskbits; else minbits = b->maskbits; if (tor_addr_compare_masked(&a->addr, &b->addr, minbits, CMP_EXACT)) return 0; if (a->prt_max < b->prt_min || b->prt_max < a->prt_min) return 0; return 1; } /** Add the exit policy described by more to policy. */ static void append_exit_policy_string(smartlist_t **policy, const char *more) { config_line_t tmp; tmp.key = NULL; tmp.value = (char*) more; tmp.next = NULL; if (parse_addr_policy(&tmp, policy, -1)<0) { log_warn(LD_BUG, "Unable to parse internally generated policy %s",more); } } /** Add "reject addr:*" to dest, creating the list as needed. */ void addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr) { addr_policy_t p, *add; memset(&p, 0, sizeof(p)); p.policy_type = ADDR_POLICY_REJECT; p.maskbits = tor_addr_family(addr) == AF_INET6 ? 128 : 32; tor_addr_copy(&p.addr, addr); p.prt_min = 1; p.prt_max = 65535; add = addr_policy_get_canonical_entry(&p); if (!*dest) *dest = smartlist_new(); smartlist_add(*dest, add); } /** Detect and excise "dead code" from the policy *dest. */ static void exit_policy_remove_redundancies(smartlist_t *dest) { addr_policy_t *ap, *tmp; int i, j; /* Step one: kill every ipv4 thing after *4:*, every IPv6 thing after *6:* */ { int kill_v4=0, kill_v6=0; for (i = 0; i < smartlist_len(dest); ++i) { sa_family_t family; ap = smartlist_get(dest, i); family = tor_addr_family(&ap->addr); if ((family == AF_INET && kill_v4) || (family == AF_INET6 && kill_v6)) { smartlist_del_keeporder(dest, i--); addr_policy_free(ap); continue; } if (ap->maskbits == 0 && ap->prt_min <= 1 && ap->prt_max >= 65535) { /* This is a catch-all line -- later lines are unreachable. */ if (family == AF_INET) { kill_v4 = 1; } else if (family == AF_INET6) { kill_v6 = 1; } } } } /* Step two: for every entry, see if there's a redundant entry * later on, and remove it. */ for (i = 0; i < smartlist_len(dest)-1; ++i) { ap = smartlist_get(dest, i); for (j = i+1; j < smartlist_len(dest); ++j) { tmp = smartlist_get(dest, j); tor_assert(j > i); if (addr_policy_covers(ap, tmp)) { char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN]; policy_write_item(p1, sizeof(p1), tmp, 0); policy_write_item(p2, sizeof(p2), ap, 0); log_debug(LD_CONFIG, "Removing exit policy %s (%d). It is made " "redundant by %s (%d).", p1, j, p2, i); smartlist_del_keeporder(dest, j--); addr_policy_free(tmp); } } } /* Step three: for every entry A, see if there's an entry B making this one * redundant later on. This is the case if A and B are of the same type * (accept/reject), A is a subset of B, and there is no other entry of * different type in between those two that intersects with A. * * Anybody want to double-check the logic here? XXX */ for (i = 0; i < smartlist_len(dest)-1; ++i) { ap = smartlist_get(dest, i); for (j = i+1; j < smartlist_len(dest); ++j) { // tor_assert(j > i); // j starts out at i+1; j only increases; i only // // decreases. tmp = smartlist_get(dest, j); if (ap->policy_type != tmp->policy_type) { if (addr_policy_intersects(ap, tmp)) break; } else { /* policy_types are equal. */ if (addr_policy_covers(tmp, ap)) { char p1[POLICY_BUF_LEN], p2[POLICY_BUF_LEN]; policy_write_item(p1, sizeof(p1), ap, 0); policy_write_item(p2, sizeof(p2), tmp, 0); log_debug(LD_CONFIG, "Removing exit policy %s. It is already " "covered by %s.", p1, p2); smartlist_del_keeporder(dest, i--); addr_policy_free(ap); break; } } } } } #define DEFAULT_EXIT_POLICY \ "reject *:25,reject *:119,reject *:135-139,reject *:445," \ "reject *:563,reject *:1214,reject *:4661-4666," \ "reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*" /** Parse the exit policy cfg into the linked list *dest. If * cfg doesn't end in an absolute accept or reject and if * add_default_policy is true, add the default exit * policy afterwards. If rejectprivate is true, prepend * "reject private:*" to the policy. Return -1 if we can't parse cfg, * else return 0. * * This function is used to parse the exit policy from our torrc. For * the functions used to parse the exit policy from a router descriptor, * see router_add_exit_policy. */ int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, int ipv6_exit, int rejectprivate, const char *local_address, int add_default_policy) { if (!ipv6_exit) { append_exit_policy_string(dest, "reject *6:*"); } if (rejectprivate) { append_exit_policy_string(dest, "reject private:*"); if (local_address) { char buf[POLICY_BUF_LEN]; tor_snprintf(buf, sizeof(buf), "reject %s:*", local_address); append_exit_policy_string(dest, buf); } } if (parse_addr_policy(cfg, dest, -1)) return -1; if (add_default_policy) { append_exit_policy_string(dest, DEFAULT_EXIT_POLICY); } else { append_exit_policy_string(dest, "reject *4:*"); append_exit_policy_string(dest, "reject *6:*"); } exit_policy_remove_redundancies(*dest); return 0; } /** Add "reject *:*" to the end of the policy in *dest, allocating * *dest as needed. */ void policies_exit_policy_append_reject_star(smartlist_t **dest) { append_exit_policy_string(dest, "reject *4:*"); append_exit_policy_string(dest, "reject *6:*"); } /** Replace the exit policy of node with reject *:* */ void policies_set_node_exitpolicy_to_reject_all(node_t *node) { node->rejects_all = 1; } /** Return 1 if there is at least one /8 subnet in policy that * allows exiting to port. Otherwise, return 0. */ static int exit_policy_is_general_exit_helper(smartlist_t *policy, int port) { uint32_t mask, ip, i; /* Is this /8 rejected (1), or undecided (0)? */ char subnet_status[256]; memset(subnet_status, 0, sizeof(subnet_status)); SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) { if (tor_addr_family(&p->addr) != AF_INET) continue; /* IPv4 only for now */ if (p->prt_min > port || p->prt_max < port) continue; /* Doesn't cover our port. */ mask = 0; tor_assert(p->maskbits <= 32); if (p->maskbits) mask = UINT32_MAX<<(32-p->maskbits); ip = tor_addr_to_ipv4h(&p->addr); /* Calculate the first and last subnet that this exit policy touches * and set it as loop boundaries. */ for (i = ((mask & ip)>>24); i <= (~((mask & ip) ^ mask)>>24); ++i) { tor_addr_t addr; if (subnet_status[i] != 0) continue; /* We already reject some part of this /8 */ tor_addr_from_ipv4h(&addr, i<<24); if (tor_addr_is_internal(&addr, 0)) continue; /* Local or non-routable addresses */ if (p->policy_type == ADDR_POLICY_ACCEPT) { if (p->maskbits > 8) continue; /* Narrower than a /8. */ /* We found an allowed subnet of at least size /8. Done * for this port! */ return 1; } else if (p->policy_type == ADDR_POLICY_REJECT) { subnet_status[i] = 1; } } } SMARTLIST_FOREACH_END(p); return 0; } /** Return true iff ri is "useful as an exit node", meaning * it allows exit to at least one /8 address space for at least * two of ports 80, 443, and 6667. */ int exit_policy_is_general_exit(smartlist_t *policy) { static const int ports[] = { 80, 443, 6667 }; int n_allowed = 0; int i; if (!policy) /*XXXX disallow NULL policies? */ return 0; for (i = 0; i < 3; ++i) { n_allowed += exit_policy_is_general_exit_helper(policy, ports[i]); } return n_allowed >= 2; } /** Return false if policy might permit access to some addr:port; * otherwise if we are certain it rejects everything, return true. */ int policy_is_reject_star(const smartlist_t *policy, sa_family_t family) { if (!policy) /*XXXX disallow NULL policies? */ return 1; SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) { if (p->policy_type == ADDR_POLICY_ACCEPT && (tor_addr_family(&p->addr) == family || tor_addr_family(&p->addr) == AF_UNSPEC)) { return 0; } else if (p->policy_type == ADDR_POLICY_REJECT && p->prt_min <= 1 && p->prt_max == 65535 && p->maskbits == 0 && (tor_addr_family(&p->addr) == family || tor_addr_family(&p->addr) == AF_UNSPEC)) { return 1; } } SMARTLIST_FOREACH_END(p); return 1; } /** Write a single address policy to the buf_len byte buffer at buf. Return * the number of characters written, or -1 on failure. */ int policy_write_item(char *buf, size_t buflen, addr_policy_t *policy, int format_for_desc) { size_t written = 0; char addrbuf[TOR_ADDR_BUF_LEN]; const char *addrpart; int result; const int is_accept = policy->policy_type == ADDR_POLICY_ACCEPT; const sa_family_t family = tor_addr_family(&policy->addr); const int is_ip6 = (family == AF_INET6); tor_addr_to_str(addrbuf, &policy->addr, sizeof(addrbuf), 1); /* write accept/reject 1.2.3.4 */ if (policy->is_private) { addrpart = "private"; } else if (policy->maskbits == 0) { if (format_for_desc) addrpart = "*"; else if (family == AF_INET6) addrpart = "*6"; else if (family == AF_INET) addrpart = "*4"; else addrpart = "*"; } else { addrpart = addrbuf; } result = tor_snprintf(buf, buflen, "%s%s %s", is_accept ? "accept" : "reject", (is_ip6&&format_for_desc)?"6":"", addrpart); if (result < 0) return -1; written += strlen(buf); /* If the maskbits is 32 we don't need to give it. If the mask is 0, * we already wrote "*". */ if (policy->maskbits < 32 && policy->maskbits > 0) { if (tor_snprintf(buf+written, buflen-written, "/%d", policy->maskbits)<0) return -1; written += strlen(buf+written); } if (policy->prt_min <= 1 && policy->prt_max == 65535) { /* There is no port set; write ":*" */ if (written+4 > buflen) return -1; strlcat(buf+written, ":*", buflen-written); written += 2; } else if (policy->prt_min == policy->prt_max) { /* There is only one port; write ":80". */ result = tor_snprintf(buf+written, buflen-written, ":%d", policy->prt_min); if (result<0) return -1; written += result; } else { /* There is a range of ports; write ":79-80". */ result = tor_snprintf(buf+written, buflen-written, ":%d-%d", policy->prt_min, policy->prt_max); if (result<0) return -1; written += result; } if (written < buflen) buf[written] = '\0'; else return -1; return (int)written; } /** Create a new exit policy summary, initially only with a single * port 1-64k item */ /* XXXX This entire thing will do most stuff in O(N^2), or worse. Use an * RB-tree if that turns out to matter. */ static smartlist_t * policy_summary_create(void) { smartlist_t *summary; policy_summary_item_t* item; item = tor_malloc_zero(sizeof(policy_summary_item_t)); item->prt_min = 1; item->prt_max = 65535; item->reject_count = 0; item->accepted = 0; summary = smartlist_new(); smartlist_add(summary, item); return summary; } /** Split the summary item in item at the port new_starts. * The current item is changed to end at new-starts - 1, the new item * copies reject_count and accepted from the old item, * starts at new_starts and ends at the port where the original item * previously ended. */ static policy_summary_item_t* policy_summary_item_split(policy_summary_item_t* old, uint16_t new_starts) { policy_summary_item_t* new; new = tor_malloc_zero(sizeof(policy_summary_item_t)); new->prt_min = new_starts; new->prt_max = old->prt_max; new->reject_count = old->reject_count; new->accepted = old->accepted; old->prt_max = new_starts-1; tor_assert(old->prt_min <= old->prt_max); tor_assert(new->prt_min <= new->prt_max); return new; } /* XXXX Nick says I'm going to hell for this. If he feels charitably towards * my immortal soul, he can clean it up himself. */ #define AT(x) ((policy_summary_item_t*)smartlist_get(summary, x)) #define REJECT_CUTOFF_COUNT (1<<25) /** Split an exit policy summary so that prt_min and prt_max * fall at exactly the start and end of an item respectively. */ static int policy_summary_split(smartlist_t *summary, uint16_t prt_min, uint16_t prt_max) { int start_at_index; int i = 0; while (AT(i)->prt_max < prt_min) i++; if (AT(i)->prt_min != prt_min) { policy_summary_item_t* new_item; new_item = policy_summary_item_split(AT(i), prt_min); smartlist_insert(summary, i+1, new_item); i++; } start_at_index = i; while (AT(i)->prt_max < prt_max) i++; if (AT(i)->prt_max != prt_max) { policy_summary_item_t* new_item; new_item = policy_summary_item_split(AT(i), prt_max+1); smartlist_insert(summary, i+1, new_item); } return start_at_index; } /** Mark port ranges as accepted if they are below the reject_count */ static void policy_summary_accept(smartlist_t *summary, uint16_t prt_min, uint16_t prt_max) { int i = policy_summary_split(summary, prt_min, prt_max); while (i < smartlist_len(summary) && AT(i)->prt_max <= prt_max) { if (!AT(i)->accepted && AT(i)->reject_count <= REJECT_CUTOFF_COUNT) AT(i)->accepted = 1; i++; } tor_assert(i < smartlist_len(summary) || prt_max==65535); } /** Count the number of addresses in a network with prefixlen maskbits * against the given portrange. */ static void policy_summary_reject(smartlist_t *summary, maskbits_t maskbits, uint16_t prt_min, uint16_t prt_max) { int i = policy_summary_split(summary, prt_min, prt_max); /* XXX: ipv4 specific */ uint64_t count = (U64_LITERAL(1) << (32-maskbits)); while (i < smartlist_len(summary) && AT(i)->prt_max <= prt_max) { AT(i)->reject_count += count; i++; } tor_assert(i < smartlist_len(summary) || prt_max==65535); } /** Add a single exit policy item to our summary: * If it is an accept ignore it unless it is for all IP addresses * ("*"), i.e. it's prefixlen/maskbits is 0, else call * policy_summary_accept(). * If it's a reject ignore it if it is about one of the private * networks, else call policy_summary_reject(). */ static void policy_summary_add_item(smartlist_t *summary, addr_policy_t *p) { if (p->policy_type == ADDR_POLICY_ACCEPT) { if (p->maskbits == 0) { policy_summary_accept(summary, p->prt_min, p->prt_max); } } else if (p->policy_type == ADDR_POLICY_REJECT) { int is_private = 0; int i; for (i = 0; private_nets[i]; ++i) { tor_addr_t addr; maskbits_t maskbits; if (tor_addr_parse_mask_ports(private_nets[i], 0, &addr, &maskbits, NULL, NULL)<0) { tor_assert(0); } if (tor_addr_compare(&p->addr, &addr, CMP_EXACT) == 0 && p->maskbits == maskbits) { is_private = 1; break; } } if (!is_private) { policy_summary_reject(summary, p->maskbits, p->prt_min, p->prt_max); } } else tor_assert(0); } /** Create a string representing a summary for an exit policy. * The summary will either be an "accept" plus a comma-separated list of port * ranges or a "reject" plus port-ranges, depending on which is shorter. * * If no exits are allowed at all then NULL is returned, if no ports * are blocked instead of "reject " we return "accept 1-65535" (this * is an exception to the shorter-representation-wins rule). */ char * policy_summarize(smartlist_t *policy, sa_family_t family) { smartlist_t *summary = policy_summary_create(); smartlist_t *accepts, *rejects; int i, last, start_prt; size_t accepts_len, rejects_len; char *accepts_str = NULL, *rejects_str = NULL, *shorter_str, *result; const char *prefix; tor_assert(policy); /* Create the summary list */ SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) { sa_family_t f = tor_addr_family(&p->addr); if (f != AF_INET && f != AF_INET6) { log_warn(LD_BUG, "Weird family when summarizing address policy"); } if (f != family) continue; /* XXXX-ipv6 More family work is needed */ policy_summary_add_item(summary, p); } SMARTLIST_FOREACH_END(p); /* Now create two lists of strings, one for accepted and one * for rejected ports. We take care to merge ranges so that * we avoid getting stuff like "1-4,5-9,10", instead we want * "1-10" */ i = 0; start_prt = 1; accepts = smartlist_new(); rejects = smartlist_new(); while (1) { last = i == smartlist_len(summary)-1; if (last || AT(i)->accepted != AT(i+1)->accepted) { char buf[POLICY_BUF_LEN]; if (start_prt == AT(i)->prt_max) tor_snprintf(buf, sizeof(buf), "%d", start_prt); else tor_snprintf(buf, sizeof(buf), "%d-%d", start_prt, AT(i)->prt_max); if (AT(i)->accepted) smartlist_add(accepts, tor_strdup(buf)); else smartlist_add(rejects, tor_strdup(buf)); if (last) break; start_prt = AT(i+1)->prt_min; }; i++; }; /* Figure out which of the two stringlists will be shorter and use * that to build the result */ if (smartlist_len(accepts) == 0) { /* no exits at all */ result = tor_strdup("reject 1-65535"); goto cleanup; } if (smartlist_len(rejects) == 0) { /* no rejects at all */ result = tor_strdup("accept 1-65535"); goto cleanup; } accepts_str = smartlist_join_strings(accepts, ",", 0, &accepts_len); rejects_str = smartlist_join_strings(rejects, ",", 0, &rejects_len); if (rejects_len > MAX_EXITPOLICY_SUMMARY_LEN-strlen("reject")-1 && accepts_len > MAX_EXITPOLICY_SUMMARY_LEN-strlen("accept")-1) { char *c; shorter_str = accepts_str; prefix = "accept"; c = shorter_str + (MAX_EXITPOLICY_SUMMARY_LEN-strlen(prefix)-1); while (*c != ',' && c >= shorter_str) c--; tor_assert(c >= shorter_str); tor_assert(*c == ','); *c = '\0'; } else if (rejects_len < accepts_len) { shorter_str = rejects_str; prefix = "reject"; } else { shorter_str = accepts_str; prefix = "accept"; } tor_asprintf(&result, "%s %s", prefix, shorter_str); cleanup: /* cleanup */ SMARTLIST_FOREACH(summary, policy_summary_item_t *, s, tor_free(s)); smartlist_free(summary); tor_free(accepts_str); SMARTLIST_FOREACH(accepts, char *, s, tor_free(s)); smartlist_free(accepts); tor_free(rejects_str); SMARTLIST_FOREACH(rejects, char *, s, tor_free(s)); smartlist_free(rejects); return result; } /** Convert a summarized policy string into a short_policy_t. Return NULL * if the string is not well-formed. */ short_policy_t * parse_short_policy(const char *summary) { const char *orig_summary = summary; short_policy_t *result; int is_accept; int n_entries; short_policy_entry_t entries[MAX_EXITPOLICY_SUMMARY_LEN]; /* overkill */ const char *next; if (!strcmpstart(summary, "accept ")) { is_accept = 1; summary += strlen("accept "); } else if (!strcmpstart(summary, "reject ")) { is_accept = 0; summary += strlen("reject "); } else { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Unrecognized policy summary keyword"); return NULL; } n_entries = 0; for ( ; *summary; summary = next) { const char *comma = strchr(summary, ','); unsigned low, high; char dummy; char ent_buf[32]; size_t len; next = comma ? comma+1 : strchr(summary, '\0'); len = comma ? (size_t)(comma - summary) : strlen(summary); if (n_entries == MAX_EXITPOLICY_SUMMARY_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Impossibly long policy summary %s", escaped(orig_summary)); return NULL; } if (! TOR_ISDIGIT(*summary) || len > (sizeof(ent_buf)-1)) { /* unrecognized entry format. skip it. */ continue; } if (len < 1) { /* empty; skip it. */ /* XXX This happens to be unreachable, since if len==0, then *summary is * ',' or '\0', and the TOR_ISDIGIT test above would have failed. */ continue; } memcpy(ent_buf, summary, len); ent_buf[len] = '\0'; if (tor_sscanf(ent_buf, "%u-%u%c", &low, &high, &dummy) == 2) { if (low<1 || low>65535 || high<1 || high>65535 || low>high) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Found bad entry in policy summary %s", escaped(orig_summary)); return NULL; } } else if (tor_sscanf(ent_buf, "%u%c", &low, &dummy) == 1) { if (low<1 || low>65535) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Found bad entry in policy summary %s", escaped(orig_summary)); return NULL; } high = low; } else { log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s", escaped(orig_summary)); return NULL; } entries[n_entries].min_port = low; entries[n_entries].max_port = high; n_entries++; } if (n_entries == 0) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Found no port-range entries in summary %s", escaped(orig_summary)); return NULL; } { size_t size = STRUCT_OFFSET(short_policy_t, entries) + sizeof(short_policy_entry_t)*(n_entries); result = tor_malloc_zero(size); tor_assert( (char*)&result->entries[n_entries-1] < ((char*)result)+size); } result->is_accept = is_accept; result->n_entries = n_entries; memcpy(result->entries, entries, sizeof(short_policy_entry_t)*n_entries); return result; } /** Write policy back out into a string. Used only for unit tests * currently. */ char * write_short_policy(const short_policy_t *policy) { int i; char *answer; smartlist_t *sl = smartlist_new(); smartlist_add_asprintf(sl, "%s", policy->is_accept ? "accept " : "reject "); for (i=0; i < policy->n_entries; i++) { const short_policy_entry_t *e = &policy->entries[i]; if (e->min_port == e->max_port) { smartlist_add_asprintf(sl, "%d", e->min_port); } else { smartlist_add_asprintf(sl, "%d-%d", e->min_port, e->max_port); } if (i < policy->n_entries-1) smartlist_add(sl, tor_strdup(",")); } answer = smartlist_join_strings(sl, "", 0, NULL); SMARTLIST_FOREACH(sl, char *, a, tor_free(a)); smartlist_free(sl); return answer; } /** Release all storage held in policy. */ void short_policy_free(short_policy_t *policy) { tor_free(policy); } /** See whether the addr:port address is likely to be accepted * or rejected by the summarized policy policy. Return values are as * for compare_tor_addr_to_addr_policy. Unlike the regular addr_policy * functions, requires the port be specified. */ addr_policy_result_t compare_tor_addr_to_short_policy(const tor_addr_t *addr, uint16_t port, const short_policy_t *policy) { int i; int found_match = 0; int accept; tor_assert(port != 0); if (addr && tor_addr_is_null(addr)) addr = NULL; /* Unspec means 'no address at all,' in this context. */ if (addr && get_options()->ClientRejectInternalAddresses && (tor_addr_is_internal(addr, 0) || tor_addr_is_loopback(addr))) return ADDR_POLICY_REJECTED; for (i=0; i < policy->n_entries; ++i) { const short_policy_entry_t *e = &policy->entries[i]; if (e->min_port <= port && port <= e->max_port) { found_match = 1; break; } } if (found_match) accept = policy->is_accept; else accept = ! policy->is_accept; /* ???? are these right? -NM */ /* We should be sure not to return ADDR_POLICY_ACCEPTED in the accept * case here, because it would cause clients to believe that the node * allows exit enclaving. Trying it anyway would open up a cool attack * where the node refuses due to exitpolicy, the client reacts in * surprise by rewriting the node's exitpolicy to reject *:*, and then * a bad guy targets users by causing them to attempt such connections * to 98% of the exits. * * Once microdescriptors can handle addresses in special cases (e.g. if * we ever solve ticket 1774), we can provide certainty here. -RD */ if (accept) return ADDR_POLICY_PROBABLY_ACCEPTED; else return ADDR_POLICY_REJECTED; } /** Return true iff policy seems reject all ports */ int short_policy_is_reject_star(const short_policy_t *policy) { /* This doesn't need to be as much on the lookout as policy_is_reject_star, * since policy summaries are from the consensus or from consensus * microdescs. */ tor_assert(policy); /* Check for an exact match of "reject 1-65535". */ return (policy->is_accept == 0 && policy->n_entries == 1 && policy->entries[0].min_port == 1 && policy->entries[0].max_port == 65535); } /** Decide whether addr:port is probably or definitely accepted or rejected by * node. See compare_tor_addr_to_addr_policy for details on addr/port * interpretation. */ addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port, const node_t *node) { if (node->rejects_all) return ADDR_POLICY_REJECTED; if (addr && tor_addr_family(addr) == AF_INET6) { const short_policy_t *p = NULL; if (node->ri) p = node->ri->ipv6_exit_policy; else if (node->md) p = node->md->ipv6_exit_policy; if (p) return compare_tor_addr_to_short_policy(addr, port, p); else return ADDR_POLICY_REJECTED; } if (node->ri) { return compare_tor_addr_to_addr_policy(addr, port, node->ri->exit_policy); } else if (node->md) { if (node->md->exit_policy == NULL) return ADDR_POLICY_REJECTED; else return compare_tor_addr_to_short_policy(addr, port, node->md->exit_policy); } else { return ADDR_POLICY_PROBABLY_REJECTED; } } /** Implementation for GETINFO control command: knows the answer for questions * about "exit-policy/..." */ int getinfo_helper_policies(control_connection_t *conn, const char *question, char **answer, const char **errmsg) { (void) conn; (void) errmsg; if (!strcmp(question, "exit-policy/default")) { *answer = tor_strdup(DEFAULT_EXIT_POLICY); } return 0; } /** Release all storage held by p. */ void addr_policy_list_free(smartlist_t *lst) { if (!lst) return; SMARTLIST_FOREACH(lst, addr_policy_t *, policy, addr_policy_free(policy)); smartlist_free(lst); } /** Release all storage held by p. */ void addr_policy_free(addr_policy_t *p) { if (!p) return; if (--p->refcnt <= 0) { if (p->is_canonical) { policy_map_ent_t search, *found; search.policy = p; found = HT_REMOVE(policy_map, &policy_root, &search); if (found) { tor_assert(p == found->policy); tor_free(found); } } tor_free(p); } } /** Release all storage held by policy variables. */ void policies_free_all(void) { addr_policy_list_free(reachable_or_addr_policy); reachable_or_addr_policy = NULL; addr_policy_list_free(reachable_dir_addr_policy); reachable_dir_addr_policy = NULL; addr_policy_list_free(socks_policy); socks_policy = NULL; addr_policy_list_free(dir_policy); dir_policy = NULL; addr_policy_list_free(authdir_reject_policy); authdir_reject_policy = NULL; addr_policy_list_free(authdir_invalid_policy); authdir_invalid_policy = NULL; addr_policy_list_free(authdir_baddir_policy); authdir_baddir_policy = NULL; addr_policy_list_free(authdir_badexit_policy); authdir_badexit_policy = NULL; if (!HT_EMPTY(&policy_root)) { policy_map_ent_t **ent; int n = 0; char buf[POLICY_BUF_LEN]; log_warn(LD_MM, "Still had %d address policies cached at shutdown.", (int)HT_SIZE(&policy_root)); /* Note the first 10 cached policies to try to figure out where they * might be coming from. */ HT_FOREACH(ent, policy_map, &policy_root) { if (++n > 10) break; if (policy_write_item(buf, sizeof(buf), (*ent)->policy, 0) >= 0) log_warn(LD_MM," %d [%d]: %s", n, (*ent)->policy->refcnt, buf); } } HT_CLEAR(policy_map, &policy_root); } tor-0.2.4.20/src/or/control.h0000644000175000017500000001011712255745673012542 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file control.h * \brief Header file for control.c. **/ #ifndef TOR_CONTROL_H #define TOR_CONTROL_H void control_update_global_event_mask(void); void control_adjust_event_log_severity(void); void control_ports_write_to_file(void); /** Log information about the connection conn, protecting it as with * CONN_LOG_PROTECT. Example: * * LOG_FN_CONN(conn, (LOG_DEBUG, "Socket %d wants to write", conn->s)); **/ #define LOG_FN_CONN(conn, args) \ CONN_LOG_PROTECT(conn, log_fn args) int connection_control_finished_flushing(control_connection_t *conn); int connection_control_reached_eof(control_connection_t *conn); void connection_control_closed(control_connection_t *conn); int connection_control_process_inbuf(control_connection_t *conn); #define EVENT_AUTHDIR_NEWDESCS 0x000D #define EVENT_NS 0x000F int control_event_is_interesting(int event); int control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t e, int reason); int control_event_circuit_purpose_changed(origin_circuit_t *circ, int old_purpose); int control_event_circuit_cannibalized(origin_circuit_t *circ, int old_purpose, const struct timeval *old_tv_created); int control_event_stream_status(entry_connection_t *conn, stream_status_event_t e, int reason); int control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t e, int reason); int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written); int control_event_stream_bandwidth(edge_connection_t *edge_conn); int control_event_stream_bandwidth_used(void); void control_event_logmsg(int severity, uint32_t domain, const char *msg); int control_event_descriptors_changed(smartlist_t *routers); int control_event_address_mapped(const char *from, const char *to, time_t expires, const char *error, const int cached); int control_event_or_authdir_new_descriptor(const char *action, const char *desc, size_t desclen, const char *msg); int control_event_my_descriptor_changed(void); int control_event_networkstatus_changed(smartlist_t *statuses); int control_event_newconsensus(const networkstatus_t *consensus); int control_event_networkstatus_changed_single(const routerstatus_t *rs); int control_event_general_status(int severity, const char *format, ...) CHECK_PRINTF(2,3); int control_event_client_status(int severity, const char *format, ...) CHECK_PRINTF(2,3); int control_event_server_status(int severity, const char *format, ...) CHECK_PRINTF(2,3); int control_event_guard(const char *nickname, const char *digest, const char *status); int control_event_conf_changed(const smartlist_t *elements); int control_event_buildtimeout_set(const circuit_build_times_t *cbt, buildtimeout_set_event_t type); int control_event_signal(uintptr_t signal); int init_cookie_authentication(int enabled); smartlist_t *decode_hashed_passwords(config_line_t *passwords); void disable_control_logging(void); void enable_control_logging(void); void monitor_owning_controller_process(const char *process_spec); void control_event_bootstrap(bootstrap_status_t status, int progress); void control_event_bootstrap_problem(const char *warn, int reason); void control_event_clients_seen(const char *controller_str); #ifdef CONTROL_PRIVATE /* Used only by control.c and test.c */ size_t write_escaped_data(const char *data, size_t len, char **out); size_t read_escaped_data(const char *data, size_t len, char **out); #endif #endif tor-0.2.4.20/src/or/circuitmux_ewma.c0000644000175000017500000005160612166112776014263 00000000000000/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file circuitmux_ewma.c * \brief EWMA circuit selection as a circuitmux_t policy **/ #define TOR_CIRCUITMUX_EWMA_C_ #include #include "or.h" #include "circuitmux.h" #include "circuitmux_ewma.h" #include "networkstatus.h" /*** EWMA parameter #defines ***/ /** How long does a tick last (seconds)? */ #define EWMA_TICK_LEN 10 /** The default per-tick scale factor, if it hasn't been overridden by a * consensus or a configuration setting. zero means "disabled". */ #define EWMA_DEFAULT_HALFLIFE 0.0 /*** Some useful constant #defines ***/ /*DOCDOC*/ #define EPSILON 0.00001 /*DOCDOC*/ #define LOG_ONEHALF -0.69314718055994529 /*** EWMA structures ***/ typedef struct cell_ewma_s cell_ewma_t; typedef struct ewma_policy_data_s ewma_policy_data_t; typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t; /** * The cell_ewma_t structure keeps track of how many cells a circuit has * transferred recently. It keeps an EWMA (exponentially weighted moving * average) of the number of cells flushed from the circuit queue onto a * connection in channel_flush_from_first_active_circuit(). */ struct cell_ewma_s { /** The last 'tick' at which we recalibrated cell_count. * * A cell sent at exactly the start of this tick has weight 1.0. Cells sent * since the start of this tick have weight greater than 1.0; ones sent * earlier have less weight. */ unsigned int last_adjusted_tick; /** The EWMA of the cell count. */ double cell_count; /** True iff this is the cell count for a circuit's previous * channel. */ unsigned int is_for_p_chan : 1; /** The position of the circuit within the OR connection's priority * queue. */ int heap_index; }; struct ewma_policy_data_s { circuitmux_policy_data_t base_; /** * Priority queue of cell_ewma_t for circuits with queued cells waiting * for room to free up on the channel that owns this circuitmux. Kept * in heap order according to EWMA. This was formerly in channel_t, and * in or_connection_t before that. */ smartlist_t *active_circuit_pqueue; /** * The tick on which the cell_ewma_ts in active_circuit_pqueue last had * their ewma values rescaled. This was formerly in channel_t, and in * or_connection_t before that. */ unsigned int active_circuit_pqueue_last_recalibrated; }; struct ewma_policy_circ_data_s { circuitmux_policy_circ_data_t base_; /** * The EWMA count for the number of cells flushed from this circuit * onto this circuitmux. Used to determine which circuit to flush * from next. This was formerly in circuit_t and or_circuit_t. */ cell_ewma_t cell_ewma; /** * Pointer back to the circuit_t this is for; since we're separating * out circuit selection policy like this, we can't attach cell_ewma_t * to the circuit_t any more, so we can't use SUBTYPE_P directly to a * circuit_t like before; instead get it here. */ circuit_t *circ; }; #define EWMA_POL_DATA_MAGIC 0x2fd8b16aU #define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U /*** Downcasts for the above types ***/ static ewma_policy_data_t * TO_EWMA_POL_DATA(circuitmux_policy_data_t *); static ewma_policy_circ_data_t * TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *); /** * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert * if the cast is impossible. */ static INLINE ewma_policy_data_t * TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol) { if (!pol) return NULL; else { tor_assert(pol->magic == EWMA_POL_DATA_MAGIC); return DOWNCAST(ewma_policy_data_t, pol); } } /** * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t * and assert if the cast is impossible. */ static INLINE ewma_policy_circ_data_t * TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol) { if (!pol) return NULL; else { tor_assert(pol->magic == EWMA_POL_CIRC_DATA_MAGIC); return DOWNCAST(ewma_policy_circ_data_t, pol); } } /*** Static declarations for circuitmux_ewma.c ***/ static void add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma); static int compare_cell_ewma_counts(const void *p1, const void *p2); static unsigned cell_ewma_tick_from_timeval(const struct timeval *now, double *remainder_out); static circuit_t * cell_ewma_to_circuit(cell_ewma_t *ewma); static INLINE double get_scale_factor(unsigned from_tick, unsigned to_tick); static cell_ewma_t * pop_first_cell_ewma(ewma_policy_data_t *pol); static void remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma); static void scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick); static void scale_active_circuits(ewma_policy_data_t *pol, unsigned cur_tick); /*** Circuitmux policy methods ***/ static circuitmux_policy_data_t * ewma_alloc_cmux_data(circuitmux_t *cmux); static void ewma_free_cmux_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data); static circuitmux_policy_circ_data_t * ewma_alloc_circ_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, cell_direction_t direction, unsigned int cell_count); static void ewma_free_circ_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, circuitmux_policy_circ_data_t *pol_circ_data); static void ewma_notify_circ_active(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, circuitmux_policy_circ_data_t *pol_circ_data); static void ewma_notify_circ_inactive(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, circuitmux_policy_circ_data_t *pol_circ_data); static void ewma_notify_xmit_cells(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, circuitmux_policy_circ_data_t *pol_circ_data, unsigned int n_cells); static circuit_t * ewma_pick_active_circuit(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data); /*** EWMA global variables ***/ /** The per-tick scale factor to be used when computing cell-count EWMA * values. (A cell sent N ticks before the start of the current tick * has value ewma_scale_factor ** N.) */ static double ewma_scale_factor = 0.1; /* DOCDOC ewma_enabled */ static int ewma_enabled = 0; /*** EWMA circuitmux_policy_t method table ***/ circuitmux_policy_t ewma_policy = { /*.alloc_cmux_data =*/ ewma_alloc_cmux_data, /*.free_cmux_data =*/ ewma_free_cmux_data, /*.alloc_circ_data =*/ ewma_alloc_circ_data, /*.free_circ_data =*/ ewma_free_circ_data, /*.notify_circ_active =*/ ewma_notify_circ_active, /*.notify_circ_inactive =*/ ewma_notify_circ_inactive, /*.notify_set_n_cells =*/ NULL, /* EWMA doesn't need this */ /*.notify_xmit_cells =*/ ewma_notify_xmit_cells, /*.pick_active_circuit =*/ ewma_pick_active_circuit }; /*** EWMA method implementations using the below EWMA helper functions ***/ /** * Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t; * this is called when setting the policy on a circuitmux_t to ewma_policy. */ static circuitmux_policy_data_t * ewma_alloc_cmux_data(circuitmux_t *cmux) { ewma_policy_data_t *pol = NULL; tor_assert(cmux); pol = tor_malloc_zero(sizeof(*pol)); pol->base_.magic = EWMA_POL_DATA_MAGIC; pol->active_circuit_pqueue = smartlist_new(); pol->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick(); return TO_CMUX_POL_DATA(pol); } /** * Free an ewma_policy_data_t allocated with ewma_alloc_cmux_data() */ static void ewma_free_cmux_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data) { ewma_policy_data_t *pol = NULL; tor_assert(cmux); if (!pol_data) return; pol = TO_EWMA_POL_DATA(pol_data); smartlist_free(pol->active_circuit_pqueue); tor_free(pol); } /** * Allocate an ewma_policy_circ_data_t and upcast it to a * circuitmux_policy_data_t; this is called when attaching a circuit to a * circuitmux_t with ewma_policy. */ static circuitmux_policy_circ_data_t * ewma_alloc_circ_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, cell_direction_t direction, unsigned int cell_count) { ewma_policy_circ_data_t *cdata = NULL; tor_assert(cmux); tor_assert(pol_data); tor_assert(circ); tor_assert(direction == CELL_DIRECTION_OUT || direction == CELL_DIRECTION_IN); /* Shut the compiler up */ tor_assert(cell_count == cell_count); cdata = tor_malloc_zero(sizeof(*cdata)); cdata->base_.magic = EWMA_POL_CIRC_DATA_MAGIC; cdata->circ = circ; /* * Initialize the cell_ewma_t structure (formerly in * init_circuit_base()) */ cdata->cell_ewma.last_adjusted_tick = cell_ewma_get_tick(); cdata->cell_ewma.cell_count = 0.0; cdata->cell_ewma.heap_index = -1; if (direction == CELL_DIRECTION_IN) { cdata->cell_ewma.is_for_p_chan = 1; } else { cdata->cell_ewma.is_for_p_chan = 0; } return TO_CMUX_POL_CIRC_DATA(cdata); } /** * Free an ewma_policy_circ_data_t allocated with ewma_alloc_circ_data() */ static void ewma_free_circ_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, circuitmux_policy_circ_data_t *pol_circ_data) { ewma_policy_circ_data_t *cdata = NULL; tor_assert(cmux); tor_assert(circ); tor_assert(pol_data); if (!pol_circ_data) return; cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); tor_free(cdata); } /** * Handle circuit activation; this inserts the circuit's cell_ewma into * the active_circuits_pqueue. */ static void ewma_notify_circ_active(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, circuitmux_policy_circ_data_t *pol_circ_data) { ewma_policy_data_t *pol = NULL; ewma_policy_circ_data_t *cdata = NULL; tor_assert(cmux); tor_assert(pol_data); tor_assert(circ); tor_assert(pol_circ_data); pol = TO_EWMA_POL_DATA(pol_data); cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); add_cell_ewma(pol, &(cdata->cell_ewma)); } /** * Handle circuit deactivation; this removes the circuit's cell_ewma from * the active_circuits_pqueue. */ static void ewma_notify_circ_inactive(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, circuitmux_policy_circ_data_t *pol_circ_data) { ewma_policy_data_t *pol = NULL; ewma_policy_circ_data_t *cdata = NULL; tor_assert(cmux); tor_assert(pol_data); tor_assert(circ); tor_assert(pol_circ_data); pol = TO_EWMA_POL_DATA(pol_data); cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); remove_cell_ewma(pol, &(cdata->cell_ewma)); } /** * Update cell_ewma for this circuit after we've sent some cells, and * remove/reinsert it in the queue. This used to be done (brokenly, * see bug 6816) in channel_flush_from_first_active_circuit(). */ static void ewma_notify_xmit_cells(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, circuit_t *circ, circuitmux_policy_circ_data_t *pol_circ_data, unsigned int n_cells) { ewma_policy_data_t *pol = NULL; ewma_policy_circ_data_t *cdata = NULL; unsigned int tick; double fractional_tick, ewma_increment; /* The current (hi-res) time */ struct timeval now_hires; cell_ewma_t *cell_ewma, *tmp; tor_assert(cmux); tor_assert(pol_data); tor_assert(circ); tor_assert(pol_circ_data); tor_assert(n_cells > 0); pol = TO_EWMA_POL_DATA(pol_data); cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); /* Rescale the EWMAs if needed */ tor_gettimeofday_cached(&now_hires); tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick); if (tick != pol->active_circuit_pqueue_last_recalibrated) { scale_active_circuits(pol, tick); } /* How much do we adjust the cell count in cell_ewma by? */ ewma_increment = ((double)(n_cells)) * pow(ewma_scale_factor, -fractional_tick); /* Do the adjustment */ cell_ewma = &(cdata->cell_ewma); cell_ewma->cell_count += ewma_increment; /* * Since we just sent on this circuit, it should be at the head of * the queue. Pop the head, assert that it matches, then re-add. */ tmp = pop_first_cell_ewma(pol); tor_assert(tmp == cell_ewma); add_cell_ewma(pol, cell_ewma); } /** * Pick the preferred circuit to send from; this will be the one with * the lowest EWMA value in the priority queue. This used to be done * in channel_flush_from_first_active_circuit(). */ static circuit_t * ewma_pick_active_circuit(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data) { ewma_policy_data_t *pol = NULL; circuit_t *circ = NULL; cell_ewma_t *cell_ewma = NULL; tor_assert(cmux); tor_assert(pol_data); pol = TO_EWMA_POL_DATA(pol_data); if (smartlist_len(pol->active_circuit_pqueue) > 0) { /* Get the head of the queue */ cell_ewma = smartlist_get(pol->active_circuit_pqueue, 0); circ = cell_ewma_to_circuit(cell_ewma); } return circ; } /** Helper for sorting cell_ewma_t values in their priority queue. */ static int compare_cell_ewma_counts(const void *p1, const void *p2) { const cell_ewma_t *e1 = p1, *e2 = p2; if (e1->cell_count < e2->cell_count) return -1; else if (e1->cell_count > e2->cell_count) return 1; else return 0; } /** Given a cell_ewma_t, return a pointer to the circuit containing it. */ static circuit_t * cell_ewma_to_circuit(cell_ewma_t *ewma) { ewma_policy_circ_data_t *cdata = NULL; tor_assert(ewma); cdata = SUBTYPE_P(ewma, ewma_policy_circ_data_t, cell_ewma); tor_assert(cdata); return cdata->circ; } /* ==== Functions for scaling cell_ewma_t ==== When choosing which cells to relay first, we favor circuits that have been quiet recently. This gives better latency on connections that aren't pushing lots of data, and makes the network feel more interactive. Conceptually, we take an exponentially weighted mean average of the number of cells a circuit has sent, and allow active circuits (those with cells to relay) to send cells in reverse order of their exponentially-weighted mean average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts' F^N times as much as a cell sent now, for 0now, compute the cell_ewma tick in which it occurs * and the fraction of the tick that has elapsed between the start of the tick * and now. Return the former and store the latter in * *remainder_out. * * These tick values are not meant to be shared between Tor instances, or used * for other purposes. */ static unsigned cell_ewma_tick_from_timeval(const struct timeval *now, double *remainder_out) { unsigned res = (unsigned) (now->tv_sec / EWMA_TICK_LEN); /* rem */ double rem = (now->tv_sec % EWMA_TICK_LEN) + ((double)(now->tv_usec)) / 1.0e6; *remainder_out = rem / EWMA_TICK_LEN; return res; } /** Tell the caller whether ewma_enabled is set */ int cell_ewma_enabled(void) { return ewma_enabled; } /** Compute and return the current cell_ewma tick. */ unsigned int cell_ewma_get_tick(void) { return ((unsigned)approx_time() / EWMA_TICK_LEN); } /** Adjust the global cell scale factor based on options */ void cell_ewma_set_scale_factor(const or_options_t *options, const networkstatus_t *consensus) { int32_t halflife_ms; double halflife; const char *source; if (options && options->CircuitPriorityHalflife >= -EPSILON) { halflife = options->CircuitPriorityHalflife; source = "CircuitPriorityHalflife in configuration"; } else if (consensus && (halflife_ms = networkstatus_get_param( consensus, "CircuitPriorityHalflifeMsec", -1, -1, INT32_MAX)) >= 0) { halflife = ((double)halflife_ms)/1000.0; source = "CircuitPriorityHalflifeMsec in consensus"; } else { halflife = EWMA_DEFAULT_HALFLIFE; source = "Default value"; } if (halflife <= EPSILON) { /* The cell EWMA algorithm is disabled. */ ewma_scale_factor = 0.1; ewma_enabled = 0; log_info(LD_OR, "Disabled cell_ewma algorithm because of value in %s", source); } else { /* convert halflife into halflife-per-tick. */ halflife /= EWMA_TICK_LEN; /* compute per-tick scale factor. */ ewma_scale_factor = exp( LOG_ONEHALF / halflife ); ewma_enabled = 1; log_info(LD_OR, "Enabled cell_ewma algorithm because of value in %s; " "scale factor is %f per %d seconds", source, ewma_scale_factor, EWMA_TICK_LEN); } } /** Return the multiplier necessary to convert the value of a cell sent in * 'from_tick' to one sent in 'to_tick'. */ static INLINE double get_scale_factor(unsigned from_tick, unsigned to_tick) { /* This math can wrap around, but that's okay: unsigned overflow is well-defined */ int diff = (int)(to_tick - from_tick); return pow(ewma_scale_factor, diff); } /** Adjust the cell count of ewma so that it is scaled with respect to * cur_tick */ static void scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick) { double factor = get_scale_factor(ewma->last_adjusted_tick, cur_tick); ewma->cell_count *= factor; ewma->last_adjusted_tick = cur_tick; } /** Adjust the cell count of every active circuit on chan so * that they are scaled with respect to cur_tick */ static void scale_active_circuits(ewma_policy_data_t *pol, unsigned cur_tick) { double factor; tor_assert(pol); tor_assert(pol->active_circuit_pqueue); factor = get_scale_factor( pol->active_circuit_pqueue_last_recalibrated, cur_tick); /** Ordinarily it isn't okay to change the value of an element in a heap, * but it's okay here, since we are preserving the order. */ SMARTLIST_FOREACH_BEGIN( pol->active_circuit_pqueue, cell_ewma_t *, e) { tor_assert(e->last_adjusted_tick == pol->active_circuit_pqueue_last_recalibrated); e->cell_count *= factor; e->last_adjusted_tick = cur_tick; } SMARTLIST_FOREACH_END(e); pol->active_circuit_pqueue_last_recalibrated = cur_tick; } /** Rescale ewma to the same scale as pol, and add it to * pol's priority queue of active circuits */ static void add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma) { tor_assert(pol); tor_assert(pol->active_circuit_pqueue); tor_assert(ewma); tor_assert(ewma->heap_index == -1); scale_single_cell_ewma( ewma, pol->active_circuit_pqueue_last_recalibrated); smartlist_pqueue_add(pol->active_circuit_pqueue, compare_cell_ewma_counts, STRUCT_OFFSET(cell_ewma_t, heap_index), ewma); } /** Remove ewma from pol's priority queue of active circuits */ static void remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma) { tor_assert(pol); tor_assert(pol->active_circuit_pqueue); tor_assert(ewma); tor_assert(ewma->heap_index != -1); smartlist_pqueue_remove(pol->active_circuit_pqueue, compare_cell_ewma_counts, STRUCT_OFFSET(cell_ewma_t, heap_index), ewma); } /** Remove and return the first cell_ewma_t from pol's priority queue of * active circuits. Requires that the priority queue is nonempty. */ static cell_ewma_t * pop_first_cell_ewma(ewma_policy_data_t *pol) { tor_assert(pol); tor_assert(pol->active_circuit_pqueue); return smartlist_pqueue_pop(pol->active_circuit_pqueue, compare_cell_ewma_counts, STRUCT_OFFSET(cell_ewma_t, heap_index)); } tor-0.2.4.20/src/or/replaycache.c0000644000175000017500000001253312255745673013341 00000000000000 /* Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* * \file replaycache.c * * \brief Self-scrubbing replay cache for rendservice.c */ #define REPLAYCACHE_PRIVATE #include "or.h" #include "replaycache.h" /** Free the replaycache r and all of its entries. */ void replaycache_free(replaycache_t *r) { if (!r) { log_info(LD_BUG, "replaycache_free() called on NULL"); return; } if (r->digests_seen) digestmap_free(r->digests_seen, tor_free_); tor_free(r); } /** Allocate a new, empty replay detection cache, where horizon is the time * for entries to age out and interval is the time after which the cache * should be scrubbed for old entries. */ replaycache_t * replaycache_new(time_t horizon, time_t interval) { replaycache_t *r = NULL; if (horizon < 0) { log_info(LD_BUG, "replaycache_new() called with negative" " horizon parameter"); goto err; } if (interval < 0) { log_info(LD_BUG, "replaycache_new() called with negative interval" " parameter"); interval = 0; } r = tor_malloc(sizeof(*r)); r->scrub_interval = interval; r->scrubbed = 0; r->horizon = horizon; r->digests_seen = digestmap_new(); err: return r; } /** See documentation for replaycache_add_and_test() */ int replaycache_add_and_test_internal( time_t present, replaycache_t *r, const void *data, int len, time_t *elapsed) { int rv = 0; char digest[DIGEST_LEN]; time_t *access_time; /* sanity check */ if (present <= 0 || !r || !data || len <= 0) { log_info(LD_BUG, "replaycache_add_and_test_internal() called with stupid" " parameters; please fix this."); goto done; } /* compute digest */ crypto_digest(digest, (const char *)data, len); /* check map */ access_time = digestmap_get(r->digests_seen, digest); /* seen before? */ if (access_time != NULL) { /* * If it's far enough in the past, no hit. If the horizon is zero, we * never expire. */ if (*access_time >= present - r->horizon || r->horizon == 0) { /* replay cache hit, return 1 */ rv = 1; /* If we want to output an elapsed time, do so */ if (elapsed) { if (present >= *access_time) { *elapsed = present - *access_time; } else { /* We shouldn't really be seeing hits from the future, but... */ *elapsed = 0; } } } /* * If it's ahead of the cached time, update */ if (*access_time < present) { *access_time = present; } } else { /* No, so no hit and update the digest map with the current time */ access_time = tor_malloc(sizeof(*access_time)); *access_time = present; digestmap_set(r->digests_seen, digest, access_time); } /* now scrub the cache if it's time */ replaycache_scrub_if_needed_internal(present, r); done: return rv; } /** See documentation for replaycache_scrub_if_needed() */ void replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r) { digestmap_iter_t *itr = NULL; const char *digest; void *valp; time_t *access_time; char scrub_this; /* sanity check */ if (!r || !(r->digests_seen)) { log_info(LD_BUG, "replaycache_scrub_if_needed_internal() called with" " stupid parameters; please fix this."); return; } /* scrub time yet? (scrubbed == 0 indicates never scrubbed before) */ if (present - r->scrubbed < r->scrub_interval && r->scrubbed > 0) return; /* if we're never expiring, don't bother scrubbing */ if (r->horizon == 0) return; /* okay, scrub time */ itr = digestmap_iter_init(r->digests_seen); while (!digestmap_iter_done(itr)) { scrub_this = 0; digestmap_iter_get(itr, &digest, &valp); access_time = (time_t *)valp; if (access_time) { /* aged out yet? */ if (*access_time < present - r->horizon) scrub_this = 1; } else { /* Buh? Get rid of it, anyway */ log_info(LD_BUG, "replaycache_scrub_if_needed_internal() saw a NULL" " entry in the digestmap."); scrub_this = 1; } if (scrub_this) { /* Advance the iterator and remove this one */ itr = digestmap_iter_next_rmv(r->digests_seen, itr); /* Free the value removed */ tor_free(access_time); } else { /* Just advance the iterator */ itr = digestmap_iter_next(r->digests_seen, itr); } } /* update scrubbed timestamp */ if (present > r->scrubbed) r->scrubbed = present; } /** Test the buffer of length len point to by data against the replay cache r; * the digest of the buffer will be added to the cache at the current time, * and the function will return 1 if it was already seen within the cache's * horizon, or 0 otherwise. */ int replaycache_add_and_test(replaycache_t *r, const void *data, int len) { return replaycache_add_and_test_internal(time(NULL), r, data, len, NULL); } /** Like replaycache_add_and_test(), but if it's a hit also return the time * elapsed since this digest was last seen. */ int replaycache_add_test_and_elapsed( replaycache_t *r, const void *data, int len, time_t *elapsed) { return replaycache_add_and_test_internal(time(NULL), r, data, len, elapsed); } /** Scrub aged entries out of r if sufficiently long has elapsed since r was * last scrubbed. */ void replaycache_scrub_if_needed(replaycache_t *r) { replaycache_scrub_if_needed_internal(time(NULL), r); } tor-0.2.4.20/src/or/channeltls.h0000644000175000017500000000330512166112776013207 00000000000000/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file channeltls.h * \brief Header file for channeltls.c **/ #ifndef TOR_CHANNELTLS_H #define TOR_CHANNELTLS_H #include "or.h" #include "channel.h" #define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c))) #define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c))) #define TLS_CHAN_MAGIC 0x8a192427U #ifdef TOR_CHANNEL_INTERNAL_ struct channel_tls_s { /* Base channel_t struct */ channel_t base_; /* or_connection_t pointer */ or_connection_t *conn; }; #endif /* TOR_CHANNEL_INTERNAL_ */ channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port, const char *id_digest); channel_listener_t * channel_tls_get_listener(void); channel_listener_t * channel_tls_start_listener(void); channel_t * channel_tls_handle_incoming(or_connection_t *orconn); /* Casts */ channel_t * channel_tls_to_base(channel_tls_t *tlschan); channel_tls_t * channel_tls_from_base(channel_t *chan); /* Things for connection_or.c to call back into */ ssize_t channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells); int channel_tls_more_to_flush(channel_tls_t *chan); void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn); void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan, or_connection_t *conn, uint8_t old_state, uint8_t state); void channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn); /* Cleanup at shutdown */ void channel_tls_free_all(void); #endif tor-0.2.4.20/src/or/channel.c0000644000175000017500000034510312255745673012473 00000000000000/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file channel.c * \brief OR-to-OR channel abstraction layer **/ /* * Define this so channel.h gives us things only channel_t subclasses * should touch. */ #define TOR_CHANNEL_INTERNAL_ #include "or.h" #include "channel.h" #include "channeltls.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuitstats.h" #include "connection_or.h" /* For var_cell_free() */ #include "circuitmux.h" #include "entrynodes.h" #include "geoip.h" #include "nodelist.h" #include "relay.h" #include "rephist.h" #include "router.h" #include "routerlist.h" /* Cell queue structure */ typedef struct cell_queue_entry_s cell_queue_entry_t; struct cell_queue_entry_s { TOR_SIMPLEQ_ENTRY(cell_queue_entry_s) next; enum { CELL_QUEUE_FIXED, CELL_QUEUE_VAR, CELL_QUEUE_PACKED } type; union { struct { cell_t *cell; } fixed; struct { var_cell_t *var_cell; } var; struct { packed_cell_t *packed_cell; } packed; } u; }; /* Global lists of channels */ /* All channel_t instances */ static smartlist_t *all_channels = NULL; /* All channel_t instances not in ERROR or CLOSED states */ static smartlist_t *active_channels = NULL; /* All channel_t instances in ERROR or CLOSED states */ static smartlist_t *finished_channels = NULL; /* All channel_listener_t instances */ static smartlist_t *all_listeners = NULL; /* All channel_listener_t instances in LISTENING state */ static smartlist_t *active_listeners = NULL; /* All channel_listener_t instances in LISTENING state */ static smartlist_t *finished_listeners = NULL; /* Counter for ID numbers */ static uint64_t n_channels_allocated = 0; /* Digest->channel map * * Similar to the one used in connection_or.c, this maps from the identity * digest of a remote endpoint to a channel_t to that endpoint. Channels * should be placed here when registered and removed when they close or error. * If more than one channel exists, follow the next_with_same_id pointer * as a linked list. */ HT_HEAD(channel_idmap, channel_idmap_entry_s) channel_identity_map = HT_INITIALIZER(); typedef struct channel_idmap_entry_s { HT_ENTRY(channel_idmap_entry_s) node; uint8_t digest[DIGEST_LEN]; TOR_LIST_HEAD(channel_list_s, channel_s) channel_list; } channel_idmap_entry_t; static INLINE unsigned channel_idmap_hash(const channel_idmap_entry_t *ent) { const unsigned *a = (const unsigned *)ent->digest; #if SIZEOF_INT == 4 return a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4]; #elif SIZEOF_INT == 8 return a[0] ^ a[1]; #endif } static INLINE int channel_idmap_eq(const channel_idmap_entry_t *a, const channel_idmap_entry_t *b) { return tor_memeq(a->digest, b->digest, DIGEST_LEN); } HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, channel_idmap_eq); HT_GENERATE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, channel_idmap_eq, 0.5, tor_malloc, tor_realloc, tor_free_); static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q); static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off); static int cell_queue_entry_is_padding(cell_queue_entry_t *q); static cell_queue_entry_t * cell_queue_entry_new_fixed(cell_t *cell); static cell_queue_entry_t * cell_queue_entry_new_var(var_cell_t *var_cell); /* Functions to maintain the digest map */ static void channel_add_to_digest_map(channel_t *chan); static void channel_remove_from_digest_map(channel_t *chan); /* * Flush cells from just the outgoing queue without trying to get them * from circuits; used internall by channel_flush_some_cells(). */ static ssize_t channel_flush_some_cells_from_outgoing_queue(channel_t *chan, ssize_t num_cells); static void channel_force_free(channel_t *chan); static void channel_free_list(smartlist_t *channels, int mark_for_close); static void channel_listener_free_list(smartlist_t *channels, int mark_for_close); static void channel_listener_force_free(channel_listener_t *chan_l); static void channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q); /*********************************** * Channel state utility functions * **********************************/ /** * Indicate whether a given channel state is valid */ int channel_state_is_valid(channel_state_t state) { int is_valid; switch (state) { case CHANNEL_STATE_CLOSED: case CHANNEL_STATE_CLOSING: case CHANNEL_STATE_ERROR: case CHANNEL_STATE_MAINT: case CHANNEL_STATE_OPENING: case CHANNEL_STATE_OPEN: is_valid = 1; break; case CHANNEL_STATE_LAST: default: is_valid = 0; } return is_valid; } /** * Indicate whether a given channel listener state is valid */ int channel_listener_state_is_valid(channel_listener_state_t state) { int is_valid; switch (state) { case CHANNEL_LISTENER_STATE_CLOSED: case CHANNEL_LISTENER_STATE_LISTENING: case CHANNEL_LISTENER_STATE_CLOSING: case CHANNEL_LISTENER_STATE_ERROR: is_valid = 1; break; case CHANNEL_LISTENER_STATE_LAST: default: is_valid = 0; } return is_valid; } /** * Indicate whether a channel state transition is valid * * This function takes two channel states and indicates whether a * transition between them is permitted (see the state definitions and * transition table in or.h at the channel_state_t typedef). */ int channel_state_can_transition(channel_state_t from, channel_state_t to) { int is_valid; switch (from) { case CHANNEL_STATE_CLOSED: is_valid = (to == CHANNEL_STATE_OPENING); break; case CHANNEL_STATE_CLOSING: is_valid = (to == CHANNEL_STATE_CLOSED || to == CHANNEL_STATE_ERROR); break; case CHANNEL_STATE_ERROR: is_valid = 0; break; case CHANNEL_STATE_MAINT: is_valid = (to == CHANNEL_STATE_CLOSING || to == CHANNEL_STATE_ERROR || to == CHANNEL_STATE_OPEN); break; case CHANNEL_STATE_OPENING: is_valid = (to == CHANNEL_STATE_CLOSING || to == CHANNEL_STATE_ERROR || to == CHANNEL_STATE_OPEN); break; case CHANNEL_STATE_OPEN: is_valid = (to == CHANNEL_STATE_CLOSING || to == CHANNEL_STATE_ERROR || to == CHANNEL_STATE_MAINT); break; case CHANNEL_STATE_LAST: default: is_valid = 0; } return is_valid; } /** * Indicate whether a channel listener state transition is valid * * This function takes two channel listener states and indicates whether a * transition between them is permitted (see the state definitions and * transition table in or.h at the channel_listener_state_t typedef). */ int channel_listener_state_can_transition(channel_listener_state_t from, channel_listener_state_t to) { int is_valid; switch (from) { case CHANNEL_LISTENER_STATE_CLOSED: is_valid = (to == CHANNEL_LISTENER_STATE_LISTENING); break; case CHANNEL_LISTENER_STATE_CLOSING: is_valid = (to == CHANNEL_LISTENER_STATE_CLOSED || to == CHANNEL_LISTENER_STATE_ERROR); break; case CHANNEL_LISTENER_STATE_ERROR: is_valid = 0; break; case CHANNEL_LISTENER_STATE_LISTENING: is_valid = (to == CHANNEL_LISTENER_STATE_CLOSING || to == CHANNEL_LISTENER_STATE_ERROR); break; case CHANNEL_LISTENER_STATE_LAST: default: is_valid = 0; } return is_valid; } /** * Return a human-readable description for a channel state */ const char * channel_state_to_string(channel_state_t state) { const char *descr; switch (state) { case CHANNEL_STATE_CLOSED: descr = "closed"; break; case CHANNEL_STATE_CLOSING: descr = "closing"; break; case CHANNEL_STATE_ERROR: descr = "channel error"; break; case CHANNEL_STATE_MAINT: descr = "temporarily suspended for maintenance"; break; case CHANNEL_STATE_OPENING: descr = "opening"; break; case CHANNEL_STATE_OPEN: descr = "open"; break; case CHANNEL_STATE_LAST: default: descr = "unknown or invalid channel state"; } return descr; } /** * Return a human-readable description for a channel listenier state */ const char * channel_listener_state_to_string(channel_listener_state_t state) { const char *descr; switch (state) { case CHANNEL_LISTENER_STATE_CLOSED: descr = "closed"; break; case CHANNEL_LISTENER_STATE_CLOSING: descr = "closing"; break; case CHANNEL_LISTENER_STATE_ERROR: descr = "channel listener error"; break; case CHANNEL_LISTENER_STATE_LISTENING: descr = "listening"; break; case CHANNEL_LISTENER_STATE_LAST: default: descr = "unknown or invalid channel listener state"; } return descr; } /*************************************** * Channel registration/unregistration * ***************************************/ /** * Register a channel * * This function registers a newly created channel in the global lists/maps * of active channels. */ void channel_register(channel_t *chan) { tor_assert(chan); /* No-op if already registered */ if (chan->registered) return; log_debug(LD_CHANNEL, "Registering channel %p (ID " U64_FORMAT ") " "in state %s (%d) with digest %s", chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->identity_digest, DIGEST_LEN)); /* Make sure we have all_channels, then add it */ if (!all_channels) all_channels = smartlist_new(); smartlist_add(all_channels, chan); /* Is it finished? */ if (chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR) { /* Put it in the finished list, creating it if necessary */ if (!finished_channels) finished_channels = smartlist_new(); smartlist_add(finished_channels, chan); } else { /* Put it in the active list, creating it if necessary */ if (!active_channels) active_channels = smartlist_new(); smartlist_add(active_channels, chan); if (chan->state != CHANNEL_STATE_CLOSING) { /* It should have a digest set */ if (!tor_digest_is_zero(chan->identity_digest)) { /* Yeah, we're good, add it to the map */ channel_add_to_digest_map(chan); } else { log_info(LD_CHANNEL, "Channel %p (global ID " U64_FORMAT ") " "in state %s (%d) registered with no identity digest", chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state); } } } /* Mark it as registered */ chan->registered = 1; } /** * Unregister a channel * * This function removes a channel from the global lists and maps and is used * when freeing a closed/errored channel. */ void channel_unregister(channel_t *chan) { tor_assert(chan); /* No-op if not registered */ if (!(chan->registered)) return; /* Is it finished? */ if (chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR) { /* Get it out of the finished list */ if (finished_channels) smartlist_remove(finished_channels, chan); } else { /* Get it out of the active list */ if (active_channels) smartlist_remove(active_channels, chan); } /* Get it out of all_channels */ if (all_channels) smartlist_remove(all_channels, chan); /* Mark it as unregistered */ chan->registered = 0; /* Should it be in the digest map? */ if (!tor_digest_is_zero(chan->identity_digest) && !(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR)) { /* Remove it */ channel_remove_from_digest_map(chan); } } /** * Register a channel listener * * This function registers a newly created channel listner in the global * lists/maps of active channel listeners. */ void channel_listener_register(channel_listener_t *chan_l) { tor_assert(chan_l); /* No-op if already registered */ if (chan_l->registered) return; log_debug(LD_CHANNEL, "Registering channel listener %p (ID " U64_FORMAT ") " "in state %s (%d)", chan_l, U64_PRINTF_ARG(chan_l->global_identifier), channel_listener_state_to_string(chan_l->state), chan_l->state); /* Make sure we have all_channels, then add it */ if (!all_listeners) all_listeners = smartlist_new(); smartlist_add(all_listeners, chan_l); /* Is it finished? */ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR) { /* Put it in the finished list, creating it if necessary */ if (!finished_listeners) finished_listeners = smartlist_new(); smartlist_add(finished_listeners, chan_l); } else { /* Put it in the active list, creating it if necessary */ if (!active_listeners) active_listeners = smartlist_new(); smartlist_add(active_listeners, chan_l); } /* Mark it as registered */ chan_l->registered = 1; } /** * Unregister a channel listener * * This function removes a channel listener from the global lists and maps * and is used when freeing a closed/errored channel listener. */ void channel_listener_unregister(channel_listener_t *chan_l) { tor_assert(chan_l); /* No-op if not registered */ if (!(chan_l->registered)) return; /* Is it finished? */ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR) { /* Get it out of the finished list */ if (finished_listeners) smartlist_remove(finished_listeners, chan_l); } else { /* Get it out of the active list */ if (active_listeners) smartlist_remove(active_listeners, chan_l); } /* Get it out of all_channels */ if (all_listeners) smartlist_remove(all_listeners, chan_l); /* Mark it as unregistered */ chan_l->registered = 0; } /********************************* * Channel digest map maintenance *********************************/ /** * Add a channel to the digest map * * This function adds a channel to the digest map and inserts it into the * correct linked list if channels with that remote endpoint identity digest * already exist. */ static void channel_add_to_digest_map(channel_t *chan) { channel_idmap_entry_t *ent, search; tor_assert(chan); /* Assert that the state makes sense */ tor_assert(!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR)); /* Assert that there is a digest */ tor_assert(!tor_digest_is_zero(chan->identity_digest)); memcpy(search.digest, chan->identity_digest, DIGEST_LEN); ent = HT_FIND(channel_idmap, &channel_identity_map, &search); if (! ent) { ent = tor_malloc(sizeof(channel_idmap_entry_t)); memcpy(ent->digest, chan->identity_digest, DIGEST_LEN); TOR_LIST_INIT(&ent->channel_list); HT_INSERT(channel_idmap, &channel_identity_map, ent); } TOR_LIST_INSERT_HEAD(&ent->channel_list, chan, next_with_same_id); log_debug(LD_CHANNEL, "Added channel %p (global ID " U64_FORMAT ") " "to identity map in state %s (%d) with digest %s", chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->identity_digest, DIGEST_LEN)); } /** * Remove a channel from the digest map * * This function removes a channel from the digest map and the linked list of * channels for that digest if more than one exists. */ static void channel_remove_from_digest_map(channel_t *chan) { channel_idmap_entry_t *ent, search; tor_assert(chan); /* Assert that there is a digest */ tor_assert(!tor_digest_is_zero(chan->identity_digest)); #if 0 /* Make sure we have a map */ if (!channel_identity_map) { /* * No identity map, so we can't find it by definition. This * case is similar to digestmap_get() failing below. */ log_warn(LD_BUG, "Trying to remove channel %p (global ID " U64_FORMAT ") " "with digest %s from identity map, but didn't have any identity " "map", chan, U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->identity_digest, DIGEST_LEN)); /* Clear out its next/prev pointers */ if (chan->next_with_same_id) { chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; } if (chan->prev_with_same_id) { chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; } chan->next_with_same_id = NULL; chan->prev_with_same_id = NULL; return; } #endif /* Pull it out of its list, wherever that list is */ TOR_LIST_REMOVE(chan, next_with_same_id); memcpy(search.digest, chan->identity_digest, DIGEST_LEN); ent = HT_FIND(channel_idmap, &channel_identity_map, &search); /* Look for it in the map */ if (ent) { /* Okay, it's here */ if (TOR_LIST_EMPTY(&ent->channel_list)) { HT_REMOVE(channel_idmap, &channel_identity_map, ent); tor_free(ent); } log_debug(LD_CHANNEL, "Removed channel %p (global ID " U64_FORMAT ") from " "identity map in state %s (%d) with digest %s", chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->identity_digest, DIGEST_LEN)); } else { /* Shouldn't happen */ log_warn(LD_BUG, "Trying to remove channel %p (global ID " U64_FORMAT ") with " "digest %s from identity map, but couldn't find any with " "that digest", chan, U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->identity_digest, DIGEST_LEN)); } } /**************************** * Channel lookup functions * ***************************/ /** * Find channel by global ID * * This function searches for a channel by the global_identifier assigned * at initialization time. This identifier is unique for the lifetime of the * Tor process. */ channel_t * channel_find_by_global_id(uint64_t global_identifier) { channel_t *rv = NULL; if (all_channels && smartlist_len(all_channels) > 0) { SMARTLIST_FOREACH_BEGIN(all_channels, channel_t *, curr) { if (curr->global_identifier == global_identifier) { rv = curr; break; } } SMARTLIST_FOREACH_END(curr); } return rv; } /** * Find channel by digest of the remote endpoint * * This function looks up a channel by the digest of its remote endpoint in * the channel digest map. It's possible that more than one channel to a * given endpoint exists. Use channel_next_with_digest() to walk the list. */ channel_t * channel_find_by_remote_digest(const char *identity_digest) { channel_t *rv = NULL; channel_idmap_entry_t *ent, search; tor_assert(identity_digest); memcpy(search.digest, identity_digest, DIGEST_LEN); ent = HT_FIND(channel_idmap, &channel_identity_map, &search); if (ent) { rv = TOR_LIST_FIRST(&ent->channel_list); } return rv; } /** * Get next channel with digest * * This function takes a channel and finds the next channel in the list * with the same digest. */ channel_t * channel_next_with_digest(channel_t *chan) { tor_assert(chan); return TOR_LIST_NEXT(chan, next_with_same_id); } /** * Initialize a channel * * This function should be called by subclasses to set up some per-channel * variables. I.e., this is the superclass constructor. Before this, the * channel should be allocated with tor_malloc_zero(). */ void channel_init(channel_t *chan) { tor_assert(chan); /* Assign an ID and bump the counter */ chan->global_identifier = n_channels_allocated++; /* Init timestamp */ chan->timestamp_last_added_nonpadding = time(NULL); /* Init next_circ_id */ chan->next_circ_id = crypto_rand_int(1 << 15); /* Initialize queues. */ TOR_SIMPLEQ_INIT(&chan->incoming_queue); TOR_SIMPLEQ_INIT(&chan->outgoing_queue); /* Initialize list entries. */ memset(&chan->next_with_same_id, 0, sizeof(chan->next_with_same_id)); /* Timestamp it */ channel_timestamp_created(chan); /* It hasn't been open yet. */ chan->has_been_open = 0; } /** * Initialize a channel listener * * This function should be called by subclasses to set up some per-channel * variables. I.e., this is the superclass constructor. Before this, the * channel listener should be allocated with tor_malloc_zero(). */ void channel_init_listener(channel_listener_t *chan_l) { tor_assert(chan_l); /* Assign an ID and bump the counter */ chan_l->global_identifier = n_channels_allocated++; /* Timestamp it */ channel_listener_timestamp_created(chan_l); } /** * Free a channel; nothing outside of channel.c and subclasses should call * this - it frees channels after they have closed and been unregistered. */ void channel_free(channel_t *chan) { if (!chan) return; /* It must be closed or errored */ tor_assert(chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); /* It must be deregistered */ tor_assert(!(chan->registered)); log_debug(LD_CHANNEL, "Freeing channel " U64_FORMAT " at %p", U64_PRINTF_ARG(chan->global_identifier), chan); /* * Get rid of cmux policy before we do anything, so cmux policies don't * see channels in weird half-freed states. */ if (chan->cmux) { circuitmux_set_policy(chan->cmux, NULL); } /* Call a free method if there is one */ if (chan->free) chan->free(chan); channel_clear_remote_end(chan); /* Get rid of cmux */ if (chan->cmux) { circuitmux_detach_all_circuits(chan->cmux); circuitmux_free(chan->cmux); chan->cmux = NULL; } /* We're in CLOSED or ERROR, so the cell queue is already empty */ tor_free(chan); } /** * Free a channel listener; nothing outside of channel.c and subclasses * should call this - it frees channel listeners after they have closed and * been unregistered. */ void channel_listener_free(channel_listener_t *chan_l) { if (!chan_l) return; log_debug(LD_CHANNEL, "Freeing channel_listener_t " U64_FORMAT " at %p", U64_PRINTF_ARG(chan_l->global_identifier), chan_l); /* It must be closed or errored */ tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR); /* It must be deregistered */ tor_assert(!(chan_l->registered)); /* Call a free method if there is one */ if (chan_l->free) chan_l->free(chan_l); /* * We're in CLOSED or ERROR, so the incoming channel queue is already * empty. */ tor_free(chan_l); } /** * Free a channel and skip the state/registration asserts; this internal- * use-only function should be called only from channel_free_all() when * shutting down the Tor process. */ static void channel_force_free(channel_t *chan) { cell_queue_entry_t *cell, *cell_tmp; tor_assert(chan); log_debug(LD_CHANNEL, "Force-freeing channel " U64_FORMAT " at %p", U64_PRINTF_ARG(chan->global_identifier), chan); /* * Get rid of cmux policy before we do anything, so cmux policies don't * see channels in weird half-freed states. */ if (chan->cmux) { circuitmux_set_policy(chan->cmux, NULL); } /* Call a free method if there is one */ if (chan->free) chan->free(chan); channel_clear_remote_end(chan); /* Get rid of cmux */ if (chan->cmux) { circuitmux_free(chan->cmux); chan->cmux = NULL; } /* We might still have a cell queue; kill it */ TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) { cell_queue_entry_free(cell, 0); } TOR_SIMPLEQ_INIT(&chan->incoming_queue); /* Outgoing cell queue is similar, but we can have to free packed cells */ TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) { cell_queue_entry_free(cell, 0); } TOR_SIMPLEQ_INIT(&chan->outgoing_queue); tor_free(chan); } /** * Free a channel listener and skip the state/reigstration asserts; this * internal-use-only function should be called only from channel_free_all() * when shutting down the Tor process. */ static void channel_listener_force_free(channel_listener_t *chan_l) { tor_assert(chan_l); log_debug(LD_CHANNEL, "Force-freeing channel_listener_t " U64_FORMAT " at %p", U64_PRINTF_ARG(chan_l->global_identifier), chan_l); /* Call a free method if there is one */ if (chan_l->free) chan_l->free(chan_l); /* * The incoming list just gets emptied and freed; we request close on * any channels we find there, but since we got called while shutting * down they will get deregistered and freed elsewhere anyway. */ if (chan_l->incoming_list) { SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list, channel_t *, qchan) { channel_mark_for_close(qchan); } SMARTLIST_FOREACH_END(qchan); smartlist_free(chan_l->incoming_list); chan_l->incoming_list = NULL; } tor_free(chan_l); } /** * Return the current registered listener for a channel listener * * This function returns a function pointer to the current registered * handler for new incoming channels on a channel listener. */ channel_listener_fn_ptr channel_listener_get_listener_fn(channel_listener_t *chan_l) { tor_assert(chan_l); if (chan_l->state == CHANNEL_LISTENER_STATE_LISTENING) return chan_l->listener; return NULL; } /** * Set the listener for a channel listener * * This function sets the handler for new incoming channels on a channel * listener. */ void channel_listener_set_listener_fn(channel_listener_t *chan_l, channel_listener_fn_ptr listener) { tor_assert(chan_l); tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_LISTENING); log_debug(LD_CHANNEL, "Setting listener callback for channel listener %p " "(global ID " U64_FORMAT ") to %p", chan_l, U64_PRINTF_ARG(chan_l->global_identifier), listener); chan_l->listener = listener; if (chan_l->listener) channel_listener_process_incoming(chan_l); } /** * Return the fixed-length cell handler for a channel * * This function gets the handler for incoming fixed-length cells installed * on a channel. */ channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan) { tor_assert(chan); if (chan->state == CHANNEL_STATE_OPENING || chan->state == CHANNEL_STATE_OPEN || chan->state == CHANNEL_STATE_MAINT) return chan->cell_handler; return NULL; } /** * Return the variable-length cell handler for a channel * * This function gets the handler for incoming variable-length cells * installed on a channel. */ channel_var_cell_handler_fn_ptr channel_get_var_cell_handler(channel_t *chan) { tor_assert(chan); if (chan->state == CHANNEL_STATE_OPENING || chan->state == CHANNEL_STATE_OPEN || chan->state == CHANNEL_STATE_MAINT) return chan->var_cell_handler; return NULL; } /** * Set both cell handlers for a channel * * This function sets both the fixed-length and variable length cell handlers * for a channel and processes any incoming cells that had been blocked in the * queue because none were available. */ void channel_set_cell_handlers(channel_t *chan, channel_cell_handler_fn_ptr cell_handler, channel_var_cell_handler_fn_ptr var_cell_handler) { int try_again = 0; tor_assert(chan); tor_assert(chan->state == CHANNEL_STATE_OPENING || chan->state == CHANNEL_STATE_OPEN || chan->state == CHANNEL_STATE_MAINT); log_debug(LD_CHANNEL, "Setting cell_handler callback for channel %p to %p", chan, cell_handler); log_debug(LD_CHANNEL, "Setting var_cell_handler callback for channel %p to %p", chan, var_cell_handler); /* Should we try the queue? */ if (cell_handler && cell_handler != chan->cell_handler) try_again = 1; if (var_cell_handler && var_cell_handler != chan->var_cell_handler) try_again = 1; /* Change them */ chan->cell_handler = cell_handler; chan->var_cell_handler = var_cell_handler; /* Re-run the queue if we have one and there's any reason to */ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue) && try_again && (chan->cell_handler || chan->var_cell_handler)) channel_process_cells(chan); } /* * On closing channels * * There are three functions that close channels, for use in * different circumstances: * * - Use channel_mark_for_close() for most cases * - Use channel_close_from_lower_layer() if you are connection_or.c * and the other end closes the underlying connection. * - Use channel_close_for_error() if you are connection_or.c and * some sort of error has occurred. */ /** * Mark a channel for closure * * This function tries to close a channel_t; it will go into the CLOSING * state, and eventually the lower layer should put it into the CLOSED or * ERROR state. Then, channel_run_cleanup() will eventually free it. */ void channel_mark_for_close(channel_t *chan) { tor_assert(chan != NULL); tor_assert(chan->close != NULL); /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ if (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR) return; log_debug(LD_CHANNEL, "Closing channel %p (global ID " U64_FORMAT ") " "by request", chan, U64_PRINTF_ARG(chan->global_identifier)); /* Note closing by request from above */ chan->reason_for_closing = CHANNEL_CLOSE_REQUESTED; /* Change state to CLOSING */ channel_change_state(chan, CHANNEL_STATE_CLOSING); /* Tell the lower layer */ chan->close(chan); /* * It's up to the lower layer to change state to CLOSED or ERROR when we're * ready; we'll try to free channels that are in the finished list from * channel_run_cleanup(). The lower layer should do this by calling * channel_closed(). */ } /** * Mark a channel listener for closure * * This function tries to close a channel_listener_t; it will go into the * CLOSING state, and eventually the lower layer should put it into the CLOSED * or ERROR state. Then, channel_run_cleanup() will eventually free it. */ void channel_listener_mark_for_close(channel_listener_t *chan_l) { tor_assert(chan_l != NULL); tor_assert(chan_l->close != NULL); /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; log_debug(LD_CHANNEL, "Closing channel listener %p (global ID " U64_FORMAT ") " "by request", chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); /* Note closing by request from above */ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_REQUESTED; /* Change state to CLOSING */ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); /* Tell the lower layer */ chan_l->close(chan_l); /* * It's up to the lower layer to change state to CLOSED or ERROR when we're * ready; we'll try to free channels that are in the finished list from * channel_run_cleanup(). The lower layer should do this by calling * channel_listener_closed(). */ } /** * Close a channel from the lower layer * * Notify the channel code that the channel is being closed due to a non-error * condition in the lower layer. This does not call the close() method, since * the lower layer already knows. */ void channel_close_from_lower_layer(channel_t *chan) { tor_assert(chan != NULL); /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ if (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR) return; log_debug(LD_CHANNEL, "Closing channel %p (global ID " U64_FORMAT ") " "due to lower-layer event", chan, U64_PRINTF_ARG(chan->global_identifier)); /* Note closing by event from below */ chan->reason_for_closing = CHANNEL_CLOSE_FROM_BELOW; /* Change state to CLOSING */ channel_change_state(chan, CHANNEL_STATE_CLOSING); } /** * Close a channel listener from the lower layer * * Notify the channel code that the channel listener is being closed due to a * non-error condition in the lower layer. This does not call the close() * method, since the lower layer already knows. */ void channel_listener_close_from_lower_layer(channel_listener_t *chan_l) { tor_assert(chan_l != NULL); /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; log_debug(LD_CHANNEL, "Closing channel listener %p (global ID " U64_FORMAT ") " "due to lower-layer event", chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); /* Note closing by event from below */ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FROM_BELOW; /* Change state to CLOSING */ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); } /** * Notify that the channel is being closed due to an error condition * * This function is called by the lower layer implementing the transport * when a channel must be closed due to an error condition. This does not * call the channel's close method, since the lower layer already knows. */ void channel_close_for_error(channel_t *chan) { tor_assert(chan != NULL); /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ if (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR) return; log_debug(LD_CHANNEL, "Closing channel %p due to lower-layer error", chan); /* Note closing by event from below */ chan->reason_for_closing = CHANNEL_CLOSE_FOR_ERROR; /* Change state to CLOSING */ channel_change_state(chan, CHANNEL_STATE_CLOSING); } /** * Notify that the channel listener is being closed due to an error condition * * This function is called by the lower layer implementing the transport * when a channel listener must be closed due to an error condition. This * does not call the channel listener's close method, since the lower layer * already knows. */ void channel_listener_close_for_error(channel_listener_t *chan_l) { tor_assert(chan_l != NULL); /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; log_debug(LD_CHANNEL, "Closing channel listener %p (global ID " U64_FORMAT ") " "due to lower-layer error", chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); /* Note closing by event from below */ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FOR_ERROR; /* Change state to CLOSING */ channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); } /** * Notify that the lower layer is finished closing the channel * * This function should be called by the lower layer when a channel * is finished closing and it should be regarded as inactive and * freed by the channel code. */ void channel_closed(channel_t *chan) { tor_assert(chan); tor_assert(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); /* No-op if already inactive */ if (chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR) return; /* Inform any pending (not attached) circs that they should * give up. */ if (! chan->has_been_open) circuit_n_chan_done(chan, 0); /* Now close all the attached circuits on it. */ circuit_unlink_all_from_channel(chan, END_CIRC_REASON_CHANNEL_CLOSED); if (chan->reason_for_closing != CHANNEL_CLOSE_FOR_ERROR) { channel_change_state(chan, CHANNEL_STATE_CLOSED); } else { channel_change_state(chan, CHANNEL_STATE_ERROR); } } /** * Notify that the lower layer is finished closing the channel listener * * This function should be called by the lower layer when a channel listener * is finished closing and it should be regarded as inactive and * freed by the channel code. */ void channel_listener_closed(channel_listener_t *chan_l) { tor_assert(chan_l); tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR); /* No-op if already inactive */ if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; if (chan_l->reason_for_closing != CHANNEL_LISTENER_CLOSE_FOR_ERROR) { channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED); } else { channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_ERROR); } } /** * Clear the identity_digest of a channel * * This function clears the identity digest of the remote endpoint for a * channel; this is intended for use by the lower layer. */ void channel_clear_identity_digest(channel_t *chan) { int state_not_in_map; tor_assert(chan); log_debug(LD_CHANNEL, "Clearing remote endpoint digest on channel %p with " "global ID " U64_FORMAT, chan, U64_PRINTF_ARG(chan->global_identifier)); state_not_in_map = (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); if (!state_not_in_map && chan->registered && !tor_digest_is_zero(chan->identity_digest)) /* if it's registered get it out of the digest map */ channel_remove_from_digest_map(chan); memset(chan->identity_digest, 0, sizeof(chan->identity_digest)); } /** * Set the identity_digest of a channel * * This function sets the identity digest of the remote endpoint for a * channel; this is intended for use by the lower layer. */ void channel_set_identity_digest(channel_t *chan, const char *identity_digest) { int was_in_digest_map, should_be_in_digest_map, state_not_in_map; tor_assert(chan); log_debug(LD_CHANNEL, "Setting remote endpoint digest on channel %p with " "global ID " U64_FORMAT " to digest %s", chan, U64_PRINTF_ARG(chan->global_identifier), identity_digest ? hex_str(identity_digest, DIGEST_LEN) : "(null)"); state_not_in_map = (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); was_in_digest_map = !state_not_in_map && chan->registered && !tor_digest_is_zero(chan->identity_digest); should_be_in_digest_map = !state_not_in_map && chan->registered && (identity_digest && !tor_digest_is_zero(identity_digest)); if (was_in_digest_map) /* We should always remove it; we'll add it back if we're writing * in a new digest. */ channel_remove_from_digest_map(chan); if (identity_digest) { memcpy(chan->identity_digest, identity_digest, sizeof(chan->identity_digest)); } else { memset(chan->identity_digest, 0, sizeof(chan->identity_digest)); } /* Put it in the digest map if we should */ if (should_be_in_digest_map) channel_add_to_digest_map(chan); } /** * Clear the remote end metadata (identity_digest/nickname) of a channel * * This function clears all the remote end info from a channel; this is * intended for use by the lower layer. */ void channel_clear_remote_end(channel_t *chan) { int state_not_in_map; tor_assert(chan); log_debug(LD_CHANNEL, "Clearing remote endpoint identity on channel %p with " "global ID " U64_FORMAT, chan, U64_PRINTF_ARG(chan->global_identifier)); state_not_in_map = (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); if (!state_not_in_map && chan->registered && !tor_digest_is_zero(chan->identity_digest)) /* if it's registered get it out of the digest map */ channel_remove_from_digest_map(chan); memset(chan->identity_digest, 0, sizeof(chan->identity_digest)); tor_free(chan->nickname); } /** * Set the remote end metadata (identity_digest/nickname) of a channel * * This function sets new remote end info on a channel; this is intended * for use by the lower layer. */ void channel_set_remote_end(channel_t *chan, const char *identity_digest, const char *nickname) { int was_in_digest_map, should_be_in_digest_map, state_not_in_map; tor_assert(chan); log_debug(LD_CHANNEL, "Setting remote endpoint identity on channel %p with " "global ID " U64_FORMAT " to nickname %s, digest %s", chan, U64_PRINTF_ARG(chan->global_identifier), nickname ? nickname : "(null)", identity_digest ? hex_str(identity_digest, DIGEST_LEN) : "(null)"); state_not_in_map = (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR); was_in_digest_map = !state_not_in_map && chan->registered && !tor_digest_is_zero(chan->identity_digest); should_be_in_digest_map = !state_not_in_map && chan->registered && (identity_digest && !tor_digest_is_zero(identity_digest)); if (was_in_digest_map) /* We should always remove it; we'll add it back if we're writing * in a new digest. */ channel_remove_from_digest_map(chan); if (identity_digest) { memcpy(chan->identity_digest, identity_digest, sizeof(chan->identity_digest)); } else { memset(chan->identity_digest, 0, sizeof(chan->identity_digest)); } tor_free(chan->nickname); if (nickname) chan->nickname = tor_strdup(nickname); /* Put it in the digest map if we should */ if (should_be_in_digest_map) channel_add_to_digest_map(chan); } /** * Duplicate a cell queue entry; this is a shallow copy intended for use * in channel_write_cell_queue_entry(). */ static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q) { cell_queue_entry_t *rv = NULL; tor_assert(q); rv = tor_malloc(sizeof(*rv)); memcpy(rv, q, sizeof(*rv)); return rv; } /** * Free a cell_queue_entry_t; the handed_off parameter indicates whether * the contents were passed to the lower layer (it is responsible for * them) or not (we should free). */ static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off) { if (!q) return; if (!handed_off) { /* * If we handed it off, the recipient becomes responsible (or * with packed cells the channel_t subclass calls packed_cell * free after writing out its contents; see, e.g., * channel_tls_write_packed_cell_method(). Otherwise, we have * to take care of it here if possible. */ switch (q->type) { case CELL_QUEUE_FIXED: if (q->u.fixed.cell) { /* * There doesn't seem to be a cell_free() function anywhere in the * pre-channel code; just use tor_free() */ tor_free(q->u.fixed.cell); } break; case CELL_QUEUE_PACKED: if (q->u.packed.packed_cell) { packed_cell_free(q->u.packed.packed_cell); } break; case CELL_QUEUE_VAR: if (q->u.var.var_cell) { /* * This one's in connection_or.c; it'd be nice to figure out the * whole flow of cells from one end to the other and factor the * cell memory management functions like this out of the specific * TLS lower layer. */ var_cell_free(q->u.var.var_cell); } break; default: /* * Nothing we can do if we don't know the type; this will * have been warned about elsewhere. */ break; } } tor_free(q); } /** * Check whether a cell queue entry is padding; this is a helper function * for channel_write_cell_queue_entry() */ static int cell_queue_entry_is_padding(cell_queue_entry_t *q) { tor_assert(q); if (q->type == CELL_QUEUE_FIXED) { if (q->u.fixed.cell) { if (q->u.fixed.cell->command == CELL_PADDING || q->u.fixed.cell->command == CELL_VPADDING) { return 1; } } } else if (q->type == CELL_QUEUE_VAR) { if (q->u.var.var_cell) { if (q->u.var.var_cell->command == CELL_PADDING || q->u.var.var_cell->command == CELL_VPADDING) { return 1; } } } return 0; } /** * Allocate a new cell queue entry for a fixed-size cell */ static cell_queue_entry_t * cell_queue_entry_new_fixed(cell_t *cell) { cell_queue_entry_t *q = NULL; tor_assert(cell); q = tor_malloc(sizeof(*q)); q->type = CELL_QUEUE_FIXED; q->u.fixed.cell = cell; return q; } /** * Allocate a new cell queue entry for a variable-size cell */ static cell_queue_entry_t * cell_queue_entry_new_var(var_cell_t *var_cell) { cell_queue_entry_t *q = NULL; tor_assert(var_cell); q = tor_malloc(sizeof(*q)); q->type = CELL_QUEUE_VAR; q->u.var.var_cell = var_cell; return q; } /** * Write to a channel based on a cell_queue_entry_t * * Given a cell_queue_entry_t filled out by the caller, try to send the cell * and queue it if we can't. */ static void channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) { int result = 0, sent = 0; cell_queue_entry_t *tmp = NULL; tor_assert(chan); tor_assert(q); /* Assert that the state makes sense for a cell write */ tor_assert(chan->state == CHANNEL_STATE_OPENING || chan->state == CHANNEL_STATE_OPEN || chan->state == CHANNEL_STATE_MAINT); /* Increment the timestamp unless it's padding */ if (!cell_queue_entry_is_padding(q)) { chan->timestamp_last_added_nonpadding = approx_time(); } /* Can we send it right out? If so, try */ if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) && chan->state == CHANNEL_STATE_OPEN) { /* Pick the right write function for this cell type and save the result */ switch (q->type) { case CELL_QUEUE_FIXED: tor_assert(chan->write_cell); tor_assert(q->u.fixed.cell); result = chan->write_cell(chan, q->u.fixed.cell); break; case CELL_QUEUE_PACKED: tor_assert(chan->write_packed_cell); tor_assert(q->u.packed.packed_cell); result = chan->write_packed_cell(chan, q->u.packed.packed_cell); break; case CELL_QUEUE_VAR: tor_assert(chan->write_var_cell); tor_assert(q->u.var.var_cell); result = chan->write_var_cell(chan, q->u.var.var_cell); break; default: tor_assert(1); } /* Check if we got it out */ if (result > 0) { sent = 1; /* Timestamp for transmission */ channel_timestamp_xmit(chan); /* If we're here the queue is empty, so it's drained too */ channel_timestamp_drained(chan); /* Update the counter */ ++(chan->n_cells_xmitted); } } if (!sent) { /* Not sent, queue it */ /* * We have to copy the queue entry passed in, since the caller probably * used the stack. */ tmp = cell_queue_entry_dup(q); TOR_SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next); /* Try to process the queue? */ if (chan->state == CHANNEL_STATE_OPEN) channel_flush_cells(chan); } } /** * Write a cell to a channel * * Write a fixed-length cell to a channel using the write_cell() method. * This is equivalent to the pre-channels connection_or_write_cell_to_buf(); * it is called by the transport-independent code to deliver a cell to a * channel for transmission. */ void channel_write_cell(channel_t *chan, cell_t *cell) { cell_queue_entry_t q; tor_assert(chan); tor_assert(cell); if (chan->state == CHANNEL_STATE_CLOSING) { log_debug(LD_CHANNEL, "Discarding cell_t %p on closing channel %p with " "global ID "U64_FORMAT, cell, chan, U64_PRINTF_ARG(chan->global_identifier)); tor_free(cell); return; } log_debug(LD_CHANNEL, "Writing cell_t %p to channel %p with global ID " U64_FORMAT, cell, chan, U64_PRINTF_ARG(chan->global_identifier)); q.type = CELL_QUEUE_FIXED; q.u.fixed.cell = cell; channel_write_cell_queue_entry(chan, &q); } /** * Write a packed cell to a channel * * Write a packed cell to a channel using the write_cell() method. This is * called by the transport-independent code to deliver a packed cell to a * channel for transmission. */ void channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell) { cell_queue_entry_t q; tor_assert(chan); tor_assert(packed_cell); if (chan->state == CHANNEL_STATE_CLOSING) { log_debug(LD_CHANNEL, "Discarding packed_cell_t %p on closing channel %p " "with global ID "U64_FORMAT, packed_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); packed_cell_free(packed_cell); return; } log_debug(LD_CHANNEL, "Writing packed_cell_t %p to channel %p with global ID " U64_FORMAT, packed_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); q.type = CELL_QUEUE_PACKED; q.u.packed.packed_cell = packed_cell; channel_write_cell_queue_entry(chan, &q); } /** * Write a variable-length cell to a channel * * Write a variable-length cell to a channel using the write_cell() method. * This is equivalent to the pre-channels * connection_or_write_var_cell_to_buf(); it's called by the transport- * independent code to deliver a var_cell to a channel for transmission. */ void channel_write_var_cell(channel_t *chan, var_cell_t *var_cell) { cell_queue_entry_t q; tor_assert(chan); tor_assert(var_cell); if (chan->state == CHANNEL_STATE_CLOSING) { log_debug(LD_CHANNEL, "Discarding var_cell_t %p on closing channel %p " "with global ID "U64_FORMAT, var_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); var_cell_free(var_cell); return; } log_debug(LD_CHANNEL, "Writing var_cell_t %p to channel %p with global ID " U64_FORMAT, var_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); q.type = CELL_QUEUE_VAR; q.u.var.var_cell = var_cell; channel_write_cell_queue_entry(chan, &q); } /** * Change channel state * * This internal and subclass use only function is used to change channel * state, performing all transition validity checks and whatever actions * are appropriate to the state transition in question. */ void channel_change_state(channel_t *chan, channel_state_t to_state) { channel_state_t from_state; unsigned char was_active, is_active; unsigned char was_in_id_map, is_in_id_map; tor_assert(chan); from_state = chan->state; tor_assert(channel_state_is_valid(from_state)); tor_assert(channel_state_is_valid(to_state)); tor_assert(channel_state_can_transition(chan->state, to_state)); /* Check for no-op transitions */ if (from_state == to_state) { log_debug(LD_CHANNEL, "Got no-op transition from \"%s\" to itself on channel %p" "(global ID " U64_FORMAT ")", channel_state_to_string(to_state), chan, U64_PRINTF_ARG(chan->global_identifier)); return; } /* If we're going to a closing or closed state, we must have a reason set */ if (to_state == CHANNEL_STATE_CLOSING || to_state == CHANNEL_STATE_CLOSED || to_state == CHANNEL_STATE_ERROR) { tor_assert(chan->reason_for_closing != CHANNEL_NOT_CLOSING); } /* * We need to maintain the queues here for some transitions: * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT) * we may have a backlog of cells to transmit, so drain the queues in * that case, and when going to CHANNEL_STATE_CLOSED the subclass * should have made sure to finish sending things (or gone to * CHANNEL_STATE_ERROR if not possible), so we assert for that here. */ log_debug(LD_CHANNEL, "Changing state of channel %p (global ID " U64_FORMAT ") from \"%s\" to \"%s\"", chan, U64_PRINTF_ARG(chan->global_identifier), channel_state_to_string(chan->state), channel_state_to_string(to_state)); chan->state = to_state; /* Need to add to the right lists if the channel is registered */ if (chan->registered) { was_active = !(from_state == CHANNEL_STATE_CLOSED || from_state == CHANNEL_STATE_ERROR); is_active = !(to_state == CHANNEL_STATE_CLOSED || to_state == CHANNEL_STATE_ERROR); /* Need to take off active list and put on finished list? */ if (was_active && !is_active) { if (active_channels) smartlist_remove(active_channels, chan); if (!finished_channels) finished_channels = smartlist_new(); smartlist_add(finished_channels, chan); } /* Need to put on active list? */ else if (!was_active && is_active) { if (finished_channels) smartlist_remove(finished_channels, chan); if (!active_channels) active_channels = smartlist_new(); smartlist_add(active_channels, chan); } if (!tor_digest_is_zero(chan->identity_digest)) { /* Now we need to handle the identity map */ was_in_id_map = !(from_state == CHANNEL_STATE_CLOSING || from_state == CHANNEL_STATE_CLOSED || from_state == CHANNEL_STATE_ERROR); is_in_id_map = !(to_state == CHANNEL_STATE_CLOSING || to_state == CHANNEL_STATE_CLOSED || to_state == CHANNEL_STATE_ERROR); if (!was_in_id_map && is_in_id_map) channel_add_to_digest_map(chan); else if (was_in_id_map && !is_in_id_map) channel_remove_from_digest_map(chan); } } /* Tell circuits if we opened and stuff */ if (to_state == CHANNEL_STATE_OPEN) { channel_do_open_actions(chan); chan->has_been_open = 1; /* Check for queued cells to process */ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) channel_process_cells(chan); if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) channel_flush_cells(chan); } else if (to_state == CHANNEL_STATE_CLOSED || to_state == CHANNEL_STATE_ERROR) { /* Assert that all queues are empty */ tor_assert(TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)); tor_assert(TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)); } } /** * Change channel listener state * * This internal and subclass use only function is used to change channel * listener state, performing all transition validity checks and whatever * actions are appropriate to the state transition in question. */ void channel_listener_change_state(channel_listener_t *chan_l, channel_listener_state_t to_state) { channel_listener_state_t from_state; unsigned char was_active, is_active; tor_assert(chan_l); from_state = chan_l->state; tor_assert(channel_listener_state_is_valid(from_state)); tor_assert(channel_listener_state_is_valid(to_state)); tor_assert(channel_listener_state_can_transition(chan_l->state, to_state)); /* Check for no-op transitions */ if (from_state == to_state) { log_debug(LD_CHANNEL, "Got no-op transition from \"%s\" to itself on channel " "listener %p (global ID " U64_FORMAT ")", channel_listener_state_to_string(to_state), chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); return; } /* If we're going to a closing or closed state, we must have a reason set */ if (to_state == CHANNEL_LISTENER_STATE_CLOSING || to_state == CHANNEL_LISTENER_STATE_CLOSED || to_state == CHANNEL_LISTENER_STATE_ERROR) { tor_assert(chan_l->reason_for_closing != CHANNEL_LISTENER_NOT_CLOSING); } /* * We need to maintain the queues here for some transitions: * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT) * we may have a backlog of cells to transmit, so drain the queues in * that case, and when going to CHANNEL_STATE_CLOSED the subclass * should have made sure to finish sending things (or gone to * CHANNEL_STATE_ERROR if not possible), so we assert for that here. */ log_debug(LD_CHANNEL, "Changing state of channel listener %p (global ID " U64_FORMAT "from \"%s\" to \"%s\"", chan_l, U64_PRINTF_ARG(chan_l->global_identifier), channel_listener_state_to_string(chan_l->state), channel_listener_state_to_string(to_state)); chan_l->state = to_state; /* Need to add to the right lists if the channel listener is registered */ if (chan_l->registered) { was_active = !(from_state == CHANNEL_LISTENER_STATE_CLOSED || from_state == CHANNEL_LISTENER_STATE_ERROR); is_active = !(to_state == CHANNEL_LISTENER_STATE_CLOSED || to_state == CHANNEL_LISTENER_STATE_ERROR); /* Need to take off active list and put on finished list? */ if (was_active && !is_active) { if (active_listeners) smartlist_remove(active_listeners, chan_l); if (!finished_listeners) finished_listeners = smartlist_new(); smartlist_add(finished_listeners, chan_l); } /* Need to put on active list? */ else if (!was_active && is_active) { if (finished_listeners) smartlist_remove(finished_listeners, chan_l); if (!active_listeners) active_listeners = smartlist_new(); smartlist_add(active_listeners, chan_l); } } if (to_state == CHANNEL_LISTENER_STATE_CLOSED || to_state == CHANNEL_LISTENER_STATE_ERROR) { /* Assert that the queue is empty */ tor_assert(!(chan_l->incoming_list) || smartlist_len(chan_l->incoming_list) == 0); } } /** * Try to flush cells to the lower layer * * this is called by the lower layer to indicate that it wants more cells; * it will try to write up to num_cells cells from the channel's cell queue or * from circuits active on that channel, or as many as it has available if * num_cells == -1. */ #define MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED 256 ssize_t channel_flush_some_cells(channel_t *chan, ssize_t num_cells) { unsigned int unlimited = 0; ssize_t flushed = 0; int num_cells_from_circs, clamped_num_cells; tor_assert(chan); if (num_cells < 0) unlimited = 1; if (!unlimited && num_cells <= flushed) goto done; /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */ if (chan->state == CHANNEL_STATE_OPEN) { /* Try to flush as much as we can that's already queued */ flushed += channel_flush_some_cells_from_outgoing_queue(chan, (unlimited ? -1 : num_cells - flushed)); if (!unlimited && num_cells <= flushed) goto done; if (circuitmux_num_cells(chan->cmux) > 0) { /* Calculate number of cells, including clamp */ if (unlimited) { clamped_num_cells = MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED; } else { if (num_cells - flushed > MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED) { clamped_num_cells = MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED; } else { clamped_num_cells = (int)(num_cells - flushed); } } /* Try to get more cells from any active circuits */ num_cells_from_circs = channel_flush_from_first_active_circuit( chan, clamped_num_cells); /* If it claims we got some, process the queue again */ if (num_cells_from_circs > 0) { flushed += channel_flush_some_cells_from_outgoing_queue(chan, (unlimited ? -1 : num_cells - flushed)); } } } done: return flushed; } /** * Flush cells from just the channel's outgoing cell queue * * This gets called from channel_flush_some_cells() above to flush cells * just from the queue without trying for active_circuits. */ static ssize_t channel_flush_some_cells_from_outgoing_queue(channel_t *chan, ssize_t num_cells) { unsigned int unlimited = 0; ssize_t flushed = 0; cell_queue_entry_t *q = NULL; tor_assert(chan); tor_assert(chan->write_cell); tor_assert(chan->write_packed_cell); tor_assert(chan->write_var_cell); if (num_cells < 0) unlimited = 1; if (!unlimited && num_cells <= flushed) return 0; /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */ if (chan->state == CHANNEL_STATE_OPEN) { while ((unlimited || num_cells > flushed) && NULL != (q = TOR_SIMPLEQ_FIRST(&chan->outgoing_queue))) { if (1) { /* * Okay, we have a good queue entry, try to give it to the lower * layer. */ switch (q->type) { case CELL_QUEUE_FIXED: if (q->u.fixed.cell) { if (chan->write_cell(chan, q->u.fixed.cell)) { ++flushed; channel_timestamp_xmit(chan); ++(chan->n_cells_xmitted); cell_queue_entry_free(q, 1); q = NULL; } /* Else couldn't write it; leave it on the queue */ } else { /* This shouldn't happen */ log_info(LD_CHANNEL, "Saw broken cell queue entry of type CELL_QUEUE_FIXED " "with no cell on channel %p " "(global ID " U64_FORMAT ").", chan, U64_PRINTF_ARG(chan->global_identifier)); /* Throw it away */ cell_queue_entry_free(q, 0); q = NULL; } break; case CELL_QUEUE_PACKED: if (q->u.packed.packed_cell) { if (chan->write_packed_cell(chan, q->u.packed.packed_cell)) { ++flushed; channel_timestamp_xmit(chan); ++(chan->n_cells_xmitted); cell_queue_entry_free(q, 1); q = NULL; } /* Else couldn't write it; leave it on the queue */ } else { /* This shouldn't happen */ log_info(LD_CHANNEL, "Saw broken cell queue entry of type CELL_QUEUE_PACKED " "with no cell on channel %p " "(global ID " U64_FORMAT ").", chan, U64_PRINTF_ARG(chan->global_identifier)); /* Throw it away */ cell_queue_entry_free(q, 0); q = NULL; } break; case CELL_QUEUE_VAR: if (q->u.var.var_cell) { if (chan->write_var_cell(chan, q->u.var.var_cell)) { ++flushed; channel_timestamp_xmit(chan); ++(chan->n_cells_xmitted); cell_queue_entry_free(q, 1); q = NULL; } /* Else couldn't write it; leave it on the queue */ } else { /* This shouldn't happen */ log_info(LD_CHANNEL, "Saw broken cell queue entry of type CELL_QUEUE_VAR " "with no cell on channel %p " "(global ID " U64_FORMAT ").", chan, U64_PRINTF_ARG(chan->global_identifier)); /* Throw it away */ cell_queue_entry_free(q, 0); q = NULL; } break; default: /* Unknown type, log and free it */ log_info(LD_CHANNEL, "Saw an unknown cell queue entry type %d on channel %p " "(global ID " U64_FORMAT "; ignoring it." " Someone should fix this.", q->type, chan, U64_PRINTF_ARG(chan->global_identifier)); cell_queue_entry_free(q, 0); q = NULL; } /* if q got NULLed out, we used it and should remove the queue entry */ if (!q) TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next); /* No cell removed from list, so we can't go on any further */ else break; } } } /* Did we drain the queue? */ if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) { channel_timestamp_drained(chan); } return flushed; } /** * Flush as many cells as we possibly can from the queue * * This tries to flush as many cells from the queue as the lower layer * will take. It just calls channel_flush_some_cells_from_outgoing_queue() * in unlimited mode. */ void channel_flush_cells(channel_t *chan) { channel_flush_some_cells_from_outgoing_queue(chan, -1); } /** * Check if any cells are available * * This gets used from the lower layer to check if any more cells are * available. */ int channel_more_to_flush(channel_t *chan) { tor_assert(chan); /* Check if we have any queued */ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) return 1; /* Check if any circuits would like to queue some */ if (circuitmux_num_cells(chan->cmux) > 0) return 1; /* Else no */ return 0; } /** * Notify the channel we're done flushing the output in the lower layer * * Connection.c will call this when we've flushed the output; there's some * dirreq-related maintenance to do. */ void channel_notify_flushed(channel_t *chan) { tor_assert(chan); if (chan->dirreq_id != 0) geoip_change_dirreq_state(chan->dirreq_id, DIRREQ_TUNNELED, DIRREQ_CHANNEL_BUFFER_FLUSHED); } /** * Process the queue of incoming channels on a listener * * Use a listener's registered callback to process as many entries in the * queue of incoming channels as possible. */ void channel_listener_process_incoming(channel_listener_t *listener) { tor_assert(listener); /* * CHANNEL_LISTENER_STATE_CLOSING permitted because we drain the queue * while closing a listener. */ tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING || listener->state == CHANNEL_LISTENER_STATE_CLOSING); tor_assert(listener->listener); log_debug(LD_CHANNEL, "Processing queue of incoming connections for channel " "listener %p (global ID " U64_FORMAT ")", listener, U64_PRINTF_ARG(listener->global_identifier)); if (!(listener->incoming_list)) return; SMARTLIST_FOREACH_BEGIN(listener->incoming_list, channel_t *, chan) { tor_assert(chan); log_debug(LD_CHANNEL, "Handling incoming channel %p (" U64_FORMAT ") " "for listener %p (" U64_FORMAT ")", chan, U64_PRINTF_ARG(chan->global_identifier), listener, U64_PRINTF_ARG(listener->global_identifier)); /* Make sure this is set correctly */ channel_mark_incoming(chan); listener->listener(listener, chan); } SMARTLIST_FOREACH_END(chan); smartlist_free(listener->incoming_list); listener->incoming_list = NULL; } /** * Take actions required when a channel becomes open * * Handle actions we should do when we know a channel is open; a lot of * this comes from the old connection_or_set_state_open() of connection_or.c. * * Because of this mechanism, future channel_t subclasses should take care * not to change a channel to from CHANNEL_STATE_OPENING to CHANNEL_STATE_OPEN * until there is positive confirmation that the network is operational. * In particular, anything UDP-based should not make this transition until a * packet is received from the other side. */ void channel_do_open_actions(channel_t *chan) { tor_addr_t remote_addr; int started_here, not_using = 0; time_t now = time(NULL); tor_assert(chan); started_here = channel_is_outgoing(chan); if (started_here) { circuit_build_times_network_is_live(&circ_times); rep_hist_note_connect_succeeded(chan->identity_digest, now); if (entry_guard_register_connect_status( chan->identity_digest, 1, 0, now) < 0) { /* Close any circuits pending on this channel. We leave it in state * 'open' though, because it didn't actually *fail* -- we just * chose not to use it. */ log_debug(LD_OR, "New entry guard was reachable, but closing this " "connection so we can retry the earlier entry guards."); circuit_n_chan_done(chan, 0); not_using = 1; } router_set_status(chan->identity_digest, 1); } else { /* only report it to the geoip module if it's not a known router */ if (!router_get_by_id_digest(chan->identity_digest)) { if (channel_get_addr_if_possible(chan, &remote_addr)) { geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &remote_addr, now); } /* Otherwise the underlying transport can't tell us this, so skip it */ } } if (!not_using) circuit_n_chan_done(chan, 1); } /** * Queue an incoming channel on a listener * * Internal and subclass use only function to queue an incoming channel from * a listener. A subclass of channel_listener_t should call this when a new * incoming channel is created. */ void channel_listener_queue_incoming(channel_listener_t *listener, channel_t *incoming) { int need_to_queue = 0; tor_assert(listener); tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING); tor_assert(incoming); log_debug(LD_CHANNEL, "Queueing incoming channel %p (global ID " U64_FORMAT ") on " "channel listener %p (global ID " U64_FORMAT ")", incoming, U64_PRINTF_ARG(incoming->global_identifier), listener, U64_PRINTF_ARG(listener->global_identifier)); /* Do we need to queue it, or can we just call the listener right away? */ if (!(listener->listener)) need_to_queue = 1; if (listener->incoming_list && (smartlist_len(listener->incoming_list) > 0)) need_to_queue = 1; /* If we need to queue and have no queue, create one */ if (need_to_queue && !(listener->incoming_list)) { listener->incoming_list = smartlist_new(); } /* Bump the counter and timestamp it */ channel_listener_timestamp_active(listener); channel_listener_timestamp_accepted(listener); ++(listener->n_accepted); /* If we don't need to queue, process it right away */ if (!need_to_queue) { tor_assert(listener->listener); listener->listener(listener, incoming); } /* * Otherwise, we need to queue; queue and then process the queue if * we can. */ else { tor_assert(listener->incoming_list); smartlist_add(listener->incoming_list, incoming); if (listener->listener) channel_listener_process_incoming(listener); } } /** * Process queued incoming cells * * Process as many queued cells as we can from the incoming * cell queue. */ void channel_process_cells(channel_t *chan) { cell_queue_entry_t *q; tor_assert(chan); tor_assert(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_MAINT || chan->state == CHANNEL_STATE_OPEN); log_debug(LD_CHANNEL, "Processing as many incoming cells as we can for channel %p", chan); /* Nothing we can do if we have no registered cell handlers */ if (!(chan->cell_handler || chan->var_cell_handler)) return; /* Nothing we can do if we have no cells */ if (TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) return; /* * Process cells until we're done or find one we have no current handler * for. */ while (NULL != (q = TOR_SIMPLEQ_FIRST(&chan->incoming_queue))) { tor_assert(q); tor_assert(q->type == CELL_QUEUE_FIXED || q->type == CELL_QUEUE_VAR); if (q->type == CELL_QUEUE_FIXED && chan->cell_handler) { /* Handle a fixed-length cell */ TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); tor_assert(q->u.fixed.cell); log_debug(LD_CHANNEL, "Processing incoming cell_t %p for channel %p (global ID " U64_FORMAT ")", q->u.fixed.cell, chan, U64_PRINTF_ARG(chan->global_identifier)); chan->cell_handler(chan, q->u.fixed.cell); tor_free(q); } else if (q->type == CELL_QUEUE_VAR && chan->var_cell_handler) { /* Handle a variable-length cell */ TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); tor_assert(q->u.var.var_cell); log_debug(LD_CHANNEL, "Processing incoming var_cell_t %p for channel %p (global ID " U64_FORMAT ")", q->u.var.var_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); chan->var_cell_handler(chan, q->u.var.var_cell); tor_free(q); } else { /* Can't handle this one */ break; } } } /** * Queue incoming cell * * This should be called by a channel_t subclass to queue an incoming fixed- * length cell for processing, and process it if possible. */ void channel_queue_cell(channel_t *chan, cell_t *cell) { int need_to_queue = 0; cell_queue_entry_t *q; tor_assert(chan); tor_assert(cell); tor_assert(chan->state == CHANNEL_STATE_OPEN); /* Do we need to queue it, or can we just call the handler right away? */ if (!(chan->cell_handler)) need_to_queue = 1; if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) need_to_queue = 1; /* Timestamp for receiving */ channel_timestamp_recv(chan); /* Update the counter */ ++(chan->n_cells_recved); /* If we don't need to queue we can just call cell_handler */ if (!need_to_queue) { tor_assert(chan->cell_handler); log_debug(LD_CHANNEL, "Directly handling incoming cell_t %p for channel %p " "(global ID " U64_FORMAT ")", cell, chan, U64_PRINTF_ARG(chan->global_identifier)); chan->cell_handler(chan, cell); } else { /* Otherwise queue it and then process the queue if possible. */ q = cell_queue_entry_new_fixed(cell); log_debug(LD_CHANNEL, "Queueing incoming cell_t %p for channel %p " "(global ID " U64_FORMAT ")", cell, chan, U64_PRINTF_ARG(chan->global_identifier)); TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); if (chan->cell_handler || chan->var_cell_handler) { channel_process_cells(chan); } } } /** * Queue incoming variable-length cell * * This should be called by a channel_t subclass to queue an incoming * variable-length cell for processing, and process it if possible. */ void channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) { int need_to_queue = 0; cell_queue_entry_t *q; tor_assert(chan); tor_assert(var_cell); tor_assert(chan->state == CHANNEL_STATE_OPEN); /* Do we need to queue it, or can we just call the handler right away? */ if (!(chan->var_cell_handler)) need_to_queue = 1; if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) need_to_queue = 1; /* Timestamp for receiving */ channel_timestamp_recv(chan); /* Update the counter */ ++(chan->n_cells_recved); /* If we don't need to queue we can just call cell_handler */ if (!need_to_queue) { tor_assert(chan->var_cell_handler); log_debug(LD_CHANNEL, "Directly handling incoming var_cell_t %p for channel %p " "(global ID " U64_FORMAT ")", var_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); chan->var_cell_handler(chan, var_cell); } else { /* Otherwise queue it and then process the queue if possible. */ q = cell_queue_entry_new_var(var_cell); log_debug(LD_CHANNEL, "Queueing incoming var_cell_t %p for channel %p " "(global ID " U64_FORMAT ")", var_cell, chan, U64_PRINTF_ARG(chan->global_identifier)); TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); if (chan->cell_handler || chan->var_cell_handler) { channel_process_cells(chan); } } } /** * Send destroy cell on a channel * * Write a destroy cell with circ ID circ_id and reason reason * onto channel chan. Don't perform range-checking on reason: * we may want to propagate reasons from other cells. */ int channel_send_destroy(circid_t circ_id, channel_t *chan, int reason) { cell_t cell; tor_assert(chan); /* Check to make sure we can send on this channel first */ if (!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR)) { memset(&cell, 0, sizeof(cell_t)); cell.circ_id = circ_id; cell.command = CELL_DESTROY; cell.payload[0] = (uint8_t) reason; log_debug(LD_OR, "Sending destroy (circID %u) on channel %p " "(global ID " U64_FORMAT ")", (unsigned)circ_id, chan, U64_PRINTF_ARG(chan->global_identifier)); channel_write_cell(chan, &cell); } else { log_warn(LD_BUG, "Someone called channel_send_destroy() for circID %u " "on a channel " U64_FORMAT " at %p in state %s (%d)", (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier), chan, channel_state_to_string(chan->state), chan->state); } return 0; } /** * Dump channel statistics to the log * * This is called from dumpstats() in main.c and spams the log with * statistics on channels. */ void channel_dumpstats(int severity) { if (all_channels && smartlist_len(all_channels) > 0) { tor_log(severity, LD_GENERAL, "Dumping statistics about %d channels:", smartlist_len(all_channels)); tor_log(severity, LD_GENERAL, "%d are active, and %d are done and waiting for cleanup", (active_channels != NULL) ? smartlist_len(active_channels) : 0, (finished_channels != NULL) ? smartlist_len(finished_channels) : 0); SMARTLIST_FOREACH(all_channels, channel_t *, chan, channel_dump_statistics(chan, severity)); tor_log(severity, LD_GENERAL, "Done spamming about channels now"); } else { tor_log(severity, LD_GENERAL, "No channels to dump"); } } /** * Dump channel listener statistics to the log * * This is called from dumpstats() in main.c and spams the log with * statistics on channel listeners. */ void channel_listener_dumpstats(int severity) { if (all_listeners && smartlist_len(all_listeners) > 0) { tor_log(severity, LD_GENERAL, "Dumping statistics about %d channel listeners:", smartlist_len(all_listeners)); tor_log(severity, LD_GENERAL, "%d are active and %d are done and waiting for cleanup", (active_listeners != NULL) ? smartlist_len(active_listeners) : 0, (finished_listeners != NULL) ? smartlist_len(finished_listeners) : 0); SMARTLIST_FOREACH(all_listeners, channel_listener_t *, chan_l, channel_listener_dump_statistics(chan_l, severity)); tor_log(severity, LD_GENERAL, "Done spamming about channel listeners now"); } else { tor_log(severity, LD_GENERAL, "No channel listeners to dump"); } } /** * Set the cmux policy on all active channels */ void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol) { if (!active_channels) return; SMARTLIST_FOREACH_BEGIN(active_channels, channel_t *, curr) { if (curr->cmux) { circuitmux_set_policy(curr->cmux, pol); } } SMARTLIST_FOREACH_END(curr); } /** * Clean up channels * * This gets called periodically from run_scheduled_events() in main.c; * it cleans up after closed channels. */ void channel_run_cleanup(void) { channel_t *tmp = NULL; /* Check if we need to do anything */ if (!finished_channels || smartlist_len(finished_channels) == 0) return; /* Iterate through finished_channels and get rid of them */ SMARTLIST_FOREACH_BEGIN(finished_channels, channel_t *, curr) { tmp = curr; /* Remove it from the list */ SMARTLIST_DEL_CURRENT(finished_channels, curr); /* Also unregister it */ channel_unregister(tmp); /* ... and free it */ channel_free(tmp); } SMARTLIST_FOREACH_END(curr); } /** * Clean up channel listeners * * This gets called periodically from run_scheduled_events() in main.c; * it cleans up after closed channel listeners. */ void channel_listener_run_cleanup(void) { channel_listener_t *tmp = NULL; /* Check if we need to do anything */ if (!finished_listeners || smartlist_len(finished_listeners) == 0) return; /* Iterate through finished_channels and get rid of them */ SMARTLIST_FOREACH_BEGIN(finished_listeners, channel_listener_t *, curr) { tmp = curr; /* Remove it from the list */ SMARTLIST_DEL_CURRENT(finished_listeners, curr); /* Also unregister it */ channel_listener_unregister(tmp); /* ... and free it */ channel_listener_free(tmp); } SMARTLIST_FOREACH_END(curr); } /** * Free a list of channels for channel_free_all() */ static void channel_free_list(smartlist_t *channels, int mark_for_close) { if (!channels) return; SMARTLIST_FOREACH_BEGIN(channels, channel_t *, curr) { /* Deregister and free it */ tor_assert(curr); log_debug(LD_CHANNEL, "Cleaning up channel %p (global ID " U64_FORMAT ") " "in state %s (%d)", curr, U64_PRINTF_ARG(curr->global_identifier), channel_state_to_string(curr->state), curr->state); /* Detach circuits early so they can find the channel */ if (curr->cmux) { circuitmux_detach_all_circuits(curr->cmux); } channel_unregister(curr); if (mark_for_close) { if (!(curr->state == CHANNEL_STATE_CLOSING || curr->state == CHANNEL_STATE_CLOSED || curr->state == CHANNEL_STATE_ERROR)) { channel_mark_for_close(curr); } channel_force_free(curr); } else channel_free(curr); } SMARTLIST_FOREACH_END(curr); } /** * Free a list of channel listeners for channel_free_all() */ static void channel_listener_free_list(smartlist_t *listeners, int mark_for_close) { if (!listeners) return; SMARTLIST_FOREACH_BEGIN(listeners, channel_listener_t *, curr) { /* Deregister and free it */ tor_assert(curr); log_debug(LD_CHANNEL, "Cleaning up channel listener %p (global ID " U64_FORMAT ") " "in state %s (%d)", curr, U64_PRINTF_ARG(curr->global_identifier), channel_listener_state_to_string(curr->state), curr->state); channel_listener_unregister(curr); if (mark_for_close) { if (!(curr->state == CHANNEL_LISTENER_STATE_CLOSING || curr->state == CHANNEL_LISTENER_STATE_CLOSED || curr->state == CHANNEL_LISTENER_STATE_ERROR)) { channel_listener_mark_for_close(curr); } channel_listener_force_free(curr); } else channel_listener_free(curr); } SMARTLIST_FOREACH_END(curr); } /** * Close all channels and free everything * * This gets called from tor_free_all() in main.c to clean up on exit. * It will close all registered channels and free associated storage, * then free the all_channels, active_channels, listening_channels and * finished_channels lists and also channel_identity_map. */ void channel_free_all(void) { log_debug(LD_CHANNEL, "Shutting down channels..."); /* First, let's go for finished channels */ if (finished_channels) { channel_free_list(finished_channels, 0); smartlist_free(finished_channels); finished_channels = NULL; } /* Now the finished listeners */ if (finished_listeners) { channel_listener_free_list(finished_listeners, 0); smartlist_free(finished_listeners); finished_listeners = NULL; } /* Now all active channels */ if (active_channels) { channel_free_list(active_channels, 1); smartlist_free(active_channels); active_channels = NULL; } /* Now all active listeners */ if (active_listeners) { channel_listener_free_list(active_listeners, 1); smartlist_free(active_listeners); active_listeners = NULL; } /* Now all channels, in case any are left over */ if (all_channels) { channel_free_list(all_channels, 1); smartlist_free(all_channels); all_channels = NULL; } /* Now all listeners, in case any are left over */ if (all_listeners) { channel_listener_free_list(all_listeners, 1); smartlist_free(all_listeners); all_listeners = NULL; } /* Now free channel_identity_map */ log_debug(LD_CHANNEL, "Freeing channel_identity_map"); /* Geez, anything still left over just won't die ... let it leak then */ HT_CLEAR(channel_idmap, &channel_identity_map); log_debug(LD_CHANNEL, "Done cleaning up after channels"); } /** * Connect to a given addr/port/digest * * This sets up a new outgoing channel; in the future if multiple * channel_t subclasses are available, this is where the selection policy * should go. It may also be desirable to fold port into tor_addr_t * or make a new type including a tor_addr_t and port, so we have a * single abstract object encapsulating all the protocol details of * how to contact an OR. */ channel_t * channel_connect(const tor_addr_t *addr, uint16_t port, const char *id_digest) { return channel_tls_connect(addr, port, id_digest); } /** * Decide which of two channels to prefer for extending a circuit * * This function is called while extending a circuit and returns true iff * a is 'better' than b. The most important criterion here is that a * canonical channel is always better than a non-canonical one, but the * number of circuits and the age are used as tie-breakers. * * This is based on the former connection_or_is_better() of connection_or.c */ int channel_is_better(time_t now, channel_t *a, channel_t *b, int forgive_new_connections) { int a_grace, b_grace; int a_is_canonical, b_is_canonical; int a_has_circs, b_has_circs; /* * Do not definitively deprecate a new channel with no circuits on it * until this much time has passed. */ #define NEW_CHAN_GRACE_PERIOD (15*60) tor_assert(a); tor_assert(b); /* Check if one is canonical and the other isn't first */ a_is_canonical = channel_is_canonical(a); b_is_canonical = channel_is_canonical(b); if (a_is_canonical && !b_is_canonical) return 1; if (!a_is_canonical && b_is_canonical) return 0; /* * Okay, if we're here they tied on canonicity. Next we check if * they have any circuits, and if one does and the other doesn't, * we prefer the one that does, unless we are forgiving and the * one that has no circuits is in its grace period. */ a_has_circs = (channel_num_circuits(a) > 0); b_has_circs = (channel_num_circuits(b) > 0); a_grace = (forgive_new_connections && (now < channel_when_created(a) + NEW_CHAN_GRACE_PERIOD)); b_grace = (forgive_new_connections && (now < channel_when_created(b) + NEW_CHAN_GRACE_PERIOD)); if (a_has_circs && !b_has_circs && !b_grace) return 1; if (!a_has_circs && b_has_circs && !a_grace) return 0; /* They tied on circuits too; just prefer whichever is newer */ if (channel_when_created(a) > channel_when_created(b)) return 1; else return 0; } /** * Get a channel to extend a circuit * * Pick a suitable channel to extend a circuit to given the desired digest * the address we believe is correct for that digest; this tries to see * if we already have one for the requested endpoint, but if there is no good * channel, set *msg_out to a message describing the channel's state * and our next action, and set *launch_out to a boolean indicated whether * the caller should try to launch a new channel with channel_connect(). */ channel_t * channel_get_for_extend(const char *digest, const tor_addr_t *target_addr, const char **msg_out, int *launch_out) { channel_t *chan, *best = NULL; int n_inprogress_goodaddr = 0, n_old = 0; int n_noncanonical = 0, n_possible = 0; time_t now = approx_time(); tor_assert(msg_out); tor_assert(launch_out); chan = channel_find_by_remote_digest(digest); /* Walk the list, unrefing the old one and refing the new at each * iteration. */ for (; chan; chan = channel_next_with_digest(chan)) { tor_assert(tor_memeq(chan->identity_digest, digest, DIGEST_LEN)); if (chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || chan->state == CHANNEL_STATE_ERROR) continue; /* Never return a channel on which the other end appears to be * a client. */ if (channel_is_client(chan)) { continue; } /* Never return a non-open connection. */ if (chan->state != CHANNEL_STATE_OPEN) { /* If the address matches, don't launch a new connection for this * circuit. */ if (channel_matches_target_addr_for_extend(chan, target_addr)) ++n_inprogress_goodaddr; continue; } /* Never return a connection that shouldn't be used for circs. */ if (channel_is_bad_for_new_circs(chan)) { ++n_old; continue; } /* Never return a non-canonical connection using a recent link protocol * if the address is not what we wanted. * * The channel_is_canonical_is_reliable() function asks the lower layer * if we should trust channel_is_canonical(). The below is from the * comments of the old circuit_or_get_for_extend() and applies when * the lower-layer transport is channel_tls_t. * * (For old link protocols, we can't rely on is_canonical getting * set properly if we're talking to the right address, since we might * have an out-of-date descriptor, and we will get no NETINFO cell to * tell us about the right address.) */ if (!channel_is_canonical(chan) && channel_is_canonical_is_reliable(chan) && !channel_matches_target_addr_for_extend(chan, target_addr)) { ++n_noncanonical; continue; } ++n_possible; if (!best) { best = chan; /* If we have no 'best' so far, this one is good enough. */ continue; } if (channel_is_better(now, chan, best, 0)) best = chan; } if (best) { *msg_out = "Connection is fine; using it."; *launch_out = 0; return best; } else if (n_inprogress_goodaddr) { *msg_out = "Connection in progress; waiting."; *launch_out = 0; return NULL; } else if (n_old || n_noncanonical) { *msg_out = "Connections all too old, or too non-canonical. " " Launching a new one."; *launch_out = 1; return NULL; } else { *msg_out = "Not connected. Connecting."; *launch_out = 1; return NULL; } } /** * Describe the transport subclass for a channel * * Invoke a method to get a string description of the lower-layer * transport for this channel. */ const char * channel_describe_transport(channel_t *chan) { tor_assert(chan); tor_assert(chan->describe_transport); return chan->describe_transport(chan); } /** * Describe the transport subclass for a channel listener * * Invoke a method to get a string description of the lower-layer * transport for this channel listener. */ const char * channel_listener_describe_transport(channel_listener_t *chan_l) { tor_assert(chan_l); tor_assert(chan_l->describe_transport); return chan_l->describe_transport(chan_l); } /** * Return the number of entries in queue */ static int chan_cell_queue_len(const chan_cell_queue_t *queue) { int r = 0; cell_queue_entry_t *cell; TOR_SIMPLEQ_FOREACH(cell, queue, next) ++r; return r; } /** * Dump channel statistics * * Dump statistics for one channel to the log */ void channel_dump_statistics(channel_t *chan, int severity) { double avg, interval, age; time_t now = time(NULL); tor_addr_t remote_addr; int have_remote_addr; char *remote_addr_str; tor_assert(chan); age = (double)(now - chan->timestamp_created); tor_log(severity, LD_GENERAL, "Channel " U64_FORMAT " (at %p) with transport %s is in state " "%s (%d)", U64_PRINTF_ARG(chan->global_identifier), chan, channel_describe_transport(chan), channel_state_to_string(chan->state), chan->state); tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " was created at " U64_FORMAT " (" U64_FORMAT " seconds ago) " "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->timestamp_created), U64_PRINTF_ARG(now - chan->timestamp_created), U64_PRINTF_ARG(chan->timestamp_active), U64_PRINTF_ARG(now - chan->timestamp_active)); /* Handle digest and nickname */ if (!tor_digest_is_zero(chan->identity_digest)) { if (chan->nickname) { tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " says it is connected " "to an OR with digest %s and nickname %s", U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->identity_digest, DIGEST_LEN), chan->nickname); } else { tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " says it is connected " "to an OR with digest %s and no known nickname", U64_PRINTF_ARG(chan->global_identifier), hex_str(chan->identity_digest, DIGEST_LEN)); } } else { if (chan->nickname) { tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " does not know the digest" " of the OR it is connected to, but reports its nickname is %s", U64_PRINTF_ARG(chan->global_identifier), chan->nickname); } else { tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " does not know the digest" " or the nickname of the OR it is connected to", U64_PRINTF_ARG(chan->global_identifier)); } } /* Handle remote address and descriptions */ have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr); if (have_remote_addr) { char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); remote_addr_str = tor_dup_addr(&remote_addr); tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " says its remote address" " is %s, and gives a canonical description of \"%s\" and an " "actual description of \"%s\"", U64_PRINTF_ARG(chan->global_identifier), remote_addr_str, channel_get_canonical_remote_descr(chan), actual); tor_free(remote_addr_str); tor_free(actual); } else { char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " does not know its remote " "address, but gives a canonical description of \"%s\" and an " "actual description of \"%s\"", U64_PRINTF_ARG(chan->global_identifier), channel_get_canonical_remote_descr(chan), actual); tor_free(actual); } /* Handle marks */ tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has these marks: %s %s %s " "%s %s %s", U64_PRINTF_ARG(chan->global_identifier), channel_is_bad_for_new_circs(chan) ? "bad_for_new_circs" : "!bad_for_new_circs", channel_is_canonical(chan) ? "canonical" : "!canonical", channel_is_canonical_is_reliable(chan) ? "is_canonical_is_reliable" : "!is_canonical_is_reliable", channel_is_client(chan) ? "client" : "!client", channel_is_local(chan) ? "local" : "!local", channel_is_incoming(chan) ? "incoming" : "outgoing"); /* Describe queues */ tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has %d queued incoming cells" " and %d queued outgoing cells", U64_PRINTF_ARG(chan->global_identifier), chan_cell_queue_len(&chan->incoming_queue), chan_cell_queue_len(&chan->outgoing_queue)); /* Describe circuits */ tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has %d active circuits out of" " %d in total", U64_PRINTF_ARG(chan->global_identifier), (chan->cmux != NULL) ? circuitmux_num_active_circuits(chan->cmux) : 0, (chan->cmux != NULL) ? circuitmux_num_circuits(chan->cmux) : 0); /* Describe timestamps */ tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " was last used by a " "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->timestamp_client), U64_PRINTF_ARG(now - chan->timestamp_client)); tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " was last drained at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->timestamp_drained), U64_PRINTF_ARG(now - chan->timestamp_drained)); tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " last received a cell " "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->timestamp_recv), U64_PRINTF_ARG(now - chan->timestamp_recv)); tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " last trasmitted a cell " "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->timestamp_xmit), U64_PRINTF_ARG(now - chan->timestamp_xmit)); /* Describe counters and rates */ tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has received " U64_FORMAT " cells and transmitted " U64_FORMAT, U64_PRINTF_ARG(chan->global_identifier), U64_PRINTF_ARG(chan->n_cells_recved), U64_PRINTF_ARG(chan->n_cells_xmitted)); if (now > chan->timestamp_created && chan->timestamp_created > 0) { if (chan->n_cells_recved > 0) { avg = (double)(chan->n_cells_recved) / age; if (avg >= 1.0) { tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has averaged %f " "cells received per second", U64_PRINTF_ARG(chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has averaged %f " "seconds between received cells", U64_PRINTF_ARG(chan->global_identifier), interval); } } if (chan->n_cells_xmitted > 0) { avg = (double)(chan->n_cells_xmitted) / age; if (avg >= 1.0) { tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has averaged %f " "cells transmitted per second", U64_PRINTF_ARG(chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; tor_log(severity, LD_GENERAL, " * Channel " U64_FORMAT " has averaged %f " "seconds between transmitted cells", U64_PRINTF_ARG(chan->global_identifier), interval); } } } /* Dump anything the lower layer has to say */ channel_dump_transport_statistics(chan, severity); } /** * Dump channel listener statistics * * Dump statistics for one channel listener to the log */ void channel_listener_dump_statistics(channel_listener_t *chan_l, int severity) { double avg, interval, age; time_t now = time(NULL); tor_assert(chan_l); age = (double)(now - chan_l->timestamp_created); tor_log(severity, LD_GENERAL, "Channel listener " U64_FORMAT " (at %p) with transport %s is in " "state %s (%d)", U64_PRINTF_ARG(chan_l->global_identifier), chan_l, channel_listener_describe_transport(chan_l), channel_listener_state_to_string(chan_l->state), chan_l->state); tor_log(severity, LD_GENERAL, " * Channel listener " U64_FORMAT " was created at " U64_FORMAT " (" U64_FORMAT " seconds ago) " "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", U64_PRINTF_ARG(chan_l->global_identifier), U64_PRINTF_ARG(chan_l->timestamp_created), U64_PRINTF_ARG(now - chan_l->timestamp_created), U64_PRINTF_ARG(chan_l->timestamp_active), U64_PRINTF_ARG(now - chan_l->timestamp_active)); tor_log(severity, LD_GENERAL, " * Channel listener " U64_FORMAT " last accepted an incoming " "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) " "and has accepted " U64_FORMAT " channels in total", U64_PRINTF_ARG(chan_l->global_identifier), U64_PRINTF_ARG(chan_l->timestamp_accepted), U64_PRINTF_ARG(now - chan_l->timestamp_accepted), U64_PRINTF_ARG(chan_l->n_accepted)); /* * If it's sensible to do so, get the rate of incoming channels on this * listener */ if (now > chan_l->timestamp_created && chan_l->timestamp_created > 0 && chan_l->n_accepted > 0) { avg = (double)(chan_l->n_accepted) / age; if (avg >= 1.0) { tor_log(severity, LD_GENERAL, " * Channel listener " U64_FORMAT " has averaged %f incoming " "channels per second", U64_PRINTF_ARG(chan_l->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; tor_log(severity, LD_GENERAL, " * Channel listener " U64_FORMAT " has averaged %f seconds " "between incoming channels", U64_PRINTF_ARG(chan_l->global_identifier), interval); } } /* Dump anything the lower layer has to say */ channel_listener_dump_transport_statistics(chan_l, severity); } /** * Invoke transport-specific stats dump for channel * * If there is a lower-layer statistics dump method, invoke it */ void channel_dump_transport_statistics(channel_t *chan, int severity) { tor_assert(chan); if (chan->dumpstats) chan->dumpstats(chan, severity); } /** * Invoke transport-specific stats dump for channel listener * * If there is a lower-layer statistics dump method, invoke it */ void channel_listener_dump_transport_statistics(channel_listener_t *chan_l, int severity) { tor_assert(chan_l); if (chan_l->dumpstats) chan_l->dumpstats(chan_l, severity); } /** * Return text description of the remote endpoint * * This function return a test provided by the lower layer of the remote * endpoint for this channel; it should specify the actual address connected * to/from. * * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} * may invalidate the return value from this function. */ const char * channel_get_actual_remote_descr(channel_t *chan) { tor_assert(chan); tor_assert(chan->get_remote_descr); /* Param 1 indicates the actual description */ return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL); } /** * Return the text address of the remote endpoint. * * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} * may invalidate the return value from this function. */ const char * channel_get_actual_remote_address(channel_t *chan) { /* Param 1 indicates the actual description */ return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY); } /** * Return text description of the remote endpoint canonical address * * This function return a test provided by the lower layer of the remote * endpoint for this channel; it should use the known canonical address for * this OR's identity digest if possible. * * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} * may invalidate the return value from this function. */ const char * channel_get_canonical_remote_descr(channel_t *chan) { tor_assert(chan); tor_assert(chan->get_remote_descr); /* Param 0 indicates the canonicalized description */ return chan->get_remote_descr(chan, 0); } /** * Get remote address if possible. * * Write the remote address out to a tor_addr_t if the underlying transport * supports this operation, and return 1. Return 0 if the underlying transport * doesn't let us do this. */ int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out) { tor_assert(chan); tor_assert(addr_out); if (chan->get_remote_addr) return chan->get_remote_addr(chan, addr_out); /* Else no support, method not implemented */ else return 0; } /** * Check if there are outgoing queue writes on this channel * * Indicate if either we have queued cells, or if not, whether the underlying * lower-layer transport thinks it has an output queue. */ int channel_has_queued_writes(channel_t *chan) { int has_writes = 0; tor_assert(chan); tor_assert(chan->has_queued_writes); if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) { has_writes = 1; } else { /* Check with the lower layer */ has_writes = chan->has_queued_writes(chan); } return has_writes; } /** * Check the is_bad_for_new_circs flag * * This function returns the is_bad_for_new_circs flag of the specified * channel. */ int channel_is_bad_for_new_circs(channel_t *chan) { tor_assert(chan); return chan->is_bad_for_new_circs; } /** * Mark a channel as bad for new circuits * * Set the is_bad_for_new_circs_flag on chan. */ void channel_mark_bad_for_new_circs(channel_t *chan) { tor_assert(chan); chan->is_bad_for_new_circs = 1; } /** * Get the client flag * * This returns the client flag of a channel, which will be set if * command_process_create_cell() in command.c thinks this is a connection * from a client. */ int channel_is_client(channel_t *chan) { tor_assert(chan); return chan->is_client; } /** * Set the client flag * * Mark a channel as being from a client */ void channel_mark_client(channel_t *chan) { tor_assert(chan); chan->is_client = 1; } /** * Get the canonical flag for a channel * * This returns the is_canonical for a channel; this flag is determined by * the lower layer and can't be set in a transport-independent way. */ int channel_is_canonical(channel_t *chan) { tor_assert(chan); tor_assert(chan->is_canonical); return chan->is_canonical(chan, 0); } /** * Test if the canonical flag is reliable * * This function asks if the lower layer thinks it's safe to trust the * result of channel_is_canonical() */ int channel_is_canonical_is_reliable(channel_t *chan) { tor_assert(chan); tor_assert(chan->is_canonical); return chan->is_canonical(chan, 1); } /** * Test incoming flag * * This function gets the incoming flag; this is set when a listener spawns * a channel. If this returns true the channel was remotely initiated. */ int channel_is_incoming(channel_t *chan) { tor_assert(chan); return chan->is_incoming; } /** * Set the incoming flag * * This function is called when a channel arrives on a listening channel * to mark it as incoming. */ void channel_mark_incoming(channel_t *chan) { tor_assert(chan); chan->is_incoming = 1; } /** * Test local flag * * This function gets the local flag; the lower layer should set this when * setting up the channel if is_local_addr() is true for all of the * destinations it will communicate with on behalf of this channel. It's * used to decide whether to declare the network reachable when seeing incoming * traffic on the channel. */ int channel_is_local(channel_t *chan) { tor_assert(chan); return chan->is_local; } /** * Set the local flag * * This internal-only function should be called by the lower layer if the * channel is to a local address. See channel_is_local() above or the * description of the is_local bit in channel.h */ void channel_mark_local(channel_t *chan) { tor_assert(chan); chan->is_local = 1; } /** * Test outgoing flag * * This function gets the outgoing flag; this is the inverse of the incoming * bit set when a listener spawns a channel. If this returns true the channel * was locally initiated. */ int channel_is_outgoing(channel_t *chan) { tor_assert(chan); return !(chan->is_incoming); } /** * Mark a channel as outgoing * * This function clears the incoming flag and thus marks a channel as * outgoing. */ void channel_mark_outgoing(channel_t *chan) { tor_assert(chan); chan->is_incoming = 0; } /********************* * Timestamp updates * ********************/ /** * Update the created timestamp for a channel * * This updates the channel's created timestamp and should only be called * from channel_init(). */ void channel_timestamp_created(channel_t *chan) { time_t now = time(NULL); tor_assert(chan); chan->timestamp_created = now; } /** * Update the created timestamp for a channel listener * * This updates the channel listener's created timestamp and should only be * called from channel_init_listener(). */ void channel_listener_timestamp_created(channel_listener_t *chan_l) { time_t now = time(NULL); tor_assert(chan_l); chan_l->timestamp_created = now; } /** * Update the last active timestamp for a channel * * This function updates the channel's last active timestamp; it should be * called by the lower layer whenever there is activity on the channel which * does not lead to a cell being transmitted or received; the active timestamp * is also updated from channel_timestamp_recv() and channel_timestamp_xmit(), * but it should be updated for things like the v3 handshake and stuff that * produce activity only visible to the lower layer. */ void channel_timestamp_active(channel_t *chan) { time_t now = time(NULL); tor_assert(chan); chan->timestamp_active = now; } /** * Update the last active timestamp for a channel listener */ void channel_listener_timestamp_active(channel_listener_t *chan_l) { time_t now = time(NULL); tor_assert(chan_l); chan_l->timestamp_active = now; } /** * Update the last accepted timestamp. * * This function updates the channel listener's last accepted timestamp; it * should be called whenever a new incoming channel is accepted on a * listener. */ void channel_listener_timestamp_accepted(channel_listener_t *chan_l) { time_t now = time(NULL); tor_assert(chan_l); chan_l->timestamp_active = now; chan_l->timestamp_accepted = now; } /** * Update client timestamp * * This function is called by relay.c to timestamp a channel that appears to * be used as a client. */ void channel_timestamp_client(channel_t *chan) { time_t now = time(NULL); tor_assert(chan); chan->timestamp_client = now; } /** * Update the last drained timestamp * * This is called whenever we transmit a cell which leaves the outgoing cell * queue completely empty. It also updates the xmit time and the active time. */ void channel_timestamp_drained(channel_t *chan) { time_t now = time(NULL); tor_assert(chan); chan->timestamp_active = now; chan->timestamp_drained = now; chan->timestamp_xmit = now; } /** * Update the recv timestamp * * This is called whenever we get an incoming cell from the lower layer. * This also updates the active timestamp. */ void channel_timestamp_recv(channel_t *chan) { time_t now = time(NULL); tor_assert(chan); chan->timestamp_active = now; chan->timestamp_recv = now; } /** * Update the xmit timestamp * This is called whenever we pass an outgoing cell to the lower layer. This * also updates the active timestamp. */ void channel_timestamp_xmit(channel_t *chan) { time_t now = time(NULL); tor_assert(chan); chan->timestamp_active = now; chan->timestamp_xmit = now; } /*************************************************************** * Timestamp queries - see above for definitions of timestamps * **************************************************************/ /** * Query created timestamp for a channel */ time_t channel_when_created(channel_t *chan) { tor_assert(chan); return chan->timestamp_created; } /** * Query created timestamp for a channel listener */ time_t channel_listener_when_created(channel_listener_t *chan_l) { tor_assert(chan_l); return chan_l->timestamp_created; } /** * Query last active timestamp for a channel */ time_t channel_when_last_active(channel_t *chan) { tor_assert(chan); return chan->timestamp_active; } /** * Query last active timestamp for a channel listener */ time_t channel_listener_when_last_active(channel_listener_t *chan_l) { tor_assert(chan_l); return chan_l->timestamp_active; } /** * Query last accepted timestamp for a channel listener */ time_t channel_listener_when_last_accepted(channel_listener_t *chan_l) { tor_assert(chan_l); return chan_l->timestamp_accepted; } /** * Query client timestamp */ time_t channel_when_last_client(channel_t *chan) { tor_assert(chan); return chan->timestamp_client; } /** * Query drained timestamp */ time_t channel_when_last_drained(channel_t *chan) { tor_assert(chan); return chan->timestamp_drained; } /** * Query recv timestamp */ time_t channel_when_last_recv(channel_t *chan) { tor_assert(chan); return chan->timestamp_recv; } /** * Query xmit timestamp */ time_t channel_when_last_xmit(channel_t *chan) { tor_assert(chan); return chan->timestamp_xmit; } /** * Query accepted counter */ uint64_t channel_listener_count_accepted(channel_listener_t *chan_l) { tor_assert(chan_l); return chan_l->n_accepted; } /** * Query received cell counter */ uint64_t channel_count_recved(channel_t *chan) { tor_assert(chan); return chan->n_cells_recved; } /** * Query transmitted cell counter */ uint64_t channel_count_xmitted(channel_t *chan) { tor_assert(chan); return chan->n_cells_xmitted; } /** * Check if a channel matches an extend_info_t * * This function calls the lower layer and asks if this channel matches a * given extend_info_t. */ int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info) { tor_assert(chan); tor_assert(chan->matches_extend_info); tor_assert(extend_info); return chan->matches_extend_info(chan, extend_info); } /** * Check if a channel matches a given target address; return true iff we do. * * This function calls into the lower layer and asks if this channel thinks * it matches a given target address for circuit extension purposes. */ int channel_matches_target_addr_for_extend(channel_t *chan, const tor_addr_t *target) { tor_assert(chan); tor_assert(chan->matches_target); tor_assert(target); return chan->matches_target(chan, target); } /** * Return the total number of circuits used by a channel * * @param chan Channel to query * @return Number of circuits using this as n_chan or p_chan */ unsigned int channel_num_circuits(channel_t *chan) { tor_assert(chan); return chan->num_n_circuits + chan->num_p_circuits; } /** * Set up circuit ID generation * * This is called when setting up a channel and replaces the old * connection_or_set_circid_type() */ void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd, int consider_identity) { int started_here; crypto_pk_t *our_identity; tor_assert(chan); started_here = channel_is_outgoing(chan); if (! consider_identity) { if (started_here) chan->circ_id_type = CIRC_ID_TYPE_HIGHER; else chan->circ_id_type = CIRC_ID_TYPE_LOWER; return; } our_identity = started_here ? get_tlsclient_identity_key() : get_server_identity_key(); if (identity_rcvd) { if (crypto_pk_cmp_keys(our_identity, identity_rcvd) < 0) { chan->circ_id_type = CIRC_ID_TYPE_LOWER; } else { chan->circ_id_type = CIRC_ID_TYPE_HIGHER; } } else { chan->circ_id_type = CIRC_ID_TYPE_NEITHER; } } tor-0.2.4.20/src/or/buffers.c0000644000175000017500000023113012255745673012511 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file buffers.c * \brief Implements a generic interface buffer. Buffers are * fairly opaque string holders that can read to or flush from: * memory, file descriptors, or TLS connections. **/ #define BUFFERS_PRIVATE #include "or.h" #include "addressmap.h" #include "buffers.h" #include "config.h" #include "connection_edge.h" #include "connection_or.h" #include "control.h" #include "reasons.h" #include "../common/util.h" #include "../common/torlog.h" #ifdef HAVE_UNISTD_H #include #endif //#define PARANOIA #ifdef PARANOIA /** Helper: If PARANOIA is defined, assert that the buffer in local variable * buf is well-formed. */ #define check() STMT_BEGIN assert_buf_ok(buf); STMT_END #else #define check() STMT_NIL #endif /* Implementation notes: * * After flirting with memmove, and dallying with ring-buffers, we're finally * getting up to speed with the 1970s and implementing buffers as a linked * list of small chunks. Each buffer has such a list; data is removed from * the head of the list, and added at the tail. The list is singly linked, * and the buffer keeps a pointer to the head and the tail. * * Every chunk, except the tail, contains at least one byte of data. Data in * each chunk is contiguous. * * When you need to treat the first N characters on a buffer as a contiguous * string, use the buf_pullup function to make them so. Don't do this more * than necessary. * * The major free Unix kernels have handled buffers like this since, like, * forever. */ static int parse_socks(const char *data, size_t datalen, socks_request_t *req, int log_sockstype, int safe_socks, ssize_t *drain_out, size_t *want_length_out); static int parse_socks_client(const uint8_t *data, size_t datalen, int state, char **reason, ssize_t *drain_out); /* Chunk manipulation functions */ /** A single chunk on a buffer or in a freelist. */ typedef struct chunk_t { struct chunk_t *next; /**< The next chunk on the buffer or freelist. */ size_t datalen; /**< The number of bytes stored in this chunk */ size_t memlen; /**< The number of usable bytes of storage in mem. */ char *data; /**< A pointer to the first byte of data stored in mem. */ char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in * this chunk. */ } chunk_t; #define CHUNK_HEADER_LEN STRUCT_OFFSET(chunk_t, mem[0]) /** Return the number of bytes needed to allocate a chunk to hold * memlen bytes. */ #define CHUNK_ALLOC_SIZE(memlen) (CHUNK_HEADER_LEN + (memlen)) /** Return the number of usable bytes in a chunk allocated with * malloc(memlen). */ #define CHUNK_SIZE_WITH_ALLOC(memlen) ((memlen) - CHUNK_HEADER_LEN) /** Return the next character in chunk onto which data can be appended. * If the chunk is full, this might be off the end of chunk->mem. */ static INLINE char * CHUNK_WRITE_PTR(chunk_t *chunk) { return chunk->data + chunk->datalen; } /** Return the number of bytes that can be written onto chunk without * running out of space. */ static INLINE size_t CHUNK_REMAINING_CAPACITY(const chunk_t *chunk) { return (chunk->mem + chunk->memlen) - (chunk->data + chunk->datalen); } /** Move all bytes stored in chunk to the front of chunk->mem, * to free up space at the end. */ static INLINE void chunk_repack(chunk_t *chunk) { if (chunk->datalen && chunk->data != &chunk->mem[0]) { memmove(chunk->mem, chunk->data, chunk->datalen); } chunk->data = &chunk->mem[0]; } #if defined(ENABLE_BUF_FREELISTS) || defined(RUNNING_DOXYGEN) /** A freelist of chunks. */ typedef struct chunk_freelist_t { size_t alloc_size; /**< What size chunks does this freelist hold? */ int max_length; /**< Never allow more than this number of chunks in the * freelist. */ int slack; /**< When trimming the freelist, leave this number of extra * chunks beyond lowest_length.*/ int cur_length; /**< How many chunks on the freelist now? */ int lowest_length; /**< What's the smallest value of cur_length since the * last time we cleaned this freelist? */ uint64_t n_alloc; uint64_t n_free; uint64_t n_hit; chunk_t *head; /**< First chunk on the freelist. */ } chunk_freelist_t; /** Macro to help define freelists. */ #define FL(a,m,s) { a, m, s, 0, 0, 0, 0, 0, NULL } /** Static array of freelists, sorted by alloc_len, terminated by an entry * with alloc_size of 0. */ static chunk_freelist_t freelists[] = { FL(4096, 256, 8), FL(8192, 128, 4), FL(16384, 64, 4), FL(32768, 32, 2), FL(0, 0, 0) }; #undef FL /** How many times have we looked for a chunk of a size that no freelist * could help with? */ static uint64_t n_freelist_miss = 0; static void assert_freelist_ok(chunk_freelist_t *fl); /** Return the freelist to hold chunks of size alloc, or NULL if * no freelist exists for that size. */ static INLINE chunk_freelist_t * get_freelist(size_t alloc) { int i; for (i=0; (freelists[i].alloc_size <= alloc && freelists[i].alloc_size); ++i ) { if (freelists[i].alloc_size == alloc) { return &freelists[i]; } } return NULL; } /** Deallocate a chunk or put it on a freelist */ static void chunk_free_unchecked(chunk_t *chunk) { size_t alloc; chunk_freelist_t *freelist; alloc = CHUNK_ALLOC_SIZE(chunk->memlen); freelist = get_freelist(alloc); if (freelist && freelist->cur_length < freelist->max_length) { chunk->next = freelist->head; freelist->head = chunk; ++freelist->cur_length; } else { if (freelist) ++freelist->n_free; tor_free(chunk); } } /** Allocate a new chunk with a given allocation size, or get one from the * freelist. Note that a chunk with allocation size A can actually hold only * CHUNK_SIZE_WITH_ALLOC(A) bytes in its mem field. */ static INLINE chunk_t * chunk_new_with_alloc_size(size_t alloc) { chunk_t *ch; chunk_freelist_t *freelist; tor_assert(alloc >= sizeof(chunk_t)); freelist = get_freelist(alloc); if (freelist && freelist->head) { ch = freelist->head; freelist->head = ch->next; if (--freelist->cur_length < freelist->lowest_length) freelist->lowest_length = freelist->cur_length; ++freelist->n_hit; } else { if (freelist) ++freelist->n_alloc; else ++n_freelist_miss; ch = tor_malloc(alloc); } ch->next = NULL; ch->datalen = 0; ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc); ch->data = &ch->mem[0]; return ch; } #else static void chunk_free_unchecked(chunk_t *chunk) { tor_free(chunk); } static INLINE chunk_t * chunk_new_with_alloc_size(size_t alloc) { chunk_t *ch; ch = tor_malloc(alloc); ch->next = NULL; ch->datalen = 0; ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc); ch->data = &ch->mem[0]; return ch; } #endif /** Expand chunk until it can hold sz bytes, and return a * new pointer to chunk. Old pointers are no longer valid. */ static INLINE chunk_t * chunk_grow(chunk_t *chunk, size_t sz) { off_t offset; tor_assert(sz > chunk->memlen); offset = chunk->data - chunk->mem; chunk = tor_realloc(chunk, CHUNK_ALLOC_SIZE(sz)); chunk->memlen = sz; chunk->data = chunk->mem + offset; return chunk; } /** If a read onto the end of a chunk would be smaller than this number, then * just start a new chunk. */ #define MIN_READ_LEN 8 /** Every chunk should take up at least this many bytes. */ #define MIN_CHUNK_ALLOC 256 /** No chunk should take up more than this many bytes. */ #define MAX_CHUNK_ALLOC 65536 /** Return the allocation size we'd like to use to hold target * bytes. */ static INLINE size_t preferred_chunk_size(size_t target) { size_t sz = MIN_CHUNK_ALLOC; while (CHUNK_SIZE_WITH_ALLOC(sz) < target) { sz <<= 1; } return sz; } /** Remove from the freelists most chunks that have not been used since the * last call to buf_shrink_freelists(). */ void buf_shrink_freelists(int free_all) { #ifdef ENABLE_BUF_FREELISTS int i; disable_control_logging(); for (i = 0; freelists[i].alloc_size; ++i) { int slack = freelists[i].slack; assert_freelist_ok(&freelists[i]); if (free_all || freelists[i].lowest_length > slack) { int n_to_free = free_all ? freelists[i].cur_length : (freelists[i].lowest_length - slack); int n_to_skip = freelists[i].cur_length - n_to_free; int orig_length = freelists[i].cur_length; int orig_n_to_free = n_to_free, n_freed=0; int orig_n_to_skip = n_to_skip; int new_length = n_to_skip; chunk_t **chp = &freelists[i].head; chunk_t *chunk; while (n_to_skip) { if (! (*chp)->next) { log_warn(LD_BUG, "I wanted to skip %d chunks in the freelist for " "%d-byte chunks, but only found %d. (Length %d)", orig_n_to_skip, (int)freelists[i].alloc_size, orig_n_to_skip-n_to_skip, freelists[i].cur_length); assert_freelist_ok(&freelists[i]); goto done; } // tor_assert((*chp)->next); chp = &(*chp)->next; --n_to_skip; } chunk = *chp; *chp = NULL; while (chunk) { chunk_t *next = chunk->next; tor_free(chunk); chunk = next; --n_to_free; ++n_freed; ++freelists[i].n_free; } if (n_to_free) { log_warn(LD_BUG, "Freelist length for %d-byte chunks may have been " "messed up somehow.", (int)freelists[i].alloc_size); log_warn(LD_BUG, "There were %d chunks at the start. I decided to " "keep %d. I wanted to free %d. I freed %d. I somehow think " "I have %d left to free.", freelists[i].cur_length, n_to_skip, orig_n_to_free, n_freed, n_to_free); } // tor_assert(!n_to_free); freelists[i].cur_length = new_length; log_info(LD_MM, "Cleaned freelist for %d-byte chunks: original " "length %d, kept %d, dropped %d.", (int)freelists[i].alloc_size, orig_length, orig_n_to_skip, orig_n_to_free); } freelists[i].lowest_length = freelists[i].cur_length; assert_freelist_ok(&freelists[i]); } done: enable_control_logging(); #else (void) free_all; #endif } /** Describe the current status of the freelists at log level severity. */ void buf_dump_freelist_sizes(int severity) { #ifdef ENABLE_BUF_FREELISTS int i; tor_log(severity, LD_MM, "====== Buffer freelists:"); for (i = 0; freelists[i].alloc_size; ++i) { uint64_t total = ((uint64_t)freelists[i].cur_length) * freelists[i].alloc_size; tor_log(severity, LD_MM, U64_FORMAT" bytes in %d %d-byte chunks ["U64_FORMAT " misses; "U64_FORMAT" frees; "U64_FORMAT" hits]", U64_PRINTF_ARG(total), freelists[i].cur_length, (int)freelists[i].alloc_size, U64_PRINTF_ARG(freelists[i].n_alloc), U64_PRINTF_ARG(freelists[i].n_free), U64_PRINTF_ARG(freelists[i].n_hit)); } tor_log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes", U64_PRINTF_ARG(n_freelist_miss)); #else (void)severity; #endif } /** Magic value for buf_t.magic, to catch pointer errors. */ #define BUFFER_MAGIC 0xB0FFF312u /** A resizeable buffer, optimized for reading and writing. */ struct buf_t { uint32_t magic; /**< Magic cookie for debugging: Must be set to * BUFFER_MAGIC. */ size_t datalen; /**< How many bytes is this buffer holding right now? */ size_t default_chunk_size; /**< Don't allocate any chunks smaller than * this for this buffer. */ chunk_t *head; /**< First chunk in the list, or NULL for none. */ chunk_t *tail; /**< Last chunk in the list, or NULL for none. */ }; /** Collapse data from the first N chunks from buf into buf->head, * growing it as necessary, until buf->head has the first bytes bytes * of data from the buffer, or until buf->head has all the data in buf. * * If nulterminate is true, ensure that there is a 0 byte in * buf->head->mem right after all the data. */ static void buf_pullup(buf_t *buf, size_t bytes, int nulterminate) { chunk_t *dest, *src; size_t capacity; if (!buf->head) return; check(); if (buf->datalen < bytes) bytes = buf->datalen; if (nulterminate) { capacity = bytes + 1; if (buf->head->datalen >= bytes && CHUNK_REMAINING_CAPACITY(buf->head)) { *CHUNK_WRITE_PTR(buf->head) = '\0'; return; } } else { capacity = bytes; if (buf->head->datalen >= bytes) return; } if (buf->head->memlen >= capacity) { /* We don't need to grow the first chunk, but we might need to repack it.*/ size_t needed = capacity - buf->head->datalen; if (CHUNK_REMAINING_CAPACITY(buf->head) < needed) chunk_repack(buf->head); tor_assert(CHUNK_REMAINING_CAPACITY(buf->head) >= needed); } else { chunk_t *newhead; size_t newsize; /* We need to grow the chunk. */ chunk_repack(buf->head); newsize = CHUNK_SIZE_WITH_ALLOC(preferred_chunk_size(capacity)); newhead = chunk_grow(buf->head, newsize); tor_assert(newhead->memlen >= capacity); if (newhead != buf->head) { if (buf->tail == buf->head) buf->tail = newhead; buf->head = newhead; } } dest = buf->head; while (dest->datalen < bytes) { size_t n = bytes - dest->datalen; src = dest->next; tor_assert(src); if (n > src->datalen) { memcpy(CHUNK_WRITE_PTR(dest), src->data, src->datalen); dest->datalen += src->datalen; dest->next = src->next; if (buf->tail == src) buf->tail = dest; chunk_free_unchecked(src); } else { memcpy(CHUNK_WRITE_PTR(dest), src->data, n); dest->datalen += n; src->data += n; src->datalen -= n; tor_assert(dest->datalen == bytes); } } if (nulterminate) { tor_assert(CHUNK_REMAINING_CAPACITY(buf->head)); *CHUNK_WRITE_PTR(buf->head) = '\0'; } check(); } /** Resize buf so it won't hold extra memory that we haven't been * using lately. */ void buf_shrink(buf_t *buf) { (void)buf; } /** Remove the first n bytes from buf. */ static INLINE void buf_remove_from_front(buf_t *buf, size_t n) { tor_assert(buf->datalen >= n); while (n) { tor_assert(buf->head); if (buf->head->datalen > n) { buf->head->datalen -= n; buf->head->data += n; buf->datalen -= n; return; } else { chunk_t *victim = buf->head; n -= victim->datalen; buf->datalen -= victim->datalen; buf->head = victim->next; if (buf->tail == victim) buf->tail = NULL; chunk_free_unchecked(victim); } } check(); } /** Create and return a new buf with default chunk capacity size. */ buf_t * buf_new_with_capacity(size_t size) { buf_t *b = buf_new(); b->default_chunk_size = preferred_chunk_size(size); return b; } /** Allocate and return a new buffer with default capacity. */ buf_t * buf_new(void) { buf_t *buf = tor_malloc_zero(sizeof(buf_t)); buf->magic = BUFFER_MAGIC; buf->default_chunk_size = 4096; return buf; } /** Remove all data from buf. */ void buf_clear(buf_t *buf) { chunk_t *chunk, *next; buf->datalen = 0; for (chunk = buf->head; chunk; chunk = next) { next = chunk->next; chunk_free_unchecked(chunk); } buf->head = buf->tail = NULL; } /** Return the number of bytes stored in buf */ size_t buf_datalen(const buf_t *buf) { return buf->datalen; } /** Return the total length of all chunks used in buf. */ size_t buf_allocation(const buf_t *buf) { size_t total = 0; const chunk_t *chunk; for (chunk = buf->head; chunk; chunk = chunk->next) { total += chunk->memlen; } return total; } /** Return the number of bytes that can be added to buf without * performing any additional allocation. */ size_t buf_slack(const buf_t *buf) { if (!buf->tail) return 0; else return CHUNK_REMAINING_CAPACITY(buf->tail); } /** Release storage held by buf. */ void buf_free(buf_t *buf) { if (!buf) return; buf_clear(buf); buf->magic = 0xdeadbeef; tor_free(buf); } /** Return a new copy of in_chunk */ static chunk_t * chunk_copy(const chunk_t *in_chunk) { chunk_t *newch = tor_memdup(in_chunk, CHUNK_ALLOC_SIZE(in_chunk->memlen)); newch->next = NULL; if (in_chunk->data) { off_t offset = in_chunk->data - in_chunk->mem; newch->data = newch->mem + offset; } return newch; } /** Return a new copy of buf */ buf_t * buf_copy(const buf_t *buf) { chunk_t *ch; buf_t *out = buf_new(); out->default_chunk_size = buf->default_chunk_size; for (ch = buf->head; ch; ch = ch->next) { chunk_t *newch = chunk_copy(ch); if (out->tail) { out->tail->next = newch; out->tail = newch; } else { out->head = out->tail = newch; } } out->datalen = buf->datalen; return out; } /** Append a new chunk with enough capacity to hold capacity bytes to * the tail of buf. If capped, don't allocate a chunk bigger * than MAX_CHUNK_ALLOC. */ static chunk_t * buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped) { chunk_t *chunk; if (CHUNK_ALLOC_SIZE(capacity) < buf->default_chunk_size) { chunk = chunk_new_with_alloc_size(buf->default_chunk_size); } else if (capped && CHUNK_ALLOC_SIZE(capacity) > MAX_CHUNK_ALLOC) { chunk = chunk_new_with_alloc_size(MAX_CHUNK_ALLOC); } else { chunk = chunk_new_with_alloc_size(preferred_chunk_size(capacity)); } if (buf->tail) { tor_assert(buf->head); buf->tail->next = chunk; buf->tail = chunk; } else { tor_assert(!buf->head); buf->head = buf->tail = chunk; } check(); return chunk; } /** Read up to at_most bytes from the socket fd into * chunk (which must be on buf). If we get an EOF, set * *reached_eof to 1. Return -1 on error, 0 on eof or blocking, * and the number of bytes read otherwise. */ static INLINE int read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, int *reached_eof, int *socket_error) { ssize_t read_result; if (at_most > CHUNK_REMAINING_CAPACITY(chunk)) at_most = CHUNK_REMAINING_CAPACITY(chunk); read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0); if (read_result < 0) { int e = tor_socket_errno(fd); if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ #ifdef _WIN32 if (e == WSAENOBUFS) log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?"); #endif *socket_error = e; return -1; } return 0; /* would block. */ } else if (read_result == 0) { log_debug(LD_NET,"Encountered eof on fd %d", (int)fd); *reached_eof = 1; return 0; } else { /* actually got bytes. */ buf->datalen += read_result; chunk->datalen += read_result; log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result, (int)buf->datalen); tor_assert(read_result < INT_MAX); return (int)read_result; } } /** As read_to_chunk(), but return (negative) error code on error, blocking, * or TLS, and the number of bytes read otherwise. */ static INLINE int read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls, size_t at_most) { int read_result; tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most); read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most); if (read_result < 0) return read_result; buf->datalen += read_result; chunk->datalen += read_result; return read_result; } /** Read from socket s, writing onto end of buf. Read at most * at_most bytes, growing the buffer as necessary. If recv() returns 0 * (because of EOF), set *reached_eof to 1 and return 0. Return -1 on * error; else return the number of bytes read. */ /* XXXX024 indicate "read blocked" somehow? */ int read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof, int *socket_error) { /* XXXX024 It's stupid to overload the return values for these functions: * "error status" and "number of bytes read" are not mutually exclusive. */ int r = 0; size_t total_read = 0; check(); tor_assert(reached_eof); tor_assert(SOCKET_OK(s)); while (at_most > total_read) { size_t readlen = at_most - total_read; chunk_t *chunk; if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { chunk = buf_add_chunk_with_capacity(buf, at_most, 1); if (readlen > chunk->memlen) readlen = chunk->memlen; } else { size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); chunk = buf->tail; if (cap < readlen) readlen = cap; } r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error); check(); if (r < 0) return r; /* Error */ tor_assert(total_read+r < INT_MAX); total_read += r; if ((size_t)r < readlen) { /* eof, block, or no more to read. */ break; } } return (int)total_read; } /** As read_to_buf, but reads from a TLS connection, and returns a TLS * status value rather than the number of bytes read. * * Using TLS on OR connections complicates matters in two ways. * * First, a TLS stream has its own read buffer independent of the * connection's read buffer. (TLS needs to read an entire frame from * the network before it can decrypt any data. Thus, trying to read 1 * byte from TLS can require that several KB be read from the network * and decrypted. The extra data is stored in TLS's decrypt buffer.) * Because the data hasn't been read by Tor (it's still inside the TLS), * this means that sometimes a connection "has stuff to read" even when * poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is * used in connection.c to detect TLS objects with non-empty internal * buffers and read from them again. * * Second, the TLS stream's events do not correspond directly to network * events: sometimes, before a TLS stream can read, the network must be * ready to write -- or vice versa. */ int read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf) { int r = 0; size_t total_read = 0; check_no_tls_errors(); check(); while (at_most > total_read) { size_t readlen = at_most - total_read; chunk_t *chunk; if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { chunk = buf_add_chunk_with_capacity(buf, at_most, 1); if (readlen > chunk->memlen) readlen = chunk->memlen; } else { size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); chunk = buf->tail; if (cap < readlen) readlen = cap; } r = read_to_chunk_tls(buf, chunk, tls, readlen); check(); if (r < 0) return r; /* Error */ tor_assert(total_read+r < INT_MAX); total_read += r; if ((size_t)r < readlen) /* eof, block, or no more to read. */ break; } return (int)total_read; } /** Helper for flush_buf(): try to write sz bytes from chunk * chunk of buffer buf onto socket s. On success, deduct * the bytes written from *buf_flushlen. Return the number of bytes * written on success, 0 on blocking, -1 on failure. */ static INLINE int flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, size_t *buf_flushlen) { ssize_t write_result; if (sz > chunk->datalen) sz = chunk->datalen; write_result = tor_socket_send(s, chunk->data, sz, 0); if (write_result < 0) { int e = tor_socket_errno(s); if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ #ifdef _WIN32 if (e == WSAENOBUFS) log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?"); #endif return -1; } log_debug(LD_NET,"write() would block, returning."); return 0; } else { *buf_flushlen -= write_result; buf_remove_from_front(buf, write_result); tor_assert(write_result < INT_MAX); return (int)write_result; } } /** Helper for flush_buf_tls(): try to write sz bytes from chunk * chunk of buffer buf onto socket s. (Tries to write * more if there is a forced pending write size.) On success, deduct the * bytes written from *buf_flushlen. Return the number of bytes * written on success, and a TOR_TLS error code on failure or blocking. */ static INLINE int flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, size_t sz, size_t *buf_flushlen) { int r; size_t forced; char *data; forced = tor_tls_get_forced_write_size(tls); if (forced > sz) sz = forced; if (chunk) { data = chunk->data; tor_assert(sz <= chunk->datalen); } else { data = NULL; tor_assert(sz == 0); } r = tor_tls_write(tls, data, sz); if (r < 0) return r; if (*buf_flushlen > (size_t)r) *buf_flushlen -= r; else *buf_flushlen = 0; buf_remove_from_front(buf, r); log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.", r,(int)*buf_flushlen,(int)buf->datalen); return r; } /** Write data from buf to the socket s. Write at most * sz bytes, decrement *buf_flushlen by * the number of bytes actually written, and remove the written bytes * from the buffer. Return the number of bytes written on success, * -1 on failure. Return 0 if write() would block. */ int flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen) { /* XXXX024 It's stupid to overload the return values for these functions: * "error status" and "number of bytes flushed" are not mutually exclusive. */ int r; size_t flushed = 0; tor_assert(buf_flushlen); tor_assert(SOCKET_OK(s)); tor_assert(*buf_flushlen <= buf->datalen); tor_assert(sz <= *buf_flushlen); check(); while (sz) { size_t flushlen0; tor_assert(buf->head); if (buf->head->datalen >= sz) flushlen0 = sz; else flushlen0 = buf->head->datalen; r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen); check(); if (r < 0) return r; flushed += r; sz -= r; if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */ break; } tor_assert(flushed < INT_MAX); return (int)flushed; } /** As flush_buf(), but writes data to a TLS connection. Can write more than * flushlen bytes. */ int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t flushlen, size_t *buf_flushlen) { int r; size_t flushed = 0; ssize_t sz; tor_assert(buf_flushlen); tor_assert(*buf_flushlen <= buf->datalen); tor_assert(flushlen <= *buf_flushlen); sz = (ssize_t) flushlen; /* we want to let tls write even if flushlen is zero, because it might * have a partial record pending */ check_no_tls_errors(); check(); do { size_t flushlen0; if (buf->head) { if ((ssize_t)buf->head->datalen >= sz) flushlen0 = sz; else flushlen0 = buf->head->datalen; } else { flushlen0 = 0; } r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen); check(); if (r < 0) return r; flushed += r; sz -= r; if (r == 0) /* Can't flush any more now. */ break; } while (sz > 0); tor_assert(flushed < INT_MAX); return (int)flushed; } /** Append string_len bytes from string to the end of * buf. * * Return the new length of the buffer on success, -1 on failure. */ int write_to_buf(const char *string, size_t string_len, buf_t *buf) { if (!string_len) return (int)buf->datalen; check(); while (string_len) { size_t copy; if (!buf->tail || !CHUNK_REMAINING_CAPACITY(buf->tail)) buf_add_chunk_with_capacity(buf, string_len, 1); copy = CHUNK_REMAINING_CAPACITY(buf->tail); if (copy > string_len) copy = string_len; memcpy(CHUNK_WRITE_PTR(buf->tail), string, copy); string_len -= copy; string += copy; buf->datalen += copy; buf->tail->datalen += copy; } check(); tor_assert(buf->datalen < INT_MAX); return (int)buf->datalen; } /** Helper: copy the first string_len bytes from buf * onto string. */ static INLINE void peek_from_buf(char *string, size_t string_len, const buf_t *buf) { chunk_t *chunk; tor_assert(string); /* make sure we don't ask for too much */ tor_assert(string_len <= buf->datalen); /* assert_buf_ok(buf); */ chunk = buf->head; while (string_len) { size_t copy = string_len; tor_assert(chunk); if (chunk->datalen < copy) copy = chunk->datalen; memcpy(string, chunk->data, copy); string_len -= copy; string += copy; chunk = chunk->next; } } /** Remove string_len bytes from the front of buf, and store * them into string. Return the new buffer size. string_len * must be \<= the number of bytes on the buffer. */ int fetch_from_buf(char *string, size_t string_len, buf_t *buf) { /* There must be string_len bytes in buf; write them onto string, * then memmove buf back (that is, remove them from buf). * * Return the number of bytes still on the buffer. */ check(); peek_from_buf(string, string_len, buf); buf_remove_from_front(buf, string_len); check(); tor_assert(buf->datalen < INT_MAX); return (int)buf->datalen; } /** True iff the cell command command is one that implies a * variable-length cell in Tor link protocol linkproto. */ static INLINE int cell_command_is_var_length(uint8_t command, int linkproto) { /* If linkproto is v2 (2), CELL_VERSIONS is the only variable-length cells * work as implemented here. If it's 1, there are no variable-length cells. * Tor does not support other versions right now, and so can't negotiate * them. */ switch (linkproto) { case 1: /* Link protocol version 1 has no variable-length cells. */ return 0; case 2: /* In link protocol version 2, VERSIONS is the only variable-length cell */ return command == CELL_VERSIONS; case 0: case 3: default: /* In link protocol version 3 and later, and in version "unknown", * commands 128 and higher indicate variable-length. VERSIONS is * grandfathered in. */ return command == CELL_VERSIONS || command >= 128; } } /** Check buf for a variable-length cell according to the rules of link * protocol version linkproto. If one is found, pull it off the buffer * and assign a newly allocated var_cell_t to *out, and return 1. * Return 0 if whatever is on the start of buf_t is not a variable-length * cell. Return 1 and set *out to NULL if there seems to be the start * of a variable-length cell on buf, but the whole thing isn't there * yet. */ int fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto) { char hdr[VAR_CELL_MAX_HEADER_SIZE]; var_cell_t *result; uint8_t command; uint16_t length; const int wide_circ_ids = linkproto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS; const int circ_id_len = get_circ_id_size(wide_circ_ids); const unsigned header_len = get_var_cell_header_size(wide_circ_ids); check(); *out = NULL; if (buf->datalen < header_len) return 0; peek_from_buf(hdr, header_len, buf); command = get_uint8(hdr + circ_id_len); if (!(cell_command_is_var_length(command, linkproto))) return 0; length = ntohs(get_uint16(hdr + circ_id_len + 1)); if (buf->datalen < (size_t)(header_len+length)) return 1; result = var_cell_new(length); result->command = command; if (wide_circ_ids) result->circ_id = ntohl(get_uint32(hdr)); else result->circ_id = ntohs(get_uint16(hdr)); buf_remove_from_front(buf, header_len); peek_from_buf((char*) result->payload, length, buf); buf_remove_from_front(buf, length); check(); *out = result; return 1; } #ifdef USE_BUFFEREVENTS /** Try to read n bytes from buf at pos (which may be * NULL for the start of the buffer), copying the data only if necessary. Set * *data_out to a pointer to the desired bytes. Set free_out * to 1 if we needed to malloc *data because the original bytes were * noncontiguous; 0 otherwise. Return the number of bytes actually available * at *data_out. */ static ssize_t inspect_evbuffer(struct evbuffer *buf, char **data_out, size_t n, int *free_out, struct evbuffer_ptr *pos) { int n_vecs, i; if (evbuffer_get_length(buf) < n) n = evbuffer_get_length(buf); if (n == 0) return 0; n_vecs = evbuffer_peek(buf, n, pos, NULL, 0); tor_assert(n_vecs > 0); if (n_vecs == 1) { struct evbuffer_iovec v; i = evbuffer_peek(buf, n, pos, &v, 1); tor_assert(i == 1); *data_out = v.iov_base; *free_out = 0; return v.iov_len; } else { ev_ssize_t copied; *data_out = tor_malloc(n); *free_out = 1; copied = evbuffer_copyout(buf, *data_out, n); tor_assert(copied >= 0 && (size_t)copied == n); return copied; } } /** As fetch_var_cell_from_buf, buf works on an evbuffer. */ int fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out, int linkproto) { char *hdr = NULL; int free_hdr = 0; size_t n; size_t buf_len; uint8_t command; uint16_t cell_length; var_cell_t *cell; int result = 0; const int wide_circ_ids = linkproto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS; const int circ_id_len = get_circ_id_size(wide_circ_ids); const unsigned header_len = get_var_cell_header_size(wide_circ_ids); *out = NULL; buf_len = evbuffer_get_length(buf); if (buf_len < header_len) return 0; n = inspect_evbuffer(buf, &hdr, header_len, &free_hdr, NULL); tor_assert(n >= header_len); command = get_uint8(hdr + circ_id_len); if (!(cell_command_is_var_length(command, linkproto))) { goto done; } cell_length = ntohs(get_uint16(hdr + circ_id_len + 1)); if (buf_len < (size_t)(header_len+cell_length)) { result = 1; /* Not all here yet. */ goto done; } cell = var_cell_new(cell_length); cell->command = command; if (wide_circ_ids) cell->circ_id = ntohl(get_uint32(hdr)); else cell->circ_id = ntohs(get_uint16(hdr)); evbuffer_drain(buf, header_len); evbuffer_remove(buf, cell->payload, cell_length); *out = cell; result = 1; done: if (free_hdr && hdr) tor_free(hdr); return result; } #endif /** Move up to *buf_flushlen bytes from buf_in to * buf_out, and modify *buf_flushlen appropriately. * Return the number of bytes actually copied. */ int move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen) { /* We can do way better here, but this doesn't turn up in any profiles. */ char b[4096]; size_t cp, len; len = *buf_flushlen; if (len > buf_in->datalen) len = buf_in->datalen; cp = len; /* Remember the number of bytes we intend to copy. */ tor_assert(cp < INT_MAX); while (len) { /* This isn't the most efficient implementation one could imagine, since * it does two copies instead of 1, but I kinda doubt that this will be * critical path. */ size_t n = len > sizeof(b) ? sizeof(b) : len; fetch_from_buf(b, n, buf_in); write_to_buf(b, n, buf_out); len -= n; } *buf_flushlen -= cp; return (int)cp; } /** Internal structure: represents a position in a buffer. */ typedef struct buf_pos_t { const chunk_t *chunk; /**< Which chunk are we pointing to? */ int pos;/**< Which character inside the chunk's data are we pointing to? */ size_t chunk_pos; /**< Total length of all previous chunks. */ } buf_pos_t; /** Initialize out to point to the first character of buf.*/ static void buf_pos_init(const buf_t *buf, buf_pos_t *out) { out->chunk = buf->head; out->pos = 0; out->chunk_pos = 0; } /** Advance out to the first appearance of ch at the current * position of out, or later. Return -1 if no instances are found; * otherwise returns the absolute position of the character. */ static off_t buf_find_pos_of_char(char ch, buf_pos_t *out) { const chunk_t *chunk; int pos; tor_assert(out); if (out->chunk) { if (out->chunk->datalen) { tor_assert(out->pos < (off_t)out->chunk->datalen); } else { tor_assert(out->pos == 0); } } pos = out->pos; for (chunk = out->chunk; chunk; chunk = chunk->next) { char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos); if (cp) { out->chunk = chunk; tor_assert(cp - chunk->data < INT_MAX); out->pos = (int)(cp - chunk->data); return out->chunk_pos + out->pos; } else { out->chunk_pos += chunk->datalen; pos = 0; } } return -1; } /** Advance pos by a single character, if there are any more characters * in the buffer. Returns 0 on success, -1 on failure. */ static INLINE int buf_pos_inc(buf_pos_t *pos) { ++pos->pos; if (pos->pos == (off_t)pos->chunk->datalen) { if (!pos->chunk->next) return -1; pos->chunk_pos += pos->chunk->datalen; pos->chunk = pos->chunk->next; pos->pos = 0; } return 0; } /** Return true iff the n-character string in s appears * (verbatim) at pos. */ static int buf_matches_at_pos(const buf_pos_t *pos, const char *s, size_t n) { buf_pos_t p; if (!n) return 1; memcpy(&p, pos, sizeof(p)); while (1) { char ch = p.chunk->data[p.pos]; if (ch != *s) return 0; ++s; /* If we're out of characters that don't match, we match. Check this * _before_ we test incrementing pos, in case we're at the end of the * string. */ if (--n == 0) return 1; if (buf_pos_inc(&p)<0) return 0; } } /** Return the first position in buf at which the n-character * string s occurs, or -1 if it does not occur. */ /*private*/ int buf_find_string_offset(const buf_t *buf, const char *s, size_t n) { buf_pos_t pos; buf_pos_init(buf, &pos); while (buf_find_pos_of_char(*s, &pos) >= 0) { if (buf_matches_at_pos(&pos, s, n)) { tor_assert(pos.chunk_pos + pos.pos < INT_MAX); return (int)(pos.chunk_pos + pos.pos); } else { if (buf_pos_inc(&pos)<0) return -1; } } return -1; } /** There is a (possibly incomplete) http statement on buf, of the * form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain NULs.) * If a) the headers include a Content-Length field and all bytes in * the body are present, or b) there's no Content-Length field and * all headers are present, then: * * - strdup headers into *headers_out, and NUL-terminate it. * - memdup body into *body_out, and NUL-terminate it. * - Then remove them from buf, and return 1. * * - If headers or body is NULL, discard that part of the buf. * - If a headers or body doesn't fit in the arg, return -1. * (We ensure that the headers or body don't exceed max len, * _even if_ we're planning to discard them.) * - If force_complete is true, then succeed even if not all of the * content has arrived. * * Else, change nothing and return 0. */ int fetch_from_buf_http(buf_t *buf, char **headers_out, size_t max_headerlen, char **body_out, size_t *body_used, size_t max_bodylen, int force_complete) { char *headers, *p; size_t headerlen, bodylen, contentlen; int crlf_offset; check(); if (!buf->head) return 0; crlf_offset = buf_find_string_offset(buf, "\r\n\r\n", 4); if (crlf_offset > (int)max_headerlen || (crlf_offset < 0 && buf->datalen > max_headerlen)) { log_debug(LD_HTTP,"headers too long."); return -1; } else if (crlf_offset < 0) { log_debug(LD_HTTP,"headers not all here yet."); return 0; } /* Okay, we have a full header. Make sure it all appears in the first * chunk. */ if ((int)buf->head->datalen < crlf_offset + 4) buf_pullup(buf, crlf_offset+4, 0); headerlen = crlf_offset + 4; headers = buf->head->data; bodylen = buf->datalen - headerlen; log_debug(LD_HTTP,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen); if (max_headerlen <= headerlen) { log_warn(LD_HTTP,"headerlen %d larger than %d. Failing.", (int)headerlen, (int)max_headerlen-1); return -1; } if (max_bodylen <= bodylen) { log_warn(LD_HTTP,"bodylen %d larger than %d. Failing.", (int)bodylen, (int)max_bodylen-1); return -1; } #define CONTENT_LENGTH "\r\nContent-Length: " p = (char*) tor_memstr(headers, headerlen, CONTENT_LENGTH); if (p) { int i; i = atoi(p+strlen(CONTENT_LENGTH)); if (i < 0) { log_warn(LD_PROTOCOL, "Content-Length is less than zero; it looks like " "someone is trying to crash us."); return -1; } contentlen = i; /* if content-length is malformed, then our body length is 0. fine. */ log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen); if (bodylen < contentlen) { if (!force_complete) { log_debug(LD_HTTP,"body not all here yet."); return 0; /* not all there yet */ } } if (bodylen > contentlen) { bodylen = contentlen; log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen); } } /* all happy. copy into the appropriate places, and return 1 */ if (headers_out) { *headers_out = tor_malloc(headerlen+1); fetch_from_buf(*headers_out, headerlen, buf); (*headers_out)[headerlen] = 0; /* NUL terminate it */ } if (body_out) { tor_assert(body_used); *body_used = bodylen; *body_out = tor_malloc(bodylen+1); fetch_from_buf(*body_out, bodylen, buf); (*body_out)[bodylen] = 0; /* NUL terminate it */ } check(); return 1; } #ifdef USE_BUFFEREVENTS /** As fetch_from_buf_http, buf works on an evbuffer. */ int fetch_from_evbuffer_http(struct evbuffer *buf, char **headers_out, size_t max_headerlen, char **body_out, size_t *body_used, size_t max_bodylen, int force_complete) { struct evbuffer_ptr crlf, content_length; size_t headerlen, bodylen, contentlen; /* Find the first \r\n\r\n in the buffer */ crlf = evbuffer_search(buf, "\r\n\r\n", 4, NULL); if (crlf.pos < 0) { /* We didn't find one. */ if (evbuffer_get_length(buf) > max_headerlen) return -1; /* Headers too long. */ return 0; /* Headers not here yet. */ } else if (crlf.pos > (int)max_headerlen) { return -1; /* Headers too long. */ } headerlen = crlf.pos + 4; /* Skip over the \r\n\r\n */ bodylen = evbuffer_get_length(buf) - headerlen; if (bodylen > max_bodylen) return -1; /* body too long */ /* Look for the first occurrence of CONTENT_LENGTH insize buf before the * crlfcrlf */ content_length = evbuffer_search_range(buf, CONTENT_LENGTH, strlen(CONTENT_LENGTH), NULL, &crlf); if (content_length.pos >= 0) { /* We found a content_length: parse it and figure out if the body is here * yet. */ struct evbuffer_ptr eol; char *data = NULL; int free_data = 0; int n, i; n = evbuffer_ptr_set(buf, &content_length, strlen(CONTENT_LENGTH), EVBUFFER_PTR_ADD); tor_assert(n == 0); eol = evbuffer_search_eol(buf, &content_length, NULL, EVBUFFER_EOL_CRLF); tor_assert(eol.pos > content_length.pos); tor_assert(eol.pos <= crlf.pos); inspect_evbuffer(buf, &data, eol.pos - content_length.pos, &free_data, &content_length); i = atoi(data); if (free_data) tor_free(data); if (i < 0) { log_warn(LD_PROTOCOL, "Content-Length is less than zero; it looks like " "someone is trying to crash us."); return -1; } contentlen = i; /* if content-length is malformed, then our body length is 0. fine. */ log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen); if (bodylen < contentlen) { if (!force_complete) { log_debug(LD_HTTP,"body not all here yet."); return 0; /* not all there yet */ } } if (bodylen > contentlen) { bodylen = contentlen; log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen); } } if (headers_out) { *headers_out = tor_malloc(headerlen+1); evbuffer_remove(buf, *headers_out, headerlen); (*headers_out)[headerlen] = '\0'; } if (body_out) { tor_assert(headers_out); tor_assert(body_used); *body_used = bodylen; *body_out = tor_malloc(bodylen+1); evbuffer_remove(buf, *body_out, bodylen); (*body_out)[bodylen] = '\0'; } return 1; } #endif /** * Wait this many seconds before warning the user about using SOCKS unsafely * again (requires that WarnUnsafeSocks is turned on). */ #define SOCKS_WARN_INTERVAL 5 /** Warn that the user application has made an unsafe socks request using * protocol socks_protocol on port port. Don't warn more than * once per SOCKS_WARN_INTERVAL, unless safe_socks is set. */ static void log_unsafe_socks_warning(int socks_protocol, const char *address, uint16_t port, int safe_socks) { static ratelim_t socks_ratelim = RATELIM_INIT(SOCKS_WARN_INTERVAL); const or_options_t *options = get_options(); if (! options->WarnUnsafeSocks) return; if (safe_socks) { log_fn_ratelim(&socks_ratelim, LOG_WARN, LD_APP, "Your application (using socks%d to port %d) is giving " "Tor only an IP address. Applications that do DNS resolves " "themselves may leak information. Consider using Socks4A " "(e.g. via privoxy or socat) instead. For more information, " "please see https://wiki.torproject.org/TheOnionRouter/" "TorFAQ#SOCKSAndDNS.%s", socks_protocol, (int)port, safe_socks ? " Rejecting." : ""); } control_event_client_status(LOG_WARN, "DANGEROUS_SOCKS PROTOCOL=SOCKS%d ADDRESS=%s:%d", socks_protocol, address, (int)port); } /** Do not attempt to parse socks messages longer than this. This value is * actually significantly higher than the longest possible socks message. */ #define MAX_SOCKS_MESSAGE_LEN 512 /** Return a new socks_request_t. */ socks_request_t * socks_request_new(void) { return tor_malloc_zero(sizeof(socks_request_t)); } /** Free all storage held in the socks_request_t req. */ void socks_request_free(socks_request_t *req) { if (!req) return; if (req->username) { memwipe(req->username, 0x10, req->usernamelen); tor_free(req->username); } if (req->password) { memwipe(req->password, 0x04, req->passwordlen); tor_free(req->password); } memwipe(req, 0xCC, sizeof(socks_request_t)); tor_free(req); } /** There is a (possibly incomplete) socks handshake on buf, of one * of the forms * - socks4: "socksheader username\\0" * - socks4a: "socksheader username\\0 destaddr\\0" * - socks5 phase one: "version #methods methods" * - socks5 phase two: "version command 0 addresstype..." * If it's a complete and valid handshake, and destaddr fits in * MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf, * assign to req, and return 1. * * If it's invalid or too big, return -1. * * Else it's not all there yet, leave buf alone and return 0. * * If you want to specify the socks reply, write it into req->reply * and set req->replylen, else leave req->replylen alone. * * If log_sockstype is non-zero, then do a notice-level log of whether * the connection is possibly leaking DNS requests locally or not. * * If safe_socks is true, then reject unsafe socks protocols. * * If returning 0 or -1, req->address and req->port are * undefined. */ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req, int log_sockstype, int safe_socks) { int res; ssize_t n_drain; size_t want_length = 128; if (buf->datalen < 2) /* version and another byte */ return 0; do { n_drain = 0; buf_pullup(buf, want_length, 0); tor_assert(buf->head && buf->head->datalen >= 2); want_length = 0; res = parse_socks(buf->head->data, buf->head->datalen, req, log_sockstype, safe_socks, &n_drain, &want_length); if (n_drain < 0) buf_clear(buf); else if (n_drain > 0) buf_remove_from_front(buf, n_drain); } while (res == 0 && buf->head && want_length < buf->datalen && buf->datalen >= 2); return res; } #ifdef USE_BUFFEREVENTS /* As fetch_from_buf_socks(), but targets an evbuffer instead. */ int fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req, int log_sockstype, int safe_socks) { char *data; ssize_t n_drain; size_t datalen, buflen, want_length; int res; buflen = evbuffer_get_length(buf); if (buflen < 2) return 0; { /* See if we can find the socks request in the first chunk of the buffer. */ struct evbuffer_iovec v; int i; n_drain = 0; i = evbuffer_peek(buf, -1, NULL, &v, 1); tor_assert(i == 1); data = v.iov_base; datalen = v.iov_len; want_length = 0; res = parse_socks(data, datalen, req, log_sockstype, safe_socks, &n_drain, &want_length); if (n_drain < 0) evbuffer_drain(buf, evbuffer_get_length(buf)); else if (n_drain > 0) evbuffer_drain(buf, n_drain); if (res) return res; } /* Okay, the first chunk of the buffer didn't have a complete socks request. * That means that either we don't have a whole socks request at all, or * it's gotten split up. We're going to try passing parse_socks() bigger * and bigger chunks until either it says "Okay, I got it", or it says it * will need more data than we currently have. */ /* Loop while we have more data that we haven't given parse_socks() yet. */ do { int free_data = 0; const size_t last_wanted = want_length; n_drain = 0; data = NULL; datalen = inspect_evbuffer(buf, &data, want_length, &free_data, NULL); want_length = 0; res = parse_socks(data, datalen, req, log_sockstype, safe_socks, &n_drain, &want_length); if (free_data) tor_free(data); if (n_drain < 0) evbuffer_drain(buf, evbuffer_get_length(buf)); else if (n_drain > 0) evbuffer_drain(buf, n_drain); if (res == 0 && n_drain == 0 && want_length <= last_wanted) { /* If we drained nothing, and we didn't ask for more than last time, * then we probably wanted more data than the buffer actually had, * and we're finding out that we're not satisified with it. It's * time to break until we have more data. */ break; } buflen = evbuffer_get_length(buf); } while (res == 0 && want_length <= buflen && buflen >= 2); return res; } #endif /** Implementation helper to implement fetch_from_*_socks. Instead of looking * at a buffer's contents, we look at the datalen bytes of data in * data. Instead of removing data from the buffer, we set * drain_out to the amount of data that should be removed (or -1 if the * buffer should be cleared). Instead of pulling more data into the first * chunk of the buffer, we set *want_length_out to the number of bytes * we'd like to see in the input buffer, if they're available. */ static int parse_socks(const char *data, size_t datalen, socks_request_t *req, int log_sockstype, int safe_socks, ssize_t *drain_out, size_t *want_length_out) { unsigned int len; char tmpbuf[TOR_ADDR_BUF_LEN+1]; tor_addr_t destaddr; uint32_t destip; uint8_t socksver; char *next, *startaddr; unsigned char usernamelen, passlen; struct in_addr in; if (datalen < 2) { /* We always need at least 2 bytes. */ *want_length_out = 2; return 0; } if (req->socks_version == 5 && !req->got_auth) { /* See if we have received authentication. Strictly speaking, we should also check whether we actually negotiated username/password authentication. But some broken clients will send us authentication even if we negotiated SOCKS_NO_AUTH. */ if (*data == 1) { /* username/pass version 1 */ /* Format is: authversion [1 byte] == 1 usernamelen [1 byte] username [usernamelen bytes] passlen [1 byte] password [passlen bytes] */ usernamelen = (unsigned char)*(data + 1); if (datalen < 2u + usernamelen + 1u) { *want_length_out = 2u + usernamelen + 1u; return 0; } passlen = (unsigned char)*(data + 2u + usernamelen); if (datalen < 2u + usernamelen + 1u + passlen) { *want_length_out = 2u + usernamelen + 1u + passlen; return 0; } req->replylen = 2; /* 2 bytes of response */ req->reply[0] = 1; /* authversion == 1 */ req->reply[1] = 0; /* authentication successful */ log_debug(LD_APP, "socks5: Accepted username/password without checking."); if (usernamelen) { req->username = tor_memdup(data+2u, usernamelen); req->usernamelen = usernamelen; } if (passlen) { req->password = tor_memdup(data+3u+usernamelen, passlen); req->passwordlen = passlen; } *drain_out = 2u + usernamelen + 1u + passlen; req->got_auth = 1; *want_length_out = 7; /* Minimal socks5 sommand. */ return 0; } else if (req->auth_type == SOCKS_USER_PASS) { /* unknown version byte */ log_warn(LD_APP, "Socks5 username/password version %d not recognized; " "rejecting.", (int)*data); return -1; } } socksver = *data; switch (socksver) { /* which version of socks? */ case 5: /* socks5 */ if (req->socks_version != 5) { /* we need to negotiate a method */ unsigned char nummethods = (unsigned char)*(data+1); int have_user_pass, have_no_auth; int r=0; tor_assert(!req->socks_version); if (datalen < 2u+nummethods) { *want_length_out = 2u+nummethods; return 0; } if (!nummethods) return -1; req->replylen = 2; /* 2 bytes of response */ req->reply[0] = 5; /* socks5 reply */ have_user_pass = (memchr(data+2, SOCKS_USER_PASS, nummethods) !=NULL); have_no_auth = (memchr(data+2, SOCKS_NO_AUTH, nummethods) !=NULL); if (have_user_pass && !(have_no_auth && req->socks_prefer_no_auth)) { req->auth_type = SOCKS_USER_PASS; req->reply[1] = SOCKS_USER_PASS; /* tell client to use "user/pass" auth method */ req->socks_version = 5; /* remember we've already negotiated auth */ log_debug(LD_APP,"socks5: accepted method 2 (username/password)"); r=0; } else if (have_no_auth) { req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth method */ req->socks_version = 5; /* remember we've already negotiated auth */ log_debug(LD_APP,"socks5: accepted method 0 (no authentication)"); r=0; } else { log_warn(LD_APP, "socks5: offered methods don't include 'no auth' or " "username/password. Rejecting."); req->reply[1] = '\xFF'; /* reject all methods */ r=-1; } /* Remove packet from buf. Some SOCKS clients will have sent extra * junk at this point; let's hope it's an authentication message. */ *drain_out = 2u + nummethods; return r; } if (req->auth_type != SOCKS_NO_AUTH && !req->got_auth) { log_warn(LD_APP, "socks5: negotiated authentication, but none provided"); return -1; } /* we know the method; read in the request */ log_debug(LD_APP,"socks5: checking request"); if (datalen < 7) {/* basic info plus >=1 for addr plus 2 for port */ *want_length_out = 7; return 0; /* not yet */ } req->command = (unsigned char) *(data+1); if (req->command != SOCKS_COMMAND_CONNECT && req->command != SOCKS_COMMAND_RESOLVE && req->command != SOCKS_COMMAND_RESOLVE_PTR) { /* not a connect or resolve or a resolve_ptr? we don't support it. */ log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.", req->command); return -1; } switch (*(data+3)) { /* address type */ case 1: /* IPv4 address */ case 4: /* IPv6 address */ { const int is_v6 = *(data+3) == 4; const unsigned addrlen = is_v6 ? 16 : 4; log_debug(LD_APP,"socks5: ipv4 address type"); if (datalen < 6+addrlen) {/* ip/port there? */ *want_length_out = 6+addrlen; return 0; /* not yet */ } if (is_v6) tor_addr_from_ipv6_bytes(&destaddr, data+4); else tor_addr_from_ipv4n(&destaddr, get_uint32(data+4)); tor_addr_to_str(tmpbuf, &destaddr, sizeof(tmpbuf), 1); if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) { log_warn(LD_APP, "socks5 IP takes %d bytes, which doesn't fit in %d. " "Rejecting.", (int)strlen(tmpbuf)+1,(int)MAX_SOCKS_ADDR_LEN); return -1; } strlcpy(req->address,tmpbuf,sizeof(req->address)); req->port = ntohs(get_uint16(data+4+addrlen)); *drain_out = 6+addrlen; if (req->command != SOCKS_COMMAND_RESOLVE_PTR && !addressmap_have_mapping(req->address,0)) { log_unsafe_socks_warning(5, req->address, req->port, safe_socks); if (safe_socks) return -1; } return 1; } case 3: /* fqdn */ log_debug(LD_APP,"socks5: fqdn address type"); if (req->command == SOCKS_COMMAND_RESOLVE_PTR) { log_warn(LD_APP, "socks5 received RESOLVE_PTR command with " "hostname type. Rejecting."); return -1; } len = (unsigned char)*(data+4); if (datalen < 7+len) { /* addr/port there? */ *want_length_out = 7+len; return 0; /* not yet */ } if (len+1 > MAX_SOCKS_ADDR_LEN) { log_warn(LD_APP, "socks5 hostname is %d bytes, which doesn't fit in " "%d. Rejecting.", len+1,MAX_SOCKS_ADDR_LEN); return -1; } memcpy(req->address,data+5,len); req->address[len] = 0; req->port = ntohs(get_uint16(data+5+len)); *drain_out = 5+len+2; if (!tor_strisprint(req->address) || strchr(req->address,'\"')) { log_warn(LD_PROTOCOL, "Your application (using socks5 to port %d) gave Tor " "a malformed hostname: %s. Rejecting the connection.", req->port, escaped(req->address)); return -1; } if (log_sockstype) log_notice(LD_APP, "Your application (using socks5 to port %d) instructed " "Tor to take care of the DNS resolution itself if " "necessary. This is good.", req->port); return 1; default: /* unsupported */ log_warn(LD_APP,"socks5: unsupported address type %d. Rejecting.", (int) *(data+3)); return -1; } tor_assert(0); case 4: { /* socks4 */ enum {socks4, socks4a} socks4_prot = socks4a; const char *authstart, *authend; /* http://ss5.sourceforge.net/socks4.protocol.txt */ /* http://ss5.sourceforge.net/socks4A.protocol.txt */ req->socks_version = 4; if (datalen < SOCKS4_NETWORK_LEN) {/* basic info available? */ *want_length_out = SOCKS4_NETWORK_LEN; return 0; /* not yet */ } // buf_pullup(buf, 1280, 0); req->command = (unsigned char) *(data+1); if (req->command != SOCKS_COMMAND_CONNECT && req->command != SOCKS_COMMAND_RESOLVE) { /* not a connect or resolve? we don't support it. (No resolve_ptr with * socks4.) */ log_warn(LD_APP,"socks4: command %d not recognized. Rejecting.", req->command); return -1; } req->port = ntohs(get_uint16(data+2)); destip = ntohl(get_uint32(data+4)); if ((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) { log_warn(LD_APP,"socks4: Port or DestIP is zero. Rejecting."); return -1; } if (destip >> 8) { log_debug(LD_APP,"socks4: destip not in form 0.0.0.x."); in.s_addr = htonl(destip); tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf)); if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) { log_debug(LD_APP,"socks4 addr (%d bytes) too long. Rejecting.", (int)strlen(tmpbuf)); return -1; } log_debug(LD_APP, "socks4: successfully read destip (%s)", safe_str_client(tmpbuf)); socks4_prot = socks4; } authstart = data + SOCKS4_NETWORK_LEN; next = memchr(authstart, 0, datalen-SOCKS4_NETWORK_LEN); if (!next) { if (datalen >= 1024) { log_debug(LD_APP, "Socks4 user name too long; rejecting."); return -1; } log_debug(LD_APP,"socks4: Username not here yet."); *want_length_out = datalen+1024; /* More than we need, but safe */ return 0; } authend = next; tor_assert(next < data+datalen); startaddr = NULL; if (socks4_prot != socks4a && !addressmap_have_mapping(tmpbuf,0)) { log_unsafe_socks_warning(4, tmpbuf, req->port, safe_socks); if (safe_socks) return -1; } if (socks4_prot == socks4a) { if (next+1 == data+datalen) { log_debug(LD_APP,"socks4: No part of destaddr here yet."); *want_length_out = datalen + 1024; /* More than we need, but safe */ return 0; } startaddr = next+1; next = memchr(startaddr, 0, data + datalen - startaddr); if (!next) { if (datalen >= 1024) { log_debug(LD_APP,"socks4: Destaddr too long."); return -1; } log_debug(LD_APP,"socks4: Destaddr not all here yet."); *want_length_out = datalen + 1024; /* More than we need, but safe */ return 0; } if (MAX_SOCKS_ADDR_LEN <= next-startaddr) { log_warn(LD_APP,"socks4: Destaddr too long. Rejecting."); return -1; } // tor_assert(next < buf->cur+buf->datalen); if (log_sockstype) log_notice(LD_APP, "Your application (using socks4a to port %d) instructed " "Tor to take care of the DNS resolution itself if " "necessary. This is good.", req->port); } log_debug(LD_APP,"socks4: Everything is here. Success."); strlcpy(req->address, startaddr ? startaddr : tmpbuf, sizeof(req->address)); if (!tor_strisprint(req->address) || strchr(req->address,'\"')) { log_warn(LD_PROTOCOL, "Your application (using socks4 to port %d) gave Tor " "a malformed hostname: %s. Rejecting the connection.", req->port, escaped(req->address)); return -1; } if (authend != authstart) { req->got_auth = 1; req->usernamelen = authend - authstart; req->username = tor_memdup(authstart, authend - authstart); } /* next points to the final \0 on inbuf */ *drain_out = next - data + 1; return 1; } case 'G': /* get */ case 'H': /* head */ case 'P': /* put/post */ case 'C': /* connect */ strlcpy((char*)req->reply, "HTTP/1.0 501 Tor is not an HTTP Proxy\r\n" "Content-Type: text/html; charset=iso-8859-1\r\n\r\n" "\n" "\n" "Tor is not an HTTP Proxy\n" "\n" "\n" "

Tor is not an HTTP Proxy

\n" "

\n" "It appears you have configured your web browser to use Tor as an HTTP proxy." "\n" "This is not correct: Tor is a SOCKS proxy, not an HTTP proxy.\n" "Please configure your client accordingly.\n" "

\n" "

\n" "See " "https://www.torproject.org/documentation.html for more " "information.\n" "\n" "

\n" "\n" "\n" , MAX_SOCKS_REPLY_LEN); req->replylen = strlen((char*)req->reply)+1; /* fall through */ default: /* version is not socks4 or socks5 */ log_warn(LD_APP, "Socks version %d not recognized. (Tor is not an http proxy.)", *(data)); { /* Tell the controller the first 8 bytes. */ char *tmp = tor_strndup(data, datalen < 8 ? datalen : 8); control_event_client_status(LOG_WARN, "SOCKS_UNKNOWN_PROTOCOL DATA=\"%s\"", escaped(tmp)); tor_free(tmp); } return -1; } } /** Inspect a reply from SOCKS server stored in buf according * to state, removing the protocol data upon success. Return 0 on * incomplete response, 1 on success and -1 on error, in which case * reason is set to a descriptive message (free() when finished * with it). * * As a special case, 2 is returned when user/pass is required * during SOCKS5 handshake and user/pass is configured. */ int fetch_from_buf_socks_client(buf_t *buf, int state, char **reason) { ssize_t drain = 0; int r; if (buf->datalen < 2) return 0; buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN, 0); tor_assert(buf->head && buf->head->datalen >= 2); r = parse_socks_client((uint8_t*)buf->head->data, buf->head->datalen, state, reason, &drain); if (drain > 0) buf_remove_from_front(buf, drain); else if (drain < 0) buf_clear(buf); return r; } #ifdef USE_BUFFEREVENTS /** As fetch_from_buf_socks_client, buf works on an evbuffer */ int fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state, char **reason) { ssize_t drain = 0; uint8_t *data; size_t datalen; int r; /* Linearize the SOCKS response in the buffer, up to 128 bytes. * (parse_socks_client shouldn't need to see anything beyond that.) */ datalen = evbuffer_get_length(buf); if (datalen > MAX_SOCKS_MESSAGE_LEN) datalen = MAX_SOCKS_MESSAGE_LEN; data = evbuffer_pullup(buf, datalen); r = parse_socks_client(data, datalen, state, reason, &drain); if (drain > 0) evbuffer_drain(buf, drain); else if (drain < 0) evbuffer_drain(buf, evbuffer_get_length(buf)); return r; } #endif /** Implementation logic for fetch_from_*_socks_client. */ static int parse_socks_client(const uint8_t *data, size_t datalen, int state, char **reason, ssize_t *drain_out) { unsigned int addrlen; *drain_out = 0; if (datalen < 2) return 0; switch (state) { case PROXY_SOCKS4_WANT_CONNECT_OK: /* Wait for the complete response */ if (datalen < 8) return 0; if (data[1] != 0x5a) { *reason = tor_strdup(socks4_response_code_to_string(data[1])); return -1; } /* Success */ *drain_out = 8; return 1; case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE: /* we don't have any credentials */ if (data[1] != 0x00) { *reason = tor_strdup("server doesn't support any of our " "available authentication methods"); return -1; } log_info(LD_NET, "SOCKS 5 client: continuing without authentication"); *drain_out = -1; return 1; case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929: /* we have a username and password. return 1 if we can proceed without * providing authentication, or 2 otherwise. */ switch (data[1]) { case 0x00: log_info(LD_NET, "SOCKS 5 client: we have auth details but server " "doesn't require authentication."); *drain_out = -1; return 1; case 0x02: log_info(LD_NET, "SOCKS 5 client: need authentication."); *drain_out = -1; return 2; /* fall through */ } *reason = tor_strdup("server doesn't support any of our available " "authentication methods"); return -1; case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK: /* handle server reply to rfc1929 authentication */ if (data[1] != 0x00) { *reason = tor_strdup("authentication failed"); return -1; } log_info(LD_NET, "SOCKS 5 client: authentication successful."); *drain_out = -1; return 1; case PROXY_SOCKS5_WANT_CONNECT_OK: /* response is variable length. BND.ADDR, etc, isn't needed * (don't bother with buf_pullup()), but make sure to eat all * the data used */ /* wait for address type field to arrive */ if (datalen < 4) return 0; switch (data[3]) { case 0x01: /* ip4 */ addrlen = 4; break; case 0x04: /* ip6 */ addrlen = 16; break; case 0x03: /* fqdn (can this happen here?) */ if (datalen < 5) return 0; addrlen = 1 + data[4]; break; default: *reason = tor_strdup("invalid response to connect request"); return -1; } /* wait for address and port */ if (datalen < 6 + addrlen) return 0; if (data[1] != 0x00) { *reason = tor_strdup(socks5_response_code_to_string(data[1])); return -1; } *drain_out = 6 + addrlen; return 1; } /* shouldn't get here... */ tor_assert(0); return -1; } /** Return 1 iff buf looks more like it has an (obsolete) v0 controller * command on it than any valid v1 controller command. */ int peek_buf_has_control0_command(buf_t *buf) { if (buf->datalen >= 4) { char header[4]; uint16_t cmd; peek_from_buf(header, sizeof(header), buf); cmd = ntohs(get_uint16(header+2)); if (cmd <= 0x14) return 1; /* This is definitely not a v1 control command. */ } return 0; } #ifdef USE_BUFFEREVENTS int peek_evbuffer_has_control0_command(struct evbuffer *buf) { int result = 0; if (evbuffer_get_length(buf) >= 4) { int free_out = 0; char *data = NULL; size_t n = inspect_evbuffer(buf, &data, 4, &free_out, NULL); uint16_t cmd; tor_assert(n >= 4); cmd = ntohs(get_uint16(data+2)); if (cmd <= 0x14) result = 1; if (free_out) tor_free(data); } return result; } #endif /** Return the index within buf at which ch first appears, * or -1 if ch does not appear on buf. */ static off_t buf_find_offset_of_char(buf_t *buf, char ch) { chunk_t *chunk; off_t offset = 0; for (chunk = buf->head; chunk; chunk = chunk->next) { char *cp = memchr(chunk->data, ch, chunk->datalen); if (cp) return offset + (cp - chunk->data); else offset += chunk->datalen; } return -1; } /** Try to read a single LF-terminated line from buf, and write it * (including the LF), NUL-terminated, into the *data_len byte buffer * at data_out. Set *data_len to the number of bytes in the * line, not counting the terminating NUL. Return 1 if we read a whole line, * return 0 if we don't have a whole line yet, and return -1 if the line * length exceeds *data_len. */ int fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len) { size_t sz; off_t offset; if (!buf->head) return 0; offset = buf_find_offset_of_char(buf, '\n'); if (offset < 0) return 0; sz = (size_t) offset; if (sz+2 > *data_len) { *data_len = sz + 2; return -1; } fetch_from_buf(data_out, sz+1, buf); data_out[sz+1] = '\0'; *data_len = sz+1; return 1; } /** Compress on uncompress the data_len bytes in data using the * zlib state state, appending the result to buf. If * done is true, flush the data in the state and finish the * compression/uncompression. Return -1 on failure, 0 on success. */ int write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state, const char *data, size_t data_len, int done) { char *next; size_t old_avail, avail; int over = 0; do { int need_new_chunk = 0; if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) { size_t cap = data_len / 4; buf_add_chunk_with_capacity(buf, cap, 1); } next = CHUNK_WRITE_PTR(buf->tail); avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail); switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) { case TOR_ZLIB_DONE: over = 1; break; case TOR_ZLIB_ERR: return -1; case TOR_ZLIB_OK: if (data_len == 0) over = 1; break; case TOR_ZLIB_BUF_FULL: if (avail) { /* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk * automatically, whether were going to or not. */ need_new_chunk = 1; } break; } buf->datalen += old_avail - avail; buf->tail->datalen += old_avail - avail; if (need_new_chunk) { buf_add_chunk_with_capacity(buf, data_len/4, 1); } } while (!over); check(); return 0; } #ifdef USE_BUFFEREVENTS int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state, const char *data, size_t data_len, int done) { char *next; size_t old_avail, avail; int over = 0, n; struct evbuffer_iovec vec[1]; do { { size_t cap = data_len / 4; if (cap < 128) cap = 128; /* XXXX NM this strategy is fragmentation-prone. We should really have * two iovecs, and write first into the one, and then into the * second if the first gets full. */ n = evbuffer_reserve_space(buf, cap, vec, 1); tor_assert(n == 1); } next = vec[0].iov_base; avail = old_avail = vec[0].iov_len; switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) { case TOR_ZLIB_DONE: over = 1; break; case TOR_ZLIB_ERR: return -1; case TOR_ZLIB_OK: if (data_len == 0) over = 1; break; case TOR_ZLIB_BUF_FULL: if (avail) { /* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk * automatically, whether were going to or not. */ } break; } /* XXXX possible infinite loop on BUF_FULL. */ vec[0].iov_len = old_avail - avail; evbuffer_commit_space(buf, vec, 1); } while (!over); check(); return 0; } #endif /** Set *output to contain a copy of the data in *input */ int generic_buffer_set_to_copy(generic_buffer_t **output, const generic_buffer_t *input) { #ifdef USE_BUFFEREVENTS struct evbuffer_ptr ptr; size_t remaining = evbuffer_get_length(input); if (*output) { evbuffer_drain(*output, evbuffer_get_length(*output)); } else { if (!(*output = evbuffer_new())) return -1; } evbuffer_ptr_set((struct evbuffer*)input, &ptr, 0, EVBUFFER_PTR_SET); while (remaining) { struct evbuffer_iovec v[4]; int n_used, i; n_used = evbuffer_peek((struct evbuffer*)input, -1, &ptr, v, 4); if (n_used < 0) return -1; for (i=0;ibuf is corrupted. */ void assert_buf_ok(buf_t *buf) { tor_assert(buf); tor_assert(buf->magic == BUFFER_MAGIC); if (! buf->head) { tor_assert(!buf->tail); tor_assert(buf->datalen == 0); } else { chunk_t *ch; size_t total = 0; tor_assert(buf->tail); for (ch = buf->head; ch; ch = ch->next) { total += ch->datalen; tor_assert(ch->datalen <= ch->memlen); tor_assert(ch->data >= &ch->mem[0]); tor_assert(ch->data < &ch->mem[0]+ch->memlen); tor_assert(ch->data+ch->datalen <= &ch->mem[0] + ch->memlen); if (!ch->next) tor_assert(ch == buf->tail); } tor_assert(buf->datalen == total); } } #ifdef ENABLE_BUF_FREELISTS /** Log an error and exit if fl is corrupted. */ static void assert_freelist_ok(chunk_freelist_t *fl) { chunk_t *ch; int n; tor_assert(fl->alloc_size > 0); n = 0; for (ch = fl->head; ch; ch = ch->next) { tor_assert(CHUNK_ALLOC_SIZE(ch->memlen) == fl->alloc_size); ++n; } tor_assert(n == fl->cur_length); tor_assert(n >= fl->lowest_length); tor_assert(n <= fl->max_length); } #endif tor-0.2.4.20/src/or/entrynodes.h0000644000175000017500000001426212255745673013261 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file guardnodes.h * \brief Header file for circuitbuild.c. **/ #ifndef TOR_ENTRYNODES_H #define TOR_ENTRYNODES_H #if 1 /* XXXX NM I would prefer that all of this stuff be private to * entrynodes.c. */ /** An entry_guard_t represents our information about a chosen long-term * first hop, known as a "helper" node in the literature. We can't just * use a node_t, since we want to remember these even when we * don't have any directory info. */ typedef struct entry_guard_t { char nickname[MAX_NICKNAME_LEN+1]; char identity[DIGEST_LEN]; time_t chosen_on_date; /**< Approximately when was this guard added? * "0" if we don't know. */ char *chosen_by_version; /**< What tor version added this guard? NULL * if we don't know. */ unsigned int made_contact : 1; /**< 0 if we have never connected to this * router, 1 if we have. */ unsigned int can_retry : 1; /**< Should we retry connecting to this entry, * in spite of having it marked as unreachable?*/ unsigned int path_bias_noticed : 1; /**< Did we alert the user about path * bias for this node already? */ unsigned int path_bias_warned : 1; /**< Did we alert the user about path bias * for this node already? */ unsigned int path_bias_extreme : 1; /**< Did we alert the user about path * bias for this node already? */ unsigned int path_bias_disabled : 1; /**< Have we disabled this node because * of path bias issues? */ unsigned int path_bias_use_noticed : 1; /**< Did we alert the user about path * use bias for this node already? */ unsigned int path_bias_use_extreme : 1; /**< Did we alert the user about path * use bias for this node already? */ unsigned int is_dir_cache : 1; /**< Is this node a directory cache? */ time_t bad_since; /**< 0 if this guard is currently usable, or the time at * which it was observed to become (according to the * directory or the user configuration) unusable. */ time_t unreachable_since; /**< 0 if we can connect to this guard, or the * time at which we first noticed we couldn't * connect to it. */ time_t last_attempted; /**< 0 if we can connect to this guard, or the time * at which we last failed to connect to it. */ double circ_attempts; /**< Number of circuits this guard has "attempted" */ double circ_successes; /**< Number of successfully built circuits using * this guard as first hop. */ double successful_circuits_closed; /**< Number of circuits that carried * streams successfully. */ double collapsed_circuits; /**< Number of fully built circuits that were * remotely closed before any streams were * attempted. */ double unusable_circuits; /**< Number of circuits for which streams were * attempted, but none succeeded. */ double timeouts; /**< Number of 'right-censored' circuit timeouts for this * guard. */ double use_attempts; /**< Number of circuits we tried to use with streams */ double use_successes; /**< Number of successfully used circuits using * this guard as first hop. */ } entry_guard_t; entry_guard_t *entry_guard_get_by_id_digest(const char *digest); void entry_guards_changed(void); const smartlist_t *get_entry_guards(void); int num_live_entry_guards(int for_directory); #endif void entry_guards_compute_status(const or_options_t *options, time_t now); int entry_guard_register_connect_status(const char *digest, int succeeded, int mark_relay_status, time_t now); void entry_nodes_should_be_added(void); int entry_list_is_constrained(const or_options_t *options); const node_t *choose_random_entry(cpath_build_state_t *state); const node_t *choose_random_dirguard(dirinfo_type_t t); int entry_guards_parse_state(or_state_t *state, int set, char **msg); void entry_guards_update_state(or_state_t *state); int getinfo_helper_entry_guards(control_connection_t *conn, const char *question, char **answer, const char **errmsg); void mark_bridge_list(void); void sweep_bridge_list(void); int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); int node_is_a_configured_bridge(const node_t *node); void learned_router_identity(const tor_addr_t *addr, uint16_t port, const char *digest); void bridge_add_from_config(const tor_addr_t *addr, uint16_t port, const char *digest, const char *transport_name); void retry_bridge_descriptor_fetch_directly(const char *digest); void fetch_bridge_descriptors(const or_options_t *options, time_t now); void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); int any_bridge_descriptors_known(void); int any_pending_bridge_descriptor_fetches(void); int entries_known_but_down(const or_options_t *options); void entries_retry_all(const or_options_t *options); int any_bridge_supports_microdescriptors(void); void entry_guards_free_all(void); const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port); struct transport_t; int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, const struct transport_t **transport); int validate_pluggable_transports_config(void); double pathbias_get_close_success_count(entry_guard_t *guard); double pathbias_get_use_success_count(entry_guard_t *guard); #endif tor-0.2.4.20/src/or/relay.c0000644000175000017500000027414112255745673012202 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file relay.c * \brief Handle relay cell encryption/decryption, plus packaging and * receiving from circuits, plus queuing on circuits. **/ #define RELAY_PRIVATE #include "or.h" #include "addressmap.h" #include "buffers.h" #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuituse.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "connection_or.h" #include "control.h" #include "geoip.h" #include "main.h" #include "mempool.h" #include "networkstatus.h" #include "nodelist.h" #include "onion.h" #include "policies.h" #include "reasons.h" #include "relay.h" #include "rendcommon.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t *layer_hint); static int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint); static void circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint); static void circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); static int circuit_resume_edge_reading_helper(edge_connection_t *conn, circuit_t *circ, crypt_path_t *layer_hint); static int circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); static int circuit_queue_streams_are_blocked(circuit_t *circ); static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, entry_connection_t *conn, node_t *node, const tor_addr_t *addr); /** Stop reading on edge connections when we have this many cells * waiting on the appropriate queue. */ #define CELL_QUEUE_HIGHWATER_SIZE 256 /** Start reading from edge connections again when we get down to this many * cells. */ #define CELL_QUEUE_LOWWATER_SIZE 64 /** Stats: how many relay cells have originated at this hop, or have * been relayed onward (not recognized at this hop)? */ uint64_t stats_n_relay_cells_relayed = 0; /** Stats: how many relay cells have been delivered to streams at this * hop? */ uint64_t stats_n_relay_cells_delivered = 0; /** Used to tell which stream to read from first on a circuit. */ static tor_weak_rng_t stream_choice_rng = TOR_WEAK_RNG_INIT; /** Update digest from the payload of cell. Assign integrity part to * cell. */ static void relay_set_digest(crypto_digest_t *digest, cell_t *cell) { char integrity[4]; relay_header_t rh; crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE); crypto_digest_get_digest(digest, integrity, 4); // log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.", // integrity[0], integrity[1], integrity[2], integrity[3]); relay_header_unpack(&rh, cell->payload); memcpy(rh.integrity, integrity, 4); relay_header_pack(cell->payload, &rh); } /** Does the digest for this circuit indicate that this cell is for us? * * Update digest from the payload of cell (with the integrity part set * to 0). If the integrity part is valid, return 1, else restore digest * and cell to their original state and return 0. */ static int relay_digest_matches(crypto_digest_t *digest, cell_t *cell) { char received_integrity[4], calculated_integrity[4]; relay_header_t rh; crypto_digest_t *backup_digest=NULL; backup_digest = crypto_digest_dup(digest); relay_header_unpack(&rh, cell->payload); memcpy(received_integrity, rh.integrity, 4); memset(rh.integrity, 0, 4); relay_header_pack(cell->payload, &rh); // log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.", // received_integrity[0], received_integrity[1], // received_integrity[2], received_integrity[3]); crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE); crypto_digest_get_digest(digest, calculated_integrity, 4); if (tor_memneq(received_integrity, calculated_integrity, 4)) { // log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing."); // (%d vs %d).", received_integrity, calculated_integrity); /* restore digest to its old form */ crypto_digest_assign(digest, backup_digest); /* restore the relay header */ memcpy(rh.integrity, received_integrity, 4); relay_header_pack(cell->payload, &rh); crypto_digest_free(backup_digest); return 0; } crypto_digest_free(backup_digest); return 1; } /** Apply cipher to CELL_PAYLOAD_SIZE bytes of in * (in place). * * If encrypt_mode is 1 then encrypt, else decrypt. * * Return -1 if the crypto fails, else return 0. */ static int relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in, int encrypt_mode) { int r; (void)encrypt_mode; r = crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE); if (r) { log_warn(LD_BUG,"Error during relay encryption"); return -1; } return 0; } /** Receive a relay cell: * - Crypt it (encrypt if headed toward the origin or if we are the * origin; decrypt if we're headed toward the exit). * - Check if recognized (if exitward). * - If recognized and the digest checks out, then find if there's a stream * that the cell is intended for, and deliver it to the right * connection_edge. * - If not recognized, then we need to relay it: append it to the appropriate * cell_queue on circ. * * Return -reason on failure. */ int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, cell_direction_t cell_direction) { channel_t *chan = NULL; crypt_path_t *layer_hint=NULL; char recognized=0; int reason; tor_assert(cell); tor_assert(circ); tor_assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN); if (circ->marked_for_close) return 0; if (relay_crypt(circ, cell, cell_direction, &layer_hint, &recognized) < 0) { log_warn(LD_BUG,"relay crypt failed. Dropping connection."); return -END_CIRC_REASON_INTERNAL; } if (recognized) { edge_connection_t *conn = NULL; if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { pathbias_check_probe_response(circ, cell); /* We need to drop this cell no matter what to avoid code that expects * a certain purpose (such as the hidserv code). */ return 0; } conn = relay_lookup_conn(circ, cell, cell_direction, layer_hint); if (cell_direction == CELL_DIRECTION_OUT) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending away from origin."); if ((reason=connection_edge_process_relay_cell(cell, circ, conn, NULL)) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "connection_edge_process_relay_cell (away from origin) " "failed."); return reason; } } if (cell_direction == CELL_DIRECTION_IN) { ++stats_n_relay_cells_delivered; log_debug(LD_OR,"Sending to origin."); if ((reason = connection_edge_process_relay_cell(cell, circ, conn, layer_hint)) < 0) { log_warn(LD_OR, "connection_edge_process_relay_cell (at origin) failed."); return reason; } } return 0; } /* not recognized. pass it on. */ if (cell_direction == CELL_DIRECTION_OUT) { cell->circ_id = circ->n_circ_id; /* switch it */ chan = circ->n_chan; } else if (! CIRCUIT_IS_ORIGIN(circ)) { cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */ chan = TO_OR_CIRCUIT(circ)->p_chan; } else { log_fn(LOG_PROTOCOL_WARN, LD_OR, "Dropping unrecognized inbound cell on origin circuit."); /* If we see unrecognized cells on path bias testing circs, * it's bad mojo. Those circuits need to die. * XXX: Shouldn't they always die? */ if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { TO_ORIGIN_CIRCUIT(circ)->path_state = PATH_STATE_USE_FAILED; return -END_CIRC_REASON_TORPROTOCOL; } else { return 0; } } if (!chan) { // XXXX Can this splice stuff be done more cleanly? if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->rend_splice && cell_direction == CELL_DIRECTION_OUT) { or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice; tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); tor_assert(splice->base_.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); cell->circ_id = splice->p_circ_id; cell->command = CELL_RELAY; /* can't be relay_early anyway */ if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice), CELL_DIRECTION_IN)) < 0) { log_warn(LD_REND, "Error relaying cell across rendezvous; closing " "circuits"); /* XXXX Do this here, or just return -1? */ circuit_mark_for_close(circ, -reason); return reason; } return 0; } log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Didn't recognize cell, but circ stops here! Closing circ."); return -END_CIRC_REASON_TORPROTOCOL; } log_debug(LD_OR,"Passing on unrecognized cell."); ++stats_n_relay_cells_relayed; /* XXXX no longer quite accurate {cells} * we might kill the circ before we relay * the cells. */ append_cell_to_circuit_queue(circ, chan, cell, cell_direction, 0); return 0; } /** Do the appropriate en/decryptions for cell arriving on * circ in direction cell_direction. * * If cell_direction == CELL_DIRECTION_IN: * - If we're at the origin (we're the OP), for hops 1..N, * decrypt cell. If recognized, stop. * - Else (we're not the OP), encrypt one hop. Cell is not recognized. * * If cell_direction == CELL_DIRECTION_OUT: * - decrypt one hop. Check if recognized. * * If cell is recognized, set *recognized to 1, and set * *layer_hint to the hop that recognized it. * * Return -1 to indicate that we should mark the circuit for close, * else return 0. */ int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t **layer_hint, char *recognized) { relay_header_t rh; tor_assert(circ); tor_assert(cell); tor_assert(recognized); tor_assert(cell_direction == CELL_DIRECTION_IN || cell_direction == CELL_DIRECTION_OUT); if (cell_direction == CELL_DIRECTION_IN) { if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit. * We'll want to do layered decrypts. */ crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath; thishop = cpath; if (thishop->state != CPATH_STATE_OPEN) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay cell before first created cell? Closing."); return -1; } do { /* Remember: cpath is in forward order, that is, first hop first. */ tor_assert(thishop); if (relay_crypt_one_payload(thishop->b_crypto, cell->payload, 0) < 0) return -1; relay_header_unpack(&rh, cell->payload); if (rh.recognized == 0) { /* it's possibly recognized. have to check digest to be sure. */ if (relay_digest_matches(thishop->b_digest, cell)) { *recognized = 1; *layer_hint = thishop; return 0; } } thishop = thishop->next; } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN); log_fn(LOG_PROTOCOL_WARN, LD_OR, "Incoming cell at client not recognized. Closing."); return -1; } else { /* we're in the middle. Just one crypt. */ if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto, cell->payload, 1) < 0) return -1; // log_fn(LOG_DEBUG,"Skipping recognized check, because we're not " // "the client."); } } else /* cell_direction == CELL_DIRECTION_OUT */ { /* we're in the middle. Just one crypt. */ if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->n_crypto, cell->payload, 0) < 0) return -1; relay_header_unpack(&rh, cell->payload); if (rh.recognized == 0) { /* it's possibly recognized. have to check digest to be sure. */ if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) { *recognized = 1; return 0; } } } return 0; } /** Package a relay cell from an edge: * - Encrypt it to the right layer * - Append it to the appropriate cell_queue on circ. */ static int circuit_package_relay_cell(cell_t *cell, circuit_t *circ, cell_direction_t cell_direction, crypt_path_t *layer_hint, streamid_t on_stream, const char *filename, int lineno) { channel_t *chan; /* where to send the cell */ if (cell_direction == CELL_DIRECTION_OUT) { crypt_path_t *thishop; /* counter for repeated crypts */ chan = circ->n_chan; if (!chan) { log_warn(LD_BUG,"outgoing relay cell sent from %s:%d has n_chan==NULL." " Dropping.", filename, lineno); return 0; /* just drop it */ } if (!CIRCUIT_IS_ORIGIN(circ)) { log_warn(LD_BUG,"outgoing relay cell sent from %s:%d on non-origin " "circ. Dropping.", filename, lineno); return 0; /* just drop it */ } relay_set_digest(layer_hint->f_digest, cell); thishop = layer_hint; /* moving from farthest to nearest hop */ do { tor_assert(thishop); /* XXXX RD This is a bug, right? */ log_debug(LD_OR,"crypting a layer of the relay cell."); if (relay_crypt_one_payload(thishop->f_crypto, cell->payload, 1) < 0) { return -1; } thishop = thishop->prev; } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev); } else { /* incoming cell */ or_circuit_t *or_circ; if (CIRCUIT_IS_ORIGIN(circ)) { /* We should never package an _incoming_ cell from the circuit * origin; that means we messed up somewhere. */ log_warn(LD_BUG,"incoming relay cell at origin circuit. Dropping."); assert_circuit_ok(circ); return 0; /* just drop it */ } or_circ = TO_OR_CIRCUIT(circ); chan = or_circ->p_chan; relay_set_digest(or_circ->p_digest, cell); if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0) return -1; } ++stats_n_relay_cells_relayed; append_cell_to_circuit_queue(circ, chan, cell, cell_direction, on_stream); return 0; } /** If cell's stream_id matches the stream_id of any conn that's * attached to circ, return that conn, else return NULL. */ static edge_connection_t * relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t *layer_hint) { edge_connection_t *tmpconn; relay_header_t rh; relay_header_unpack(&rh, cell->payload); if (!rh.stream_id) return NULL; /* IN or OUT cells could have come from either direction, now * that we allow rendezvous *to* an OP. */ if (CIRCUIT_IS_ORIGIN(circ)) { for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (rh.stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close && tmpconn->cpath_layer == layer_hint) { log_debug(LD_APP,"found conn for stream %d.", rh.stream_id); return tmpconn; } } } else { for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (rh.stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close) { log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); if (cell_direction == CELL_DIRECTION_OUT || connection_edge_is_rendezvous_stream(tmpconn)) return tmpconn; } } for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream) { if (rh.stream_id == tmpconn->stream_id && !tmpconn->base_.marked_for_close) { log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id); return tmpconn; } } } return NULL; /* probably a begin relay cell */ } /** Pack the relay_header_t host-order structure src into * network-order in the buffer dest. See tor-spec.txt for details * about the wire format. */ void relay_header_pack(uint8_t *dest, const relay_header_t *src) { set_uint8(dest, src->command); set_uint16(dest+1, htons(src->recognized)); set_uint16(dest+3, htons(src->stream_id)); memcpy(dest+5, src->integrity, 4); set_uint16(dest+9, htons(src->length)); } /** Unpack the network-order buffer src into a host-order * relay_header_t structure dest. */ void relay_header_unpack(relay_header_t *dest, const uint8_t *src) { dest->command = get_uint8(src); dest->recognized = ntohs(get_uint16(src+1)); dest->stream_id = ntohs(get_uint16(src+3)); memcpy(dest->integrity, src+5, 4); dest->length = ntohs(get_uint16(src+9)); } /** Convert the relay command into a human-readable string. */ static const char * relay_command_to_string(uint8_t command) { switch (command) { case RELAY_COMMAND_BEGIN: return "BEGIN"; case RELAY_COMMAND_DATA: return "DATA"; case RELAY_COMMAND_END: return "END"; case RELAY_COMMAND_CONNECTED: return "CONNECTED"; case RELAY_COMMAND_SENDME: return "SENDME"; case RELAY_COMMAND_EXTEND: return "EXTEND"; case RELAY_COMMAND_EXTENDED: return "EXTENDED"; case RELAY_COMMAND_TRUNCATE: return "TRUNCATE"; case RELAY_COMMAND_TRUNCATED: return "TRUNCATED"; case RELAY_COMMAND_DROP: return "DROP"; case RELAY_COMMAND_RESOLVE: return "RESOLVE"; case RELAY_COMMAND_RESOLVED: return "RESOLVED"; case RELAY_COMMAND_BEGIN_DIR: return "BEGIN_DIR"; case RELAY_COMMAND_ESTABLISH_INTRO: return "ESTABLISH_INTRO"; case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: return "ESTABLISH_RENDEZVOUS"; case RELAY_COMMAND_INTRODUCE1: return "INTRODUCE1"; case RELAY_COMMAND_INTRODUCE2: return "INTRODUCE2"; case RELAY_COMMAND_RENDEZVOUS1: return "RENDEZVOUS1"; case RELAY_COMMAND_RENDEZVOUS2: return "RENDEZVOUS2"; case RELAY_COMMAND_INTRO_ESTABLISHED: return "INTRO_ESTABLISHED"; case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: return "RENDEZVOUS_ESTABLISHED"; case RELAY_COMMAND_INTRODUCE_ACK: return "INTRODUCE_ACK"; default: return "(unrecognized)"; } } /** Make a relay cell out of relay_command and payload, and send * it onto the open circuit circ. stream_id is the ID on * circ for the stream that's sending the relay cell, or 0 if it's a * control cell. cpath_layer is NULL for OR->OP cells, or the * destination hop for OP->OR cells. * * If you can't send the cell, mark the circuit for close and return -1. Else * return 0. */ int relay_send_command_from_edge_(streamid_t stream_id, circuit_t *circ, uint8_t relay_command, const char *payload, size_t payload_len, crypt_path_t *cpath_layer, const char *filename, int lineno) { cell_t cell; relay_header_t rh; cell_direction_t cell_direction; /* XXXX NM Split this function into a separate versions per circuit type? */ tor_assert(circ); tor_assert(payload_len <= RELAY_PAYLOAD_SIZE); memset(&cell, 0, sizeof(cell_t)); cell.command = CELL_RELAY; if (cpath_layer) { cell.circ_id = circ->n_circ_id; cell_direction = CELL_DIRECTION_OUT; } else if (! CIRCUIT_IS_ORIGIN(circ)) { cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; cell_direction = CELL_DIRECTION_IN; } else { return -1; } memset(&rh, 0, sizeof(rh)); rh.command = relay_command; rh.stream_id = stream_id; rh.length = payload_len; relay_header_pack(cell.payload, &rh); if (payload_len) memcpy(cell.payload+RELAY_HEADER_SIZE, payload, payload_len); log_debug(LD_OR,"delivering %d cell %s.", relay_command, cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward"); /* If we are sending an END cell and this circuit is used for a tunneled * directory request, advance its state. */ if (relay_command == RELAY_COMMAND_END && circ->dirreq_id) geoip_change_dirreq_state(circ->dirreq_id, DIRREQ_TUNNELED, DIRREQ_END_CELL_SENT); if (cell_direction == CELL_DIRECTION_OUT && circ->n_chan) { /* if we're using relaybandwidthrate, this conn wants priority */ channel_timestamp_client(circ->n_chan); } if (cell_direction == CELL_DIRECTION_OUT) { origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); if (origin_circ->remaining_relay_early_cells > 0 && (relay_command == RELAY_COMMAND_EXTEND || relay_command == RELAY_COMMAND_EXTEND2 || cpath_layer != origin_circ->cpath)) { /* If we've got any relay_early cells left and (we're sending * an extend cell or we're not talking to the first hop), use * one of them. Don't worry about the conn protocol version: * append_cell_to_circuit_queue will fix it up. */ cell.command = CELL_RELAY_EARLY; --origin_circ->remaining_relay_early_cells; log_debug(LD_OR, "Sending a RELAY_EARLY cell; %d remaining.", (int)origin_circ->remaining_relay_early_cells); /* Memorize the command that is sent as RELAY_EARLY cell; helps debug * task 878. */ origin_circ->relay_early_commands[ origin_circ->relay_early_cells_sent++] = relay_command; } else if (relay_command == RELAY_COMMAND_EXTEND || relay_command == RELAY_COMMAND_EXTEND2) { /* If no RELAY_EARLY cells can be sent over this circuit, log which * commands have been sent as RELAY_EARLY cells before; helps debug * task 878. */ smartlist_t *commands_list = smartlist_new(); int i = 0; char *commands = NULL; for (; i < origin_circ->relay_early_cells_sent; i++) smartlist_add(commands_list, (char *) relay_command_to_string(origin_circ->relay_early_commands[i])); commands = smartlist_join_strings(commands_list, ",", 0, NULL); log_warn(LD_BUG, "Uh-oh. We're sending a RELAY_COMMAND_EXTEND cell, " "but we have run out of RELAY_EARLY cells on that circuit. " "Commands sent before: %s", commands); tor_free(commands); smartlist_free(commands_list); } } if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer, stream_id, filename, lineno) < 0) { log_warn(LD_BUG,"circuit_package_relay_cell failed. Closing."); circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); return -1; } return 0; } /** Make a relay cell out of relay_command and payload, and * send it onto the open circuit circ. fromconn is the stream * that's sending the relay cell, or NULL if it's a control cell. * cpath_layer is NULL for OR->OP cells, or the destination hop * for OP->OR cells. * * If you can't send the cell, mark the circuit for close and * return -1. Else return 0. */ int connection_edge_send_command(edge_connection_t *fromconn, uint8_t relay_command, const char *payload, size_t payload_len) { /* XXXX NM Split this function into a separate versions per circuit type? */ circuit_t *circ; crypt_path_t *cpath_layer = fromconn->cpath_layer; tor_assert(fromconn); circ = fromconn->on_circuit; if (fromconn->base_.marked_for_close) { log_warn(LD_BUG, "called on conn that's already marked for close at %s:%d.", fromconn->base_.marked_for_close_file, fromconn->base_.marked_for_close); return 0; } if (!circ) { if (fromconn->base_.type == CONN_TYPE_AP) { log_info(LD_APP,"no circ. Closing conn."); connection_mark_unattached_ap(EDGE_TO_ENTRY_CONN(fromconn), END_STREAM_REASON_INTERNAL); } else { log_info(LD_EXIT,"no circ. Closing conn."); fromconn->edge_has_sent_end = 1; /* no circ to send to */ fromconn->end_reason = END_STREAM_REASON_INTERNAL; connection_mark_for_close(TO_CONN(fromconn)); } return -1; } return relay_send_command_from_edge(fromconn->stream_id, circ, relay_command, payload, payload_len, cpath_layer); } /** How many times will I retry a stream that fails due to DNS * resolve failure or misc error? */ #define MAX_RESOLVE_FAILURES 3 /** Return 1 if reason is something that you should retry if you * get the end cell before you've connected; else return 0. */ static int edge_reason_is_retriable(int reason) { return reason == END_STREAM_REASON_HIBERNATING || reason == END_STREAM_REASON_RESOURCELIMIT || reason == END_STREAM_REASON_EXITPOLICY || reason == END_STREAM_REASON_RESOLVEFAILED || reason == END_STREAM_REASON_MISC || reason == END_STREAM_REASON_NOROUTE; } /** Called when we receive an END cell on a stream that isn't open yet, * from the client side. * Arguments are as for connection_edge_process_relay_cell(). */ static int connection_ap_process_end_not_open( relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, entry_connection_t *conn, crypt_path_t *layer_hint) { node_t *exitrouter; int reason = *(cell->payload+RELAY_HEADER_SIZE); int control_reason; edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); (void) layer_hint; /* unused */ if (rh->length > 0) { if (reason == END_STREAM_REASON_TORPROTOCOL || reason == END_STREAM_REASON_INTERNAL || reason == END_STREAM_REASON_DESTROY) { /* All three of these reasons could mean a failed tag * hit the exit and it complained. Do not probe. * Fail the circuit. */ circ->path_state = PATH_STATE_USE_FAILED; return -END_CIRC_REASON_TORPROTOCOL; } else { /* Path bias: If we get a valid reason code from the exit, * it wasn't due to tagging. * * We rely on recognized+digest being strong enough to make * tags unlikely to allow us to get tagged, yet 'recognized' * reason codes here. */ pathbias_mark_use_success(circ); } } if (rh->length == 0) { reason = END_STREAM_REASON_MISC; } control_reason = reason | END_STREAM_REASON_FLAG_REMOTE; if (edge_reason_is_retriable(reason) && /* avoid retry if rend */ !connection_edge_is_rendezvous_stream(edge_conn)) { const char *chosen_exit_digest = circ->build_state->chosen_exit->identity_digest; log_info(LD_APP,"Address '%s' refused due to '%s'. Considering retrying.", safe_str(conn->socks_request->address), stream_end_reason_to_string(reason)); exitrouter = node_get_mutable_by_id(chosen_exit_digest); switch (reason) { case END_STREAM_REASON_EXITPOLICY: { tor_addr_t addr; tor_addr_make_unspec(&addr); if (rh->length >= 5) { int ttl = -1; tor_addr_make_unspec(&addr); if (rh->length == 5 || rh->length == 9) { tor_addr_from_ipv4n(&addr, get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); if (rh->length == 9) ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5)); } else if (rh->length == 17 || rh->length == 21) { tor_addr_from_ipv6_bytes(&addr, (char*)(cell->payload+RELAY_HEADER_SIZE+1)); if (rh->length == 21) ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17)); } if (tor_addr_is_null(&addr)) { log_info(LD_APP,"Address '%s' resolved to 0.0.0.0. Closing,", safe_str(conn->socks_request->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return 0; } if ((tor_addr_family(&addr) == AF_INET && !conn->ipv4_traffic_ok) || (tor_addr_family(&addr) == AF_INET6 && !conn->ipv6_traffic_ok)) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got an EXITPOLICY failure on a connection with a " "mismatched family. Closing."); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return 0; } if (get_options()->ClientDNSRejectInternalAddresses && tor_addr_is_internal(&addr, 0)) { log_info(LD_APP,"Address '%s' resolved to internal. Closing,", safe_str(conn->socks_request->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return 0; } client_dns_set_addressmap(conn, conn->socks_request->address, &addr, conn->chosen_exit_name, ttl); { char new_addr[TOR_ADDR_BUF_LEN]; tor_addr_to_str(new_addr, &addr, sizeof(new_addr), 1); if (strcmp(conn->socks_request->address, new_addr)) { strlcpy(conn->socks_request->address, new_addr, sizeof(conn->socks_request->address)); control_event_stream_status(conn, STREAM_EVENT_REMAP, 0); } } } /* check if he *ought* to have allowed it */ adjust_exit_policy_from_exitpolicy_failure(circ, conn, exitrouter, &addr); if (conn->chosen_exit_optional || conn->chosen_exit_retries) { /* stop wanting a specific exit */ conn->chosen_exit_optional = 0; /* A non-zero chosen_exit_retries can happen if we set a * TrackHostExits for this address under a port that the exit * relay allows, but then try the same address with a different * port that it doesn't allow to exit. We shouldn't unregister * the mapping, since it is probably still wanted on the * original port. But now we give away to the exit relay that * we probably have a TrackHostExits on it. So be it. */ conn->chosen_exit_retries = 0; tor_free(conn->chosen_exit_name); /* clears it */ } if (connection_ap_detach_retriable(conn, circ, control_reason) >= 0) return 0; /* else, conn will get closed below */ break; } case END_STREAM_REASON_CONNECTREFUSED: if (!conn->chosen_exit_optional) break; /* break means it'll close, below */ /* Else fall through: expire this circuit, clear the * chosen_exit_name field, and try again. */ case END_STREAM_REASON_RESOLVEFAILED: case END_STREAM_REASON_TIMEOUT: case END_STREAM_REASON_MISC: case END_STREAM_REASON_NOROUTE: if (client_dns_incr_failures(conn->socks_request->address) < MAX_RESOLVE_FAILURES) { /* We haven't retried too many times; reattach the connection. */ circuit_log_path(LOG_INFO,LD_APP,circ); /* Mark this circuit "unusable for new streams". */ mark_circuit_unusable_for_new_conns(circ); if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ conn->chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); /* clears it */ } if (connection_ap_detach_retriable(conn, circ, control_reason) >= 0) return 0; /* else, conn will get closed below */ } else { log_notice(LD_APP, "Have tried resolving or connecting to address '%s' " "at %d different places. Giving up.", safe_str(conn->socks_request->address), MAX_RESOLVE_FAILURES); /* clear the failures, so it will have a full try next time */ client_dns_clear_failures(conn->socks_request->address); } break; case END_STREAM_REASON_HIBERNATING: case END_STREAM_REASON_RESOURCELIMIT: if (exitrouter) { policies_set_node_exitpolicy_to_reject_all(exitrouter); } if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ conn->chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); /* clears it */ } if (connection_ap_detach_retriable(conn, circ, control_reason) >= 0) return 0; /* else, will close below */ break; } /* end switch */ log_info(LD_APP,"Giving up on retrying; conn can't be handled."); } log_info(LD_APP, "Edge got end (%s) before we're connected. Marking for close.", stream_end_reason_to_string(rh->length > 0 ? reason : -1)); circuit_log_path(LOG_INFO,LD_APP,circ); /* need to test because of detach_retriable */ if (!ENTRY_TO_CONN(conn)->marked_for_close) connection_mark_unattached_ap(conn, control_reason); return 0; } /** Called when we have gotten an END_REASON_EXITPOLICY failure on circ * for conn, while attempting to connect via node. If the node * told us which address it rejected, then addr is that address; * otherwise it is AF_UNSPEC. * * If we are sure the node should have allowed this address, mark the node as * having a reject *:* exit policy. Otherwise, mark the circuit as unusable * for this particular address. **/ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, entry_connection_t *conn, node_t *node, const tor_addr_t *addr) { int make_reject_all = 0; const sa_family_t family = tor_addr_family(addr); if (node) { tor_addr_t tmp; int asked_for_family = tor_addr_parse(&tmp, conn->socks_request->address); if (family == AF_UNSPEC) { make_reject_all = 1; } else if (node_exit_policy_is_exact(node, family) && asked_for_family != -1 && !conn->chosen_exit_name) { make_reject_all = 1; } if (make_reject_all) { log_info(LD_APP, "Exitrouter %s seems to be more restrictive than its exit " "policy. Not using this router as exit for now.", node_describe(node)); policies_set_node_exitpolicy_to_reject_all(node); } } if (family != AF_UNSPEC) addr_policy_append_reject_addr(&circ->prepend_policy, addr); } /** Helper: change the socks_request->address field on conn to the * dotted-quad representation of new_addr, * and send an appropriate REMAP event. */ static void remap_event_helper(entry_connection_t *conn, const tor_addr_t *new_addr) { tor_addr_to_str(conn->socks_request->address, new_addr, sizeof(conn->socks_request->address), 1); control_event_stream_status(conn, STREAM_EVENT_REMAP, REMAP_STREAM_SOURCE_EXIT); } /** Extract the contents of a connected cell in cell, whose relay * header has already been parsed into rh. On success, set * addr_out to the address we're connected to, and ttl_out to * the ttl of that address, in seconds, and return 0. On failure, return * -1. */ int connected_cell_parse(const relay_header_t *rh, const cell_t *cell, tor_addr_t *addr_out, int *ttl_out) { uint32_t bytes; const uint8_t *payload = cell->payload + RELAY_HEADER_SIZE; tor_addr_make_unspec(addr_out); *ttl_out = -1; if (rh->length == 0) return 0; if (rh->length < 4) return -1; bytes = ntohl(get_uint32(payload)); /* If bytes is 0, this is maybe a v6 address. Otherwise it's a v4 address */ if (bytes != 0) { /* v4 address */ tor_addr_from_ipv4h(addr_out, bytes); if (rh->length >= 8) { bytes = ntohl(get_uint32(payload + 4)); if (bytes <= INT32_MAX) *ttl_out = bytes; } } else { if (rh->length < 25) /* 4 bytes of 0s, 1 addr, 16 ipv4, 4 ttl. */ return -1; if (get_uint8(payload + 4) != 6) return -1; tor_addr_from_ipv6_bytes(addr_out, (char*)(payload + 5)); bytes = ntohl(get_uint32(payload + 21)); if (bytes <= INT32_MAX) *ttl_out = (int) bytes; } return 0; } /** An incoming relay cell has arrived from circuit circ to * stream conn. * * The arguments here are the same as in * connection_edge_process_relay_cell() below; this function is called * from there when conn is defined and not in an open state. */ static int connection_edge_process_relay_cell_not_open( relay_header_t *rh, cell_t *cell, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint) { if (rh->command == RELAY_COMMAND_END) { if (CIRCUIT_IS_ORIGIN(circ) && conn->base_.type == CONN_TYPE_AP) { return connection_ap_process_end_not_open(rh, cell, TO_ORIGIN_CIRCUIT(circ), EDGE_TO_ENTRY_CONN(conn), layer_hint); } else { /* we just got an 'end', don't need to send one */ conn->edge_has_sent_end = 1; conn->end_reason = *(cell->payload+RELAY_HEADER_SIZE) | END_STREAM_REASON_FLAG_REMOTE; connection_mark_for_close(TO_CONN(conn)); return 0; } } if (conn->base_.type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) { tor_addr_t addr; int ttl; entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); tor_assert(CIRCUIT_IS_ORIGIN(circ)); if (conn->base_.state != AP_CONN_STATE_CONNECT_WAIT) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got 'connected' while not in state connect_wait. Dropping."); return 0; } conn->base_.state = AP_CONN_STATE_OPEN; log_info(LD_APP,"'connected' received after %d seconds.", (int)(time(NULL) - conn->base_.timestamp_lastread)); if (connected_cell_parse(rh, cell, &addr, &ttl) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a badly formatted connected cell. Closing."); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); } if (tor_addr_family(&addr) != AF_UNSPEC) { const sa_family_t family = tor_addr_family(&addr); if (tor_addr_is_null(&addr) || (get_options()->ClientDNSRejectInternalAddresses && tor_addr_is_internal(&addr, 0))) { log_info(LD_APP, "...but it claims the IP address was %s. Closing.", fmt_addr(&addr)); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); return 0; } if ((family == AF_INET && ! entry_conn->ipv4_traffic_ok) || (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok)) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a connected cell to %s with unsupported address family." " Closing.", fmt_addr(&addr)); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); return 0; } client_dns_set_addressmap(entry_conn, entry_conn->socks_request->address, &addr, entry_conn->chosen_exit_name, ttl); remap_event_helper(entry_conn, &addr); } circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ)); /* don't send a socks reply to transparent conns */ tor_assert(entry_conn->socks_request != NULL); if (!entry_conn->socks_request->has_finished) connection_ap_handshake_socks_reply(entry_conn, NULL, 0, 0); /* Was it a linked dir conn? If so, a dir request just started to * fetch something; this could be a bootstrap status milestone. */ log_debug(LD_APP, "considering"); if (TO_CONN(conn)->linked_conn && TO_CONN(conn)->linked_conn->type == CONN_TYPE_DIR) { connection_t *dirconn = TO_CONN(conn)->linked_conn; log_debug(LD_APP, "it is! %d", dirconn->purpose); switch (dirconn->purpose) { case DIR_PURPOSE_FETCH_CERTIFICATE: if (consensus_is_waiting_for_certs()) control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_KEYS, 0); break; case DIR_PURPOSE_FETCH_CONSENSUS: control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_STATUS, 0); break; case DIR_PURPOSE_FETCH_SERVERDESC: case DIR_PURPOSE_FETCH_MICRODESC: control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, count_loading_descriptors_progress()); break; } } /* This is definitely a success, so forget about any pending data we * had sent. */ if (entry_conn->pending_optimistic_data) { generic_buffer_free(entry_conn->pending_optimistic_data); entry_conn->pending_optimistic_data = NULL; } /* handle anything that might have queued */ if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { /* (We already sent an end cell if possible) */ connection_mark_for_close(TO_CONN(conn)); return 0; } return 0; } if (conn->base_.type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) { int ttl; int answer_len; uint8_t answer_type; entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); if (conn->base_.state != AP_CONN_STATE_RESOLVE_WAIT) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Got a 'resolved' cell while " "not in state resolve_wait. Dropping."); return 0; } tor_assert(SOCKS_COMMAND_IS_RESOLVE(entry_conn->socks_request->command)); answer_len = cell->payload[RELAY_HEADER_SIZE+1]; if (rh->length < 2 || answer_len+2>rh->length) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Dropping malformed 'resolved' cell"); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); return 0; } answer_type = cell->payload[RELAY_HEADER_SIZE]; if (rh->length >= answer_len+6) ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+ 2+answer_len)); else ttl = -1; if (answer_type == RESOLVED_TYPE_IPV4 || answer_type == RESOLVED_TYPE_IPV6) { tor_addr_t addr; if (decode_address_from_payload(&addr, cell->payload+RELAY_HEADER_SIZE, rh->length) && tor_addr_is_internal(&addr, 0) && get_options()->ClientDNSRejectInternalAddresses) { log_info(LD_APP,"Got a resolve with answer %s. Rejecting.", fmt_addr(&addr)); connection_ap_handshake_socks_resolved(entry_conn, RESOLVED_TYPE_ERROR_TRANSIENT, 0, NULL, 0, TIME_MAX); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL); return 0; } } connection_ap_handshake_socks_resolved(entry_conn, answer_type, cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/ cell->payload+RELAY_HEADER_SIZE+2, /*answer*/ ttl, -1); if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { tor_addr_t addr; tor_addr_from_ipv4n(&addr, get_uint32(cell->payload+RELAY_HEADER_SIZE+2)); remap_event_helper(entry_conn, &addr); } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) { tor_addr_t addr; tor_addr_from_ipv6_bytes(&addr, (char*)(cell->payload+RELAY_HEADER_SIZE+2)); remap_event_helper(entry_conn, &addr); } connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_DONE | END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); return 0; } log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Got an unexpected relay command %d, in state %d (%s). Dropping.", rh->command, conn->base_.state, conn_state_to_string(conn->base_.type, conn->base_.state)); return 0; /* for forward compatibility, don't kill the circuit */ // connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); // connection_mark_for_close(conn); // return -1; } /** An incoming relay cell has arrived on circuit circ. If * conn is NULL this is a control cell, else cell is * destined for conn. * * If layer_hint is defined, then we're the origin of the * circuit, and it specifies the hop that packaged cell. * * Return -reason if you want to warn and tear down the circuit, else 0. */ static int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint) { static int num_seen=0; relay_header_t rh; unsigned domain = layer_hint?LD_APP:LD_EXIT; int reason; int optimistic_data = 0; /* Set to 1 if we receive data on a stream * that's in the EXIT_CONN_STATE_RESOLVING * or EXIT_CONN_STATE_CONNECTING states. */ tor_assert(cell); tor_assert(circ); relay_header_unpack(&rh, cell->payload); // log_fn(LOG_DEBUG,"command %d stream %d", rh.command, rh.stream_id); num_seen++; log_debug(domain, "Now seen %d relay cells here (command %d, stream %d).", num_seen, rh.command, rh.stream_id); if (rh.length > RELAY_PAYLOAD_SIZE) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay cell length field too long. Closing circuit."); return - END_CIRC_REASON_TORPROTOCOL; } if (rh.stream_id == 0) { switch (rh.command) { case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_CONNECTED: case RELAY_COMMAND_DATA: case RELAY_COMMAND_END: case RELAY_COMMAND_RESOLVE: case RELAY_COMMAND_RESOLVED: case RELAY_COMMAND_BEGIN_DIR: log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay command %d with zero " "stream_id. Dropping.", (int)rh.command); return 0; default: ; } } /* either conn is NULL, in which case we've got a control cell, or else * conn points to the recognized stream. */ if (conn && !connection_state_is_open(TO_CONN(conn))) { if (conn->base_.type == CONN_TYPE_EXIT && (conn->base_.state == EXIT_CONN_STATE_CONNECTING || conn->base_.state == EXIT_CONN_STATE_RESOLVING) && rh.command == RELAY_COMMAND_DATA) { /* Allow DATA cells to be delivered to an exit node in state * EXIT_CONN_STATE_CONNECTING or EXIT_CONN_STATE_RESOLVING. * This speeds up HTTP, for example. */ optimistic_data = 1; } else { return connection_edge_process_relay_cell_not_open( &rh, cell, circ, conn, layer_hint); } } switch (rh.command) { case RELAY_COMMAND_DROP: // log_info(domain,"Got a relay-level padding cell. Dropping."); return 0; case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_BEGIN_DIR: if (layer_hint && circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Relay begin request unsupported at AP. Dropping."); return 0; } if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED && layer_hint != TO_ORIGIN_CIRCUIT(circ)->cpath->prev) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "Relay begin request to Hidden Service " "from intermediary node. Dropping."); return 0; } if (conn) { log_fn(LOG_PROTOCOL_WARN, domain, "Begin cell for known stream. Dropping."); return 0; } if (rh.command == RELAY_COMMAND_BEGIN_DIR) { /* Assign this circuit and its app-ward OR connection a unique ID, * so that we can measure download times. The local edge and dir * connection will be assigned the same ID when they are created * and linked. */ static uint64_t next_id = 0; circ->dirreq_id = ++next_id; TO_OR_CIRCUIT(circ)->p_chan->dirreq_id = circ->dirreq_id; } return connection_exit_begin_conn(cell, circ); case RELAY_COMMAND_DATA: ++stats_n_data_cells_received; if (( layer_hint && --layer_hint->deliver_window < 0) || (!layer_hint && --circ->deliver_window < 0)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "(relay data) circ deliver_window below 0. Killing."); if (conn) { /* XXXX Do we actually need to do this? Will killing the circuit * not send an END and mark the stream for close as appropriate? */ connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_for_close(TO_CONN(conn)); } return -END_CIRC_REASON_TORPROTOCOL; } log_debug(domain,"circ deliver_window now %d.", layer_hint ? layer_hint->deliver_window : circ->deliver_window); circuit_consider_sending_sendme(circ, layer_hint); if (!conn) { log_info(domain,"data cell dropped, unknown stream (streamid %d).", rh.stream_id); return 0; } if (--conn->deliver_window < 0) { /* is it below 0 after decrement? */ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "(relay data) conn deliver_window below 0. Killing."); return -END_CIRC_REASON_TORPROTOCOL; } stats_n_data_bytes_received += rh.length; connection_write_to_buf((char*)(cell->payload + RELAY_HEADER_SIZE), rh.length, TO_CONN(conn)); if (!optimistic_data) { /* Only send a SENDME if we're not getting optimistic data; otherwise * a SENDME could arrive before the CONNECTED. */ connection_edge_consider_sending_sendme(conn); } return 0; case RELAY_COMMAND_END: reason = rh.length > 0 ? get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC; if (!conn) { log_info(domain,"end cell (%s) dropped, unknown stream.", stream_end_reason_to_string(reason)); return 0; } /* XXX add to this log_fn the exit node's nickname? */ log_info(domain,TOR_SOCKET_T_FORMAT": end cell (%s) for stream %d. " "Removing stream.", conn->base_.s, stream_end_reason_to_string(reason), conn->stream_id); if (conn->base_.type == CONN_TYPE_AP) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); if (entry_conn->socks_request && !entry_conn->socks_request->has_finished) log_warn(LD_BUG, "open stream hasn't sent socks answer yet? Closing."); } /* We just *got* an end; no reason to send one. */ conn->edge_has_sent_end = 1; if (!conn->end_reason) conn->end_reason = reason | END_STREAM_REASON_FLAG_REMOTE; if (!conn->base_.marked_for_close) { /* only mark it if not already marked. it's possible to * get the 'end' right around when the client hangs up on us. */ connection_mark_and_flush(TO_CONN(conn)); } return 0; case RELAY_COMMAND_EXTEND: case RELAY_COMMAND_EXTEND2: { static uint64_t total_n_extend=0, total_nonearly=0; total_n_extend++; if (rh.stream_id) { log_fn(LOG_PROTOCOL_WARN, domain, "'extend' cell received for non-zero stream. Dropping."); return 0; } if (cell->command != CELL_RELAY_EARLY && !networkstatus_get_param(NULL,"AllowNonearlyExtend",0,0,1)) { #define EARLY_WARNING_INTERVAL 3600 static ratelim_t early_warning_limit = RATELIM_INIT(EARLY_WARNING_INTERVAL); char *m; if (cell->command == CELL_RELAY) { ++total_nonearly; if ((m = rate_limit_log(&early_warning_limit, approx_time()))) { double percentage = ((double)total_nonearly)/total_n_extend; percentage *= 100; log_fn(LOG_PROTOCOL_WARN, domain, "EXTEND cell received, " "but not via RELAY_EARLY. Dropping.%s", m); log_fn(LOG_PROTOCOL_WARN, domain, " (We have dropped %.02f%% of " "all EXTEND cells for this reason)", percentage); tor_free(m); } } else { log_fn(LOG_WARN, domain, "EXTEND cell received, in a cell with type %d! Dropping.", cell->command); } return 0; } return circuit_extend(cell, circ); } case RELAY_COMMAND_EXTENDED: case RELAY_COMMAND_EXTENDED2: if (!layer_hint) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "'extended' unsupported at non-origin. Dropping."); return 0; } log_debug(domain,"Got an extended cell! Yay."); { extended_cell_t extended_cell; if (extended_cell_parse(&extended_cell, rh.command, (const uint8_t*)cell->payload+RELAY_HEADER_SIZE, rh.length)<0) { log_warn(LD_PROTOCOL, "Can't parse EXTENDED cell; killing circuit."); return -END_CIRC_REASON_TORPROTOCOL; } if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ), &extended_cell.created_cell)) < 0) { log_warn(domain,"circuit_finish_handshake failed."); return reason; } } if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) { log_info(domain,"circuit_send_next_onion_skin() failed."); return reason; } return 0; case RELAY_COMMAND_TRUNCATE: if (layer_hint) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "'truncate' unsupported at origin. Dropping."); return 0; } if (circ->n_hop) { if (circ->n_chan) log_warn(LD_BUG, "n_chan and n_hop set on the same circuit!"); extend_info_free(circ->n_hop); circ->n_hop = NULL; tor_free(circ->n_chan_create_cell); circuit_set_state(circ, CIRCUIT_STATE_OPEN); } if (circ->n_chan) { uint8_t trunc_reason = get_uint8(cell->payload + RELAY_HEADER_SIZE); circuit_clear_cell_queue(circ, circ->n_chan); channel_send_destroy(circ->n_circ_id, circ->n_chan, trunc_reason); circuit_set_n_circid_chan(circ, 0, NULL); } log_debug(LD_EXIT, "Processed 'truncate', replying."); { char payload[1]; payload[0] = (char)END_CIRC_REASON_REQUESTED; relay_send_command_from_edge(0, circ, RELAY_COMMAND_TRUNCATED, payload, sizeof(payload), NULL); } return 0; case RELAY_COMMAND_TRUNCATED: if (!layer_hint) { log_fn(LOG_PROTOCOL_WARN, LD_EXIT, "'truncated' unsupported at non-origin. Dropping."); return 0; } circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint, get_uint8(cell->payload + RELAY_HEADER_SIZE)); return 0; case RELAY_COMMAND_CONNECTED: if (conn) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "'connected' unsupported while open. Closing circ."); return -END_CIRC_REASON_TORPROTOCOL; } log_info(domain, "'connected' received, no conn attached anymore. Ignoring."); return 0; case RELAY_COMMAND_SENDME: if (!rh.stream_id) { if (layer_hint) { if (layer_hint->package_window + CIRCWINDOW_INCREMENT > CIRCWINDOW_START_MAX) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Unexpected sendme cell from exit relay. " "Closing circ."); return -END_CIRC_REASON_TORPROTOCOL; } layer_hint->package_window += CIRCWINDOW_INCREMENT; log_debug(LD_APP,"circ-level sendme at origin, packagewindow %d.", layer_hint->package_window); circuit_resume_edge_reading(circ, layer_hint); } else { if (circ->package_window + CIRCWINDOW_INCREMENT > CIRCWINDOW_START_MAX) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Unexpected sendme cell from client. " "Closing circ (window %d).", circ->package_window); return -END_CIRC_REASON_TORPROTOCOL; } circ->package_window += CIRCWINDOW_INCREMENT; log_debug(LD_APP, "circ-level sendme at non-origin, packagewindow %d.", circ->package_window); circuit_resume_edge_reading(circ, layer_hint); } return 0; } if (!conn) { log_info(domain,"sendme cell dropped, unknown stream (streamid %d).", rh.stream_id); return 0; } conn->package_window += STREAMWINDOW_INCREMENT; log_debug(domain,"stream-level sendme, packagewindow now %d.", conn->package_window); if (circuit_queue_streams_are_blocked(circ)) { /* Still waiting for queue to flush; don't touch conn */ return 0; } connection_start_reading(TO_CONN(conn)); /* handle whatever might still be on the inbuf */ if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { /* (We already sent an end cell if possible) */ connection_mark_for_close(TO_CONN(conn)); return 0; } return 0; case RELAY_COMMAND_RESOLVE: if (layer_hint) { log_fn(LOG_PROTOCOL_WARN, LD_APP, "resolve request unsupported at AP; dropping."); return 0; } else if (conn) { log_fn(LOG_PROTOCOL_WARN, domain, "resolve request for known stream; dropping."); return 0; } else if (circ->purpose != CIRCUIT_PURPOSE_OR) { log_fn(LOG_PROTOCOL_WARN, domain, "resolve request on circ with purpose %d; dropping", circ->purpose); return 0; } connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ)); return 0; case RELAY_COMMAND_RESOLVED: if (conn) { log_fn(LOG_PROTOCOL_WARN, domain, "'resolved' unsupported while open. Closing circ."); return -END_CIRC_REASON_TORPROTOCOL; } log_info(domain, "'resolved' received, no conn attached anymore. Ignoring."); return 0; case RELAY_COMMAND_ESTABLISH_INTRO: case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: case RELAY_COMMAND_INTRODUCE1: case RELAY_COMMAND_INTRODUCE2: case RELAY_COMMAND_INTRODUCE_ACK: case RELAY_COMMAND_RENDEZVOUS1: case RELAY_COMMAND_RENDEZVOUS2: case RELAY_COMMAND_INTRO_ESTABLISHED: case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: rend_process_relay_cell(circ, layer_hint, rh.command, rh.length, cell->payload+RELAY_HEADER_SIZE); return 0; } log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received unknown relay command %d. Perhaps the other side is using " "a newer version of Tor? Dropping.", rh.command); return 0; /* for forward compatibility, don't kill the circuit */ } /** How many relay_data cells have we built, ever? */ uint64_t stats_n_data_cells_packaged = 0; /** How many bytes of data have we put in relay_data cells have we built, * ever? This would be RELAY_PAYLOAD_SIZE*stats_n_data_cells_packaged if * every relay cell we ever sent were completely full of data. */ uint64_t stats_n_data_bytes_packaged = 0; /** How many relay_data cells have we received, ever? */ uint64_t stats_n_data_cells_received = 0; /** How many bytes of data have we received relay_data cells, ever? This would * be RELAY_PAYLOAD_SIZE*stats_n_data_cells_packaged if every relay cell we * ever received were completely full of data. */ uint64_t stats_n_data_bytes_received = 0; /** If conn has an entire relay payload of bytes on its inbuf (or * package_partial is true), and the appropriate package windows aren't * empty, grab a cell and send it down the circuit. * * If *max_cells is given, package no more than max_cells. Decrement * *max_cells by the number of cells packaged. * * Return -1 (and send a RELAY_COMMAND_END cell if necessary) if conn should * be marked for close, else return 0. */ int connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, int *max_cells) { size_t bytes_to_process, length; char payload[CELL_PAYLOAD_SIZE]; circuit_t *circ; const unsigned domain = conn->base_.type == CONN_TYPE_AP ? LD_APP : LD_EXIT; int sending_from_optimistic = 0; entry_connection_t *entry_conn = conn->base_.type == CONN_TYPE_AP ? EDGE_TO_ENTRY_CONN(conn) : NULL; const int sending_optimistically = entry_conn && conn->base_.type == CONN_TYPE_AP && conn->base_.state != AP_CONN_STATE_OPEN; crypt_path_t *cpath_layer = conn->cpath_layer; tor_assert(conn); if (conn->base_.marked_for_close) { log_warn(LD_BUG, "called on conn that's already marked for close at %s:%d.", conn->base_.marked_for_close_file, conn->base_.marked_for_close); return 0; } if (max_cells && *max_cells <= 0) return 0; repeat_connection_edge_package_raw_inbuf: circ = circuit_get_by_edge_conn(conn); if (!circ) { log_info(domain,"conn has no circuit! Closing."); conn->end_reason = END_STREAM_REASON_CANT_ATTACH; return -1; } if (circuit_consider_stop_edge_reading(circ, cpath_layer)) return 0; if (conn->package_window <= 0) { log_info(domain,"called with package_window %d. Skipping.", conn->package_window); connection_stop_reading(TO_CONN(conn)); return 0; } sending_from_optimistic = entry_conn && entry_conn->sending_optimistic_data != NULL; if (PREDICT_UNLIKELY(sending_from_optimistic)) { bytes_to_process = generic_buffer_len(entry_conn->sending_optimistic_data); if (PREDICT_UNLIKELY(!bytes_to_process)) { log_warn(LD_BUG, "sending_optimistic_data was non-NULL but empty"); bytes_to_process = connection_get_inbuf_len(TO_CONN(conn)); sending_from_optimistic = 0; } } else { bytes_to_process = connection_get_inbuf_len(TO_CONN(conn)); } if (!bytes_to_process) return 0; if (!package_partial && bytes_to_process < RELAY_PAYLOAD_SIZE) return 0; if (bytes_to_process > RELAY_PAYLOAD_SIZE) { length = RELAY_PAYLOAD_SIZE; } else { length = bytes_to_process; } stats_n_data_bytes_packaged += length; stats_n_data_cells_packaged += 1; if (PREDICT_UNLIKELY(sending_from_optimistic)) { /* XXXX We could be more efficient here by sometimes packing * previously-sent optimistic data in the same cell with data * from the inbuf. */ generic_buffer_get(entry_conn->sending_optimistic_data, payload, length); if (!generic_buffer_len(entry_conn->sending_optimistic_data)) { generic_buffer_free(entry_conn->sending_optimistic_data); entry_conn->sending_optimistic_data = NULL; } } else { connection_fetch_from_buf(payload, length, TO_CONN(conn)); } log_debug(domain,TOR_SOCKET_T_FORMAT": Packaging %d bytes (%d waiting).", conn->base_.s, (int)length, (int)connection_get_inbuf_len(TO_CONN(conn))); if (sending_optimistically && !sending_from_optimistic) { /* This is new optimistic data; remember it in case we need to detach and retry */ if (!entry_conn->pending_optimistic_data) entry_conn->pending_optimistic_data = generic_buffer_new(); generic_buffer_add(entry_conn->pending_optimistic_data, payload, length); } if (connection_edge_send_command(conn, RELAY_COMMAND_DATA, payload, length) < 0 ) /* circuit got marked for close, don't continue, don't need to mark conn */ return 0; if (!cpath_layer) { /* non-rendezvous exit */ tor_assert(circ->package_window > 0); circ->package_window--; } else { /* we're an AP, or an exit on a rendezvous circ */ tor_assert(cpath_layer->package_window > 0); cpath_layer->package_window--; } if (--conn->package_window <= 0) { /* is it 0 after decrement? */ connection_stop_reading(TO_CONN(conn)); log_debug(domain,"conn->package_window reached 0."); circuit_consider_stop_edge_reading(circ, cpath_layer); return 0; /* don't process the inbuf any more */ } log_debug(domain,"conn->package_window is now %d",conn->package_window); if (max_cells) { *max_cells -= 1; if (*max_cells <= 0) return 0; } /* handle more if there's more, or return 0 if there isn't */ goto repeat_connection_edge_package_raw_inbuf; } /** Called when we've just received a relay data cell, when * we've just finished flushing all bytes to stream conn, * or when we've flushed *some* bytes to the stream conn. * * If conn->outbuf is not too full, and our deliver window is * low, send back a suitable number of stream-level sendme cells. */ void connection_edge_consider_sending_sendme(edge_connection_t *conn) { circuit_t *circ; if (connection_outbuf_too_full(TO_CONN(conn))) return; circ = circuit_get_by_edge_conn(conn); if (!circ) { /* this can legitimately happen if the destroy has already * arrived and torn down the circuit */ log_info(LD_APP,"No circuit associated with conn. Skipping."); return; } while (conn->deliver_window <= STREAMWINDOW_START - STREAMWINDOW_INCREMENT) { log_debug(conn->base_.type == CONN_TYPE_AP ?LD_APP:LD_EXIT, "Outbuf %d, Queuing stream sendme.", (int)conn->base_.outbuf_flushlen); conn->deliver_window += STREAMWINDOW_INCREMENT; if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME, NULL, 0) < 0) { log_warn(LD_APP,"connection_edge_send_command failed. Skipping."); return; /* the circuit's closed, don't continue */ } } } /** The circuit circ has received a circuit-level sendme * (on hop layer_hint, if we're the OP). Go through all the * attached streams and let them resume reading and packaging, if * their stream windows allow it. */ static void circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) { if (circuit_queue_streams_are_blocked(circ)) { log_debug(layer_hint?LD_APP:LD_EXIT,"Too big queue, no resuming"); return; } log_debug(layer_hint?LD_APP:LD_EXIT,"resuming"); if (CIRCUIT_IS_ORIGIN(circ)) circuit_resume_edge_reading_helper(TO_ORIGIN_CIRCUIT(circ)->p_streams, circ, layer_hint); else circuit_resume_edge_reading_helper(TO_OR_CIRCUIT(circ)->n_streams, circ, layer_hint); } void stream_choice_seed_weak_rng(void) { crypto_seed_weak_rng(&stream_choice_rng); } /** A helper function for circuit_resume_edge_reading() above. * The arguments are the same, except that conn is the head * of a linked list of edge streams that should each be considered. */ static int circuit_resume_edge_reading_helper(edge_connection_t *first_conn, circuit_t *circ, crypt_path_t *layer_hint) { edge_connection_t *conn; int n_packaging_streams, n_streams_left; int packaged_this_round; int cells_on_queue; int cells_per_conn; edge_connection_t *chosen_stream = NULL; int max_to_package; if (first_conn == NULL) { /* Don't bother to try to do the rest of this if there are no connections * to resume. */ return 0; } /* How many cells do we have space for? It will be the minimum of * the number needed to exhaust the package window, and the minimum * needed to fill the cell queue. */ max_to_package = circ->package_window; if (CIRCUIT_IS_ORIGIN(circ)) { cells_on_queue = circ->n_chan_cells.n; } else { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); cells_on_queue = or_circ->p_chan_cells.n; } if (CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue < max_to_package) max_to_package = CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue; /* Once we used to start listening on the streams in the order they * appeared in the linked list. That leads to starvation on the * streams that appeared later on the list, since the first streams * would always get to read first. Instead, we just pick a random * stream on the list, and enable reading for streams starting at that * point (and wrapping around as if the list were circular). It would * probably be better to actually remember which streams we've * serviced in the past, but this is simple and effective. */ /* Select a stream uniformly at random from the linked list. We * don't need cryptographic randomness here. */ { int num_streams = 0; for (conn = first_conn; conn; conn = conn->next_stream) { num_streams++; if (tor_weak_random_one_in_n(&stream_choice_rng, num_streams)) { chosen_stream = conn; } /* Invariant: chosen_stream has been chosen uniformly at random from * among the first num_streams streams on first_conn. * * (Note that we iterate over every stream on the circuit, so that after * we've considered the first stream, we've chosen it with P=1; and * after we consider the second stream, we've switched to it with P=1/2 * and stayed with the first stream with P=1/2; and after we've * considered the third stream, we've switched to it with P=1/3 and * remained with one of the first two streams with P=(2/3), giving each * one P=(1/2)(2/3) )=(1/3).) */ } } /* Count how many non-marked streams there are that have anything on * their inbuf, and enable reading on all of the connections. */ n_packaging_streams = 0; /* Activate reading starting from the chosen stream */ for (conn=chosen_stream; conn; conn = conn->next_stream) { /* Start reading for the streams starting from here */ if (conn->base_.marked_for_close || conn->package_window <= 0) continue; if (!layer_hint || conn->cpath_layer == layer_hint) { connection_start_reading(TO_CONN(conn)); if (connection_get_inbuf_len(TO_CONN(conn)) > 0) ++n_packaging_streams; } } /* Go back and do the ones we skipped, circular-style */ for (conn = first_conn; conn != chosen_stream; conn = conn->next_stream) { if (conn->base_.marked_for_close || conn->package_window <= 0) continue; if (!layer_hint || conn->cpath_layer == layer_hint) { connection_start_reading(TO_CONN(conn)); if (connection_get_inbuf_len(TO_CONN(conn)) > 0) ++n_packaging_streams; } } if (n_packaging_streams == 0) /* avoid divide-by-zero */ return 0; again: cells_per_conn = CEIL_DIV(max_to_package, n_packaging_streams); packaged_this_round = 0; n_streams_left = 0; /* Iterate over all connections. Package up to cells_per_conn cells on * each. Update packaged_this_round with the total number of cells * packaged, and n_streams_left with the number that still have data to * package. */ for (conn=first_conn; conn; conn=conn->next_stream) { if (conn->base_.marked_for_close || conn->package_window <= 0) continue; if (!layer_hint || conn->cpath_layer == layer_hint) { int n = cells_per_conn, r; /* handle whatever might still be on the inbuf */ r = connection_edge_package_raw_inbuf(conn, 1, &n); /* Note how many we packaged */ packaged_this_round += (cells_per_conn-n); if (r<0) { /* Problem while packaging. (We already sent an end cell if * possible) */ connection_mark_for_close(TO_CONN(conn)); continue; } /* If there's still data to read, we'll be coming back to this stream. */ if (connection_get_inbuf_len(TO_CONN(conn))) ++n_streams_left; /* If the circuit won't accept any more data, return without looking * at any more of the streams. Any connections that should be stopped * have already been stopped by connection_edge_package_raw_inbuf. */ if (circuit_consider_stop_edge_reading(circ, layer_hint)) return -1; /* XXXX should we also stop immediately if we fill up the cell queue? * Probably. */ } } /* If we made progress, and we are willing to package more, and there are * any streams left that want to package stuff... try again! */ if (packaged_this_round && packaged_this_round < max_to_package && n_streams_left) { max_to_package -= packaged_this_round; n_packaging_streams = n_streams_left; goto again; } return 0; } /** Check if the package window for circ is empty (at * hop layer_hint if it's defined). * * If yes, tell edge streams to stop reading and return 1. * Else return 0. */ static int circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) { edge_connection_t *conn = NULL; unsigned domain = layer_hint ? LD_APP : LD_EXIT; if (!layer_hint) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); log_debug(domain,"considering circ->package_window %d", circ->package_window); if (circ->package_window <= 0) { log_debug(domain,"yes, not-at-origin. stopped."); for (conn = or_circ->n_streams; conn; conn=conn->next_stream) connection_stop_reading(TO_CONN(conn)); return 1; } return 0; } /* else, layer hint is defined, use it */ log_debug(domain,"considering layer_hint->package_window %d", layer_hint->package_window); if (layer_hint->package_window <= 0) { log_debug(domain,"yes, at-origin. stopped."); for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn; conn=conn->next_stream) { if (conn->cpath_layer == layer_hint) connection_stop_reading(TO_CONN(conn)); } return 1; } return 0; } /** Check if the deliver_window for circuit circ (at hop * layer_hint if it's defined) is low enough that we should * send a circuit-level sendme back down the circuit. If so, send * enough sendmes that the window would be overfull if we sent any * more. */ static void circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint) { // log_fn(LOG_INFO,"Considering: layer_hint is %s", // layer_hint ? "defined" : "null"); while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <= CIRCWINDOW_START - CIRCWINDOW_INCREMENT) { log_debug(LD_CIRC,"Queuing circuit sendme."); if (layer_hint) layer_hint->deliver_window += CIRCWINDOW_INCREMENT; else circ->deliver_window += CIRCWINDOW_INCREMENT; if (relay_send_command_from_edge(0, circ, RELAY_COMMAND_SENDME, NULL, 0, layer_hint) < 0) { log_warn(LD_CIRC, "relay_send_command_from_edge failed. Circuit's closed."); return; /* the circuit's closed, don't continue */ } } } #ifdef ACTIVE_CIRCUITS_PARANOIA #define assert_cmux_ok_paranoid(chan) \ assert_circuit_mux_okay(chan) #else #define assert_cmux_ok_paranoid(chan) #endif /** The total number of cells we have allocated from the memory pool. */ static size_t total_cells_allocated = 0; /** A memory pool to allocate packed_cell_t objects. */ static mp_pool_t *cell_pool = NULL; /** Memory pool to allocate insertion_time_elem_t objects used for cell * statistics. */ static mp_pool_t *it_pool = NULL; /** Allocate structures to hold cells. */ void init_cell_pool(void) { tor_assert(!cell_pool); cell_pool = mp_pool_new(sizeof(packed_cell_t), 128*1024); } /** Free all storage used to hold cells (and insertion times if we measure * cell statistics). */ void free_cell_pool(void) { /* Maybe we haven't called init_cell_pool yet; need to check for it. */ if (cell_pool) { mp_pool_destroy(cell_pool); cell_pool = NULL; } if (it_pool) { mp_pool_destroy(it_pool); it_pool = NULL; } } /** Free excess storage in cell pool. */ void clean_cell_pool(void) { tor_assert(cell_pool); mp_pool_clean(cell_pool, 0, 1); } /** Release storage held by cell. */ static INLINE void packed_cell_free_unchecked(packed_cell_t *cell) { --total_cells_allocated; mp_pool_release(cell); } /** Allocate and return a new packed_cell_t. */ static INLINE packed_cell_t * packed_cell_new(void) { ++total_cells_allocated; return mp_pool_get(cell_pool); } /** Return a packed cell used outside by channel_t lower layer */ void packed_cell_free(packed_cell_t *cell) { packed_cell_free_unchecked(cell); } /** Log current statistics for cell pool allocation at log level * severity. */ void dump_cell_pool_usage(int severity) { circuit_t *c; int n_circs = 0; int n_cells = 0; for (c = circuit_get_global_list_(); c; c = c->next) { n_cells += c->n_chan_cells.n; if (!CIRCUIT_IS_ORIGIN(c)) n_cells += TO_OR_CIRCUIT(c)->p_chan_cells.n; ++n_circs; } tor_log(severity, LD_MM, "%d cells allocated on %d circuits. %d cells leaked.", n_cells, n_circs, (int)total_cells_allocated - n_cells); mp_pool_log_status(cell_pool, severity); } /** Allocate a new copy of packed cell. */ static INLINE packed_cell_t * packed_cell_copy(const cell_t *cell, int wide_circ_ids) { packed_cell_t *c = packed_cell_new(); cell_pack(c, cell, wide_circ_ids); c->next = NULL; return c; } /** Append cell to the end of queue. */ void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell) { if (queue->tail) { tor_assert(!queue->tail->next); queue->tail->next = cell; } else { queue->head = cell; } queue->tail = cell; cell->next = NULL; ++queue->n; } /** Append a newly allocated copy of cell to the end of queue */ void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell, int wide_circ_ids) { struct timeval now; packed_cell_t *copy = packed_cell_copy(cell, wide_circ_ids); tor_gettimeofday_cached(&now); copy->inserted_time = (uint32_t)tv_to_msec(&now); /* Remember the time when this cell was put in the queue. */ /*XXXX This may be obsoleted by inserted_time */ if (get_options()->CellStatistics) { uint32_t added; insertion_time_queue_t *it_queue = queue->insertion_times; if (!it_pool) it_pool = mp_pool_new(sizeof(insertion_time_elem_t), 1024); #define SECONDS_IN_A_DAY 86400L added = (uint32_t)(((now.tv_sec % SECONDS_IN_A_DAY) * 100L) + ((uint32_t)now.tv_usec / (uint32_t)10000L)); if (!it_queue) { it_queue = tor_malloc_zero(sizeof(insertion_time_queue_t)); queue->insertion_times = it_queue; } if (it_queue->last && it_queue->last->insertion_time == added) { it_queue->last->counter++; } else { insertion_time_elem_t *elem = mp_pool_get(it_pool); elem->next = NULL; elem->insertion_time = added; elem->counter = 1; if (it_queue->last) { it_queue->last->next = elem; it_queue->last = elem; } else { it_queue->first = it_queue->last = elem; } } } cell_queue_append(queue, copy); } /** Remove and free every cell in queue. */ void cell_queue_clear(cell_queue_t *queue) { packed_cell_t *cell, *next; cell = queue->head; while (cell) { next = cell->next; packed_cell_free_unchecked(cell); cell = next; } queue->head = queue->tail = NULL; queue->n = 0; if (queue->insertion_times) { while (queue->insertion_times->first) { insertion_time_elem_t *elem = queue->insertion_times->first; queue->insertion_times->first = elem->next; mp_pool_release(elem); } tor_free(queue->insertion_times); } } /** Extract and return the cell at the head of queue; return NULL if * queue is empty. */ static INLINE packed_cell_t * cell_queue_pop(cell_queue_t *queue) { packed_cell_t *cell = queue->head; if (!cell) return NULL; queue->head = cell->next; if (cell == queue->tail) { tor_assert(!queue->head); queue->tail = NULL; } --queue->n; return cell; } /** Return the total number of bytes used for each packed_cell in a queue. * Approximate. */ size_t packed_cell_mem_cost(void) { return sizeof(packed_cell_t) + MP_POOL_ITEM_OVERHEAD + get_options()->CellStatistics ? (sizeof(insertion_time_elem_t)+MP_POOL_ITEM_OVERHEAD) : 0; } /** Check whether we've got too much space used for cells. If so, * call the OOM handler and return 1. Otherwise, return 0. */ static int cell_queues_check_size(void) { size_t alloc = total_cells_allocated * packed_cell_mem_cost(); if (alloc >= get_options()->MaxMemInCellQueues) { circuits_handle_oom(alloc); return 1; } return 0; } /** * Update the number of cells available on the circuit's n_chan or p_chan's * circuit mux. */ void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction, const char *file, int lineno) { channel_t *chan = NULL; or_circuit_t *or_circ = NULL; circuitmux_t *cmux = NULL; tor_assert(circ); /* Okay, get the channel */ if (direction == CELL_DIRECTION_OUT) { chan = circ->n_chan; } else { or_circ = TO_OR_CIRCUIT(circ); chan = or_circ->p_chan; } tor_assert(chan); tor_assert(chan->cmux); /* Now get the cmux */ cmux = chan->cmux; /* Cmux sanity check */ if (! circuitmux_is_circuit_attached(cmux, circ)) { log_warn(LD_BUG, "called on non-attachd circuit from %s:%d", file, lineno); return; } tor_assert(circuitmux_attached_circuit_direction(cmux, circ) == direction); assert_cmux_ok_paranoid(chan); /* Update the number of cells we have for the circuit mux */ if (direction == CELL_DIRECTION_OUT) { circuitmux_set_num_cells(cmux, circ, circ->n_chan_cells.n); } else { circuitmux_set_num_cells(cmux, circ, or_circ->p_chan_cells.n); } assert_cmux_ok_paranoid(chan); } /** Remove all circuits from the cmux on chan. */ void channel_unlink_all_circuits(channel_t *chan) { tor_assert(chan); tor_assert(chan->cmux); circuitmux_detach_all_circuits(chan->cmux); chan->num_n_circuits = 0; chan->num_p_circuits = 0; } /** Block (if block is true) or unblock (if block is false) * every edge connection that is using circ to write to chan, * and start or stop reading as appropriate. * * If stream_id is nonzero, block only the edge connection whose * stream_id matches it. * * Returns the number of streams whose status we changed. */ static int set_streams_blocked_on_circ(circuit_t *circ, channel_t *chan, int block, streamid_t stream_id) { edge_connection_t *edge = NULL; int n = 0; if (circ->n_chan == chan) { circ->streams_blocked_on_n_chan = block; if (CIRCUIT_IS_ORIGIN(circ)) edge = TO_ORIGIN_CIRCUIT(circ)->p_streams; } else { circ->streams_blocked_on_p_chan = block; tor_assert(!CIRCUIT_IS_ORIGIN(circ)); edge = TO_OR_CIRCUIT(circ)->n_streams; } for (; edge; edge = edge->next_stream) { connection_t *conn = TO_CONN(edge); if (stream_id && edge->stream_id != stream_id) continue; if (edge->edge_blocked_on_circ != block) { ++n; edge->edge_blocked_on_circ = block; } if (!conn->read_event && !HAS_BUFFEREVENT(conn)) { /* This connection is a placeholder for something; probably a DNS * request. It can't actually stop or start reading.*/ continue; } if (block) { if (connection_is_reading(conn)) connection_stop_reading(conn); } else { /* Is this right? */ if (!connection_is_reading(conn)) connection_start_reading(conn); } } return n; } /** Pull as many cells as possible (but no more than max) from the * queue of the first active circuit on chan, and write them to * chan->outbuf. Return the number of cells written. Advance * the active circuit pointer to the next active circuit in the ring. */ int channel_flush_from_first_active_circuit(channel_t *chan, int max) { circuitmux_t *cmux = NULL; int n_flushed = 0; cell_queue_t *queue; circuit_t *circ; or_circuit_t *or_circ; int streams_blocked; packed_cell_t *cell; /* Get the cmux */ tor_assert(chan); tor_assert(chan->cmux); cmux = chan->cmux; /* Main loop: pick a circuit, send a cell, update the cmux */ while (n_flushed < max) { circ = circuitmux_get_first_active_circuit(cmux); /* If it returns NULL, no cells left to send */ if (!circ) break; assert_cmux_ok_paranoid(chan); if (circ->n_chan == chan) { queue = &circ->n_chan_cells; streams_blocked = circ->streams_blocked_on_n_chan; } else { or_circ = TO_OR_CIRCUIT(circ); tor_assert(or_circ->p_chan == chan); queue = &TO_OR_CIRCUIT(circ)->p_chan_cells; streams_blocked = circ->streams_blocked_on_p_chan; } /* Circuitmux told us this was active, so it should have cells */ tor_assert(queue->n > 0); /* * Get just one cell here; once we've sent it, that can change the circuit * selection, so we have to loop around for another even if this circuit * has more than one. */ cell = cell_queue_pop(queue); /* Calculate the exact time that this cell has spent in the queue. */ if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) { struct timeval tvnow; uint32_t flushed; uint32_t cell_waiting_time; insertion_time_queue_t *it_queue = queue->insertion_times; tor_gettimeofday_cached(&tvnow); flushed = (uint32_t)((tvnow.tv_sec % SECONDS_IN_A_DAY) * 100L + (uint32_t)tvnow.tv_usec / (uint32_t)10000L); if (!it_queue || !it_queue->first) { log_info(LD_GENERAL, "Cannot determine insertion time of cell. " "Looks like the CellStatistics option was " "recently enabled."); } else { insertion_time_elem_t *elem = it_queue->first; or_circ = TO_OR_CIRCUIT(circ); cell_waiting_time = (uint32_t)((flushed * 10L + SECONDS_IN_A_DAY * 1000L - elem->insertion_time * 10L) % (SECONDS_IN_A_DAY * 1000L)); #undef SECONDS_IN_A_DAY elem->counter--; if (elem->counter < 1) { it_queue->first = elem->next; if (elem == it_queue->last) it_queue->last = NULL; mp_pool_release(elem); } or_circ->total_cell_waiting_time += cell_waiting_time; or_circ->processed_cells++; } } /* If we just flushed our queue and this circuit is used for a * tunneled directory request, possibly advance its state. */ if (queue->n == 0 && chan->dirreq_id) geoip_change_dirreq_state(chan->dirreq_id, DIRREQ_TUNNELED, DIRREQ_CIRC_QUEUE_FLUSHED); /* Now send the cell */ channel_write_packed_cell(chan, cell); cell = NULL; /* * Don't packed_cell_free_unchecked(cell) here because the channel will * do so when it gets out of the channel queue (probably already did, in * which case that was an immediate double-free bug). */ /* Update the counter */ ++n_flushed; /* * Now update the cmux; tell it we've just sent a cell, and how many * we have left. */ circuitmux_notify_xmit_cells(cmux, circ, 1); circuitmux_set_num_cells(cmux, circ, queue->n); if (queue->n == 0) log_debug(LD_GENERAL, "Made a circuit inactive."); /* Is the cell queue low enough to unblock all the streams that are waiting * to write to this circuit? */ if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE) set_streams_blocked_on_circ(circ, chan, 0, 0); /* unblock streams */ /* If n_flushed < max still, loop around and pick another circuit */ } /* Okay, we're done sending now */ assert_cmux_ok_paranoid(chan); return n_flushed; } /** Add cell to the queue of circ writing to chan * transmitting in direction. */ void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, cell_t *cell, cell_direction_t direction, streamid_t fromstream) { or_circuit_t *orcirc = NULL; cell_queue_t *queue; int streams_blocked; if (circ->marked_for_close) return; if (direction == CELL_DIRECTION_OUT) { queue = &circ->n_chan_cells; streams_blocked = circ->streams_blocked_on_n_chan; } else { orcirc = TO_OR_CIRCUIT(circ); queue = &orcirc->p_chan_cells; streams_blocked = circ->streams_blocked_on_p_chan; } /* * Disabling this for now because of a possible guard discovery attack */ #if 0 /* Are we a middle circuit about to exceed ORCIRC_MAX_MIDDLE_CELLS? */ if ((circ->n_chan != NULL) && CIRCUIT_IS_ORCIRC(circ)) { orcirc = TO_OR_CIRCUIT(circ); if (orcirc->p_chan) { if (queue->n + 1 >= ORCIRC_MAX_MIDDLE_CELLS) { /* Queueing this cell would put queue over the cap */ log_warn(LD_CIRC, "Got a cell exceeding the cap of %u in the %s direction " "on middle circ ID %u on chan ID " U64_FORMAT "; killing the circuit.", ORCIRC_MAX_MIDDLE_CELLS, (direction == CELL_DIRECTION_OUT) ? "n" : "p", (direction == CELL_DIRECTION_OUT) ? circ->n_circ_id : orcirc->p_circ_id, U64_PRINTF_ARG( (direction == CELL_DIRECTION_OUT) ? circ->n_chan->global_identifier : orcirc->p_chan->global_identifier)); circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); return; } } } #endif cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids); if (PREDICT_UNLIKELY(cell_queues_check_size())) { /* We ran the OOM handler */ if (circ->marked_for_close) return; } /* If we have too many cells on the circuit, we should stop reading from * the edge streams for a while. */ if (!streams_blocked && queue->n >= CELL_QUEUE_HIGHWATER_SIZE) set_streams_blocked_on_circ(circ, chan, 1, 0); /* block streams */ if (streams_blocked && fromstream) { /* This edge connection is apparently not blocked; block it. */ set_streams_blocked_on_circ(circ, chan, 1, fromstream); } update_circuit_on_cmux(circ, direction); if (queue->n == 1) { /* This was the first cell added to the queue. We just made this * circuit active. */ log_debug(LD_GENERAL, "Made a circuit active."); } if (!channel_has_queued_writes(chan)) { /* There is no data at all waiting to be sent on the outbuf. Add a * cell, so that we can notice when it gets flushed, flushed_some can * get called, and we can start putting more data onto the buffer then. */ log_debug(LD_GENERAL, "Primed a buffer."); channel_flush_from_first_active_circuit(chan, 1); } } /** Append an encoded value of addr to payload_out, which must * have at least 18 bytes of free space. The encoding is, as specified in * tor-spec.txt: * RESOLVED_TYPE_IPV4 or RESOLVED_TYPE_IPV6 [1 byte] * LENGTH [1 byte] * ADDRESS [length bytes] * Return the number of bytes added, or -1 on error */ int append_address_to_payload(uint8_t *payload_out, const tor_addr_t *addr) { uint32_t a; switch (tor_addr_family(addr)) { case AF_INET: payload_out[0] = RESOLVED_TYPE_IPV4; payload_out[1] = 4; a = tor_addr_to_ipv4n(addr); memcpy(payload_out+2, &a, 4); return 6; case AF_INET6: payload_out[0] = RESOLVED_TYPE_IPV6; payload_out[1] = 16; memcpy(payload_out+2, tor_addr_to_in6_addr8(addr), 16); return 18; case AF_UNSPEC: default: return -1; } } /** Given payload_len bytes at payload, starting with an address * encoded as by append_address_to_payload(), try to decode the address into * *addr_out. Return the next byte in the payload after the address on * success, or NULL on failure. */ const uint8_t * decode_address_from_payload(tor_addr_t *addr_out, const uint8_t *payload, int payload_len) { if (payload_len < 2) return NULL; if (payload_len < 2+payload[1]) return NULL; switch (payload[0]) { case RESOLVED_TYPE_IPV4: if (payload[1] != 4) return NULL; tor_addr_from_ipv4n(addr_out, get_uint32(payload+2)); break; case RESOLVED_TYPE_IPV6: if (payload[1] != 16) return NULL; tor_addr_from_ipv6_bytes(addr_out, (char*)(payload+2)); break; default: tor_addr_make_unspec(addr_out); break; } return payload + 2 + payload[1]; } /** Remove all the cells queued on circ for chan. */ void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan) { cell_queue_t *queue; cell_direction_t direction; if (circ->n_chan == chan) { queue = &circ->n_chan_cells; direction = CELL_DIRECTION_OUT; } else { or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); tor_assert(orcirc->p_chan == chan); queue = &orcirc->p_chan_cells; direction = CELL_DIRECTION_IN; } /* Clear the queue */ cell_queue_clear(queue); /* Update the cell counter in the cmux */ if (chan->cmux && circuitmux_is_circuit_attached(chan->cmux, circ)) update_circuit_on_cmux(circ, direction); } /** Fail with an assert if the circuit mux on chan is corrupt */ void assert_circuit_mux_okay(channel_t *chan) { tor_assert(chan); tor_assert(chan->cmux); circuitmux_assert_okay(chan->cmux); } /** Return 1 if we shouldn't restart reading on this circuit, even if * we get a SENDME. Else return 0. */ static int circuit_queue_streams_are_blocked(circuit_t *circ) { if (CIRCUIT_IS_ORIGIN(circ)) { return circ->streams_blocked_on_n_chan; } else { return circ->streams_blocked_on_p_chan; } } tor-0.2.4.20/src/or/dirserv.h0000644000175000017500000001513312255745673012543 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file dirserv.h * \brief Header file for dirserv.c. **/ #ifndef TOR_DIRSERV_H #define TOR_DIRSERV_H /** What fraction (1 over this number) of the relay ID space do we * (as a directory authority) launch connections to at each reachability * test? */ #define REACHABILITY_MODULO_PER_TEST 128 /** How often (in seconds) do we launch reachability tests? */ #define REACHABILITY_TEST_INTERVAL 10 /** How many seconds apart are the reachability tests for a given relay? */ #define REACHABILITY_TEST_CYCLE_PERIOD \ (REACHABILITY_TEST_INTERVAL*REACHABILITY_MODULO_PER_TEST) /** Maximum length of an exit policy summary. */ #define MAX_EXITPOLICY_SUMMARY_LEN 1000 /** Maximum allowable length of a version line in a networkstatus. */ #define MAX_V_LINE_LEN 128 int connection_dirserv_flushed_some(dir_connection_t *conn); int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk); int dirserv_load_fingerprint_file(void); void dirserv_free_fingerprint_list(void); const char *dirserv_get_nickname_by_digest(const char *digest); enum was_router_added_t dirserv_add_multiple_descriptors( const char *desc, uint8_t purpose, const char *source, const char **msg); enum was_router_added_t dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source); void dirserv_set_router_is_running(routerinfo_t *router, time_t now); int list_server_status_v1(smartlist_t *routers, char **router_status_out, int for_controller); int dirserv_dump_directory_to_string(char **dir_out, crypto_pk_t *private_key); char *dirserv_get_flag_thresholds_line(void); int directory_fetches_from_authorities(const or_options_t *options); int directory_fetches_dir_info_early(const or_options_t *options); int directory_fetches_dir_info_later(const or_options_t *options); int directory_caches_v2_dir_info(const or_options_t *options); int directory_caches_unknown_auth_certs(const or_options_t *options); int directory_caches_dir_info(const or_options_t *options); int directory_permits_begindir_requests(const or_options_t *options); int directory_permits_controller_requests(const or_options_t *options); int directory_too_idle_to_fetch_descriptors(const or_options_t *options, time_t now); void directory_set_dirty(void); cached_dir_t *dirserv_get_directory(void); cached_dir_t *dirserv_get_runningrouters(void); cached_dir_t *dirserv_get_consensus(const char *flavor_name); void dirserv_set_cached_networkstatus_v2(const char *directory, const char *identity, time_t published); void dirserv_set_cached_consensus_networkstatus(const char *consensus, const char *flavor_name, const digests_t *digests, time_t published); void dirserv_clear_old_networkstatuses(time_t cutoff); void dirserv_clear_old_v1_info(time_t now); void dirserv_get_networkstatus_v2(smartlist_t *result, const char *key); void dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result, const char *key); int dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key, const char **msg, int for_unencrypted_conn, int is_extrainfo); int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key, const char **msg); void dirserv_orconn_tls_done(const tor_addr_t *addr, uint16_t or_port, const char *digest_rcvd); int dirserv_should_launch_reachability_test(const routerinfo_t *ri, const routerinfo_t *ri_old); void dirserv_single_reachability_test(time_t now, routerinfo_t *router); void dirserv_test_reachability(time_t now); int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, int complain, int *valid_out); uint32_t dirserv_router_get_status(const routerinfo_t *router, const char **msg); void dirserv_set_node_flags_from_authoritative_status(node_t *node, uint32_t authstatus); int dirserv_would_reject_router(const routerstatus_t *rs); int dirserv_remove_old_statuses(smartlist_t *fps, time_t cutoff); int dirserv_have_any_serverdesc(smartlist_t *fps, int spool_src); int dirserv_have_any_microdesc(const smartlist_t *fps); size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs, int compressed); size_t dirserv_estimate_microdesc_size(const smartlist_t *fps, int compressed); char *routerstatus_format_entry( const routerstatus_t *rs, const char *platform, routerstatus_format_type_t format, const vote_routerstatus_t *vrs); void dirserv_free_all(void); void cached_dir_decref(cached_dir_t *d); cached_dir_t *new_cached_dir(char *s, time_t published); #ifdef DIRSERV_PRIVATE /* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */ #define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */ int measured_bw_line_parse(measured_bw_line_t *out, const char *line); int measured_bw_line_apply(measured_bw_line_t *parsed_line, smartlist_t *routerstatuses); void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, time_t as_of); void dirserv_clear_measured_bw_cache(void); void dirserv_expire_measured_bw_cache(time_t now); int dirserv_get_measured_bw_cache_size(void); int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out, time_t *as_of_out); int dirserv_has_measured_bw(const char *node_id); cached_dir_t *generate_v2_networkstatus_opinion(void); #endif int dirserv_read_measured_bandwidths(const char *from_file, smartlist_t *routerstatuses); #endif tor-0.2.4.20/src/or/fp_pair.c0000644000175000017500000001541612166112777012476 00000000000000/* Copyright (c) 2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "or.h" #include "fp_pair.h" /* Define fp_pair_map_t structures */ struct fp_pair_map_entry_s { HT_ENTRY(fp_pair_map_entry_s) node; void *val; fp_pair_t key; }; struct fp_pair_map_s { HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_s) head; }; /* * Hash function and equality checker for fp_pair_map_t */ /** Compare fp_pair_entry_t objects by key value. */ static INLINE int fp_pair_map_entries_eq(const fp_pair_map_entry_t *a, const fp_pair_map_entry_t *b) { return tor_memeq(&(a->key), &(b->key), sizeof(fp_pair_t)); } /** Return a hash value for an fp_pair_entry_t. */ static INLINE unsigned int fp_pair_map_entry_hash(const fp_pair_map_entry_t *a) { const uint32_t *p; unsigned int hash; p = (const uint32_t *)(a->key.first); /* Hashes are 20 bytes long, so 5 times uint32_t */ hash = p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4]; /* Now XOR in the second fingerprint */ p = (const uint32_t *)(a->key.second); hash ^= p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4]; return hash; } /* * Hash table functions for fp_pair_map_t */ HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node, fp_pair_map_entry_hash, fp_pair_map_entries_eq) HT_GENERATE(fp_pair_map_impl, fp_pair_map_entry_s, node, fp_pair_map_entry_hash, fp_pair_map_entries_eq, 0.6, tor_malloc, tor_realloc, tor_free) /** Constructor to create a new empty map from fp_pair_t to void * */ fp_pair_map_t * fp_pair_map_new(void) { fp_pair_map_t *result; result = tor_malloc(sizeof(fp_pair_map_t)); HT_INIT(fp_pair_map_impl, &result->head); return result; } /** Set the current value for key to val; returns the previous * value for key if one was set, or NULL if one was not. */ void * fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val) { fp_pair_map_entry_t *resolve; fp_pair_map_entry_t search; void *oldval; tor_assert(map); tor_assert(key); tor_assert(val); memcpy(&(search.key), key, sizeof(*key)); resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search); if (resolve) { oldval = resolve->val; resolve->val = val; } else { resolve = tor_malloc_zero(sizeof(fp_pair_map_entry_t)); memcpy(&(resolve->key), key, sizeof(*key)); resolve->val = val; HT_INSERT(fp_pair_map_impl, &(map->head), resolve); oldval = NULL; } return oldval; } /** Set the current value for the key (first, second) to val; returns * the previous value for key if one was set, or NULL if one was not. */ void * fp_pair_map_set_by_digests(fp_pair_map_t *map, const char *first, const char *second, void *val) { fp_pair_t k; tor_assert(first); tor_assert(second); memcpy(k.first, first, DIGEST_LEN); memcpy(k.second, second, DIGEST_LEN); return fp_pair_map_set(map, &k, val); } /** Return the current value associated with key, or NULL if no value is set. */ void * fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key) { fp_pair_map_entry_t *resolve; fp_pair_map_entry_t search; void *val = NULL; tor_assert(map); tor_assert(key); memcpy(&(search.key), key, sizeof(*key)); resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search); if (resolve) val = resolve->val; return val; } /** Return the current value associated the key (first, second), or * NULL if no value is set. */ void * fp_pair_map_get_by_digests(const fp_pair_map_t *map, const char *first, const char *second) { fp_pair_t k; tor_assert(first); tor_assert(second); memcpy(k.first, first, DIGEST_LEN); memcpy(k.second, second, DIGEST_LEN); return fp_pair_map_get(map, &k); } /** Remove the value currently associated with key from the map. * Return the value if one was set, or NULL if there was no entry for * key. The caller must free any storage associated with the * returned value. */ void * fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key) { fp_pair_map_entry_t *resolve; fp_pair_map_entry_t search; void *val = NULL; tor_assert(map); tor_assert(key); memcpy(&(search.key), key, sizeof(*key)); resolve = HT_REMOVE(fp_pair_map_impl, &(map->head), &search); if (resolve) { val = resolve->val; tor_free(resolve); } return val; } /** Remove all entries from map, and deallocate storage for those entries. * If free_val is provided, it is invoked on every value in map. */ void fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*)) { fp_pair_map_entry_t **ent, **next, *this; if (map) { for (ent = HT_START(fp_pair_map_impl, &(map->head)); ent != NULL; ent = next) { this = *ent; next = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), ent); if (free_val) free_val(this->val); tor_free(this); } tor_assert(HT_EMPTY(&(map->head))); HT_CLEAR(fp_pair_map_impl, &(map->head)); tor_free(map); } } /** Return true iff map has no entries. */ int fp_pair_map_isempty(const fp_pair_map_t *map) { tor_assert(map); return HT_EMPTY(&(map->head)); } /** Return the number of items in map. */ int fp_pair_map_size(const fp_pair_map_t *map) { tor_assert(map); return HT_SIZE(&(map->head)); } /** return an iterator pointing to the start of map. */ fp_pair_map_iter_t * fp_pair_map_iter_init(fp_pair_map_t *map) { tor_assert(map); return HT_START(fp_pair_map_impl, &(map->head)); } /** Advance iter a single step to the next entry of map, and return * its new value. */ fp_pair_map_iter_t * fp_pair_map_iter_next(fp_pair_map_t *map, fp_pair_map_iter_t *iter) { tor_assert(map); tor_assert(iter); return HT_NEXT(fp_pair_map_impl, &(map->head), iter); } /** Advance iter a single step to the next entry of map, removing the current * entry, and return its new value. */ fp_pair_map_iter_t * fp_pair_map_iter_next_rmv(fp_pair_map_t *map, fp_pair_map_iter_t *iter) { fp_pair_map_entry_t *rmv; tor_assert(map); tor_assert(iter); tor_assert(*iter); rmv = *iter; iter = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), iter); tor_free(rmv); return iter; } /** Set *key_out and *val_out to the current entry pointed to by iter. */ void fp_pair_map_iter_get(fp_pair_map_iter_t *iter, fp_pair_t *key_out, void **val_out) { tor_assert(iter); tor_assert(*iter); if (key_out) memcpy(key_out, &((*iter)->key), sizeof(fp_pair_t)); if (val_out) *val_out = (*iter)->val; } /** Return true iff iter has advanced past the last entry of its map. */ int fp_pair_map_iter_done(fp_pair_map_iter_t *iter) { return (iter == NULL); } /** Assert if anything has gone wrong with the internal * representation of map. */ void fp_pair_map_assert_ok(const fp_pair_map_t *map) { tor_assert(!fp_pair_map_impl_HT_REP_IS_BAD_(&(map->head))); } tor-0.2.4.20/src/or/circuituse.c0000644000175000017500000025542512255745673013251 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file circuituse.c * \brief Launch the right sort of circuits and attach streams to them. **/ #include "or.h" #include "addressmap.h" #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuitstats.h" #include "circuituse.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "control.h" #include "entrynodes.h" #include "nodelist.h" #include "networkstatus.h" #include "policies.h" #include "rendclient.h" #include "rendcommon.h" #include "rendservice.h" #include "rephist.h" #include "router.h" #include "routerlist.h" /********* START VARIABLES **********/ extern circuit_t *global_circuitlist; /* from circuitlist.c */ /********* END VARIABLES ************/ static void circuit_expire_old_circuits_clientside(void); static void circuit_increment_failure_count(void); /** Return 1 if circ could be returned by circuit_get_best(). * Else return 0. */ static int circuit_is_acceptable(const origin_circuit_t *origin_circ, const entry_connection_t *conn, int must_be_open, uint8_t purpose, int need_uptime, int need_internal, time_t now) { const circuit_t *circ = TO_CIRCUIT(origin_circ); const node_t *exitnode; cpath_build_state_t *build_state; tor_assert(circ); tor_assert(conn); tor_assert(conn->socks_request); if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_chan)) return 0; /* ignore non-open circs */ if (circ->marked_for_close) return 0; /* if this circ isn't our purpose, skip. */ if (purpose == CIRCUIT_PURPOSE_C_REND_JOINED && !must_be_open) { if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND && circ->purpose != CIRCUIT_PURPOSE_C_REND_READY && circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED && circ->purpose != CIRCUIT_PURPOSE_C_REND_JOINED) return 0; } else if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT && !must_be_open) { if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCING && circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) return 0; } else { if (purpose != circ->purpose) return 0; } /* If this is a timed-out hidden service circuit, skip it. */ if (origin_circ->hs_circ_has_timed_out) { return 0; } if (purpose == CIRCUIT_PURPOSE_C_GENERAL || purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { if (circ->timestamp_dirty && circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now) return 0; } if (origin_circ->unusable_for_new_conns) return 0; /* decide if this circ is suitable for this conn */ /* for rend circs, circ->cpath->prev is not the last router in the * circuit, it's the magical extra bob hop. so just check the nickname * of the one we meant to finish at. */ build_state = origin_circ->build_state; exitnode = build_state_get_exit_node(build_state); if (need_uptime && !build_state->need_uptime) return 0; if (need_internal != build_state->is_internal) return 0; if (purpose == CIRCUIT_PURPOSE_C_GENERAL) { tor_addr_t addr; const int family = tor_addr_parse(&addr, conn->socks_request->address); if (!exitnode && !build_state->onehop_tunnel) { log_debug(LD_CIRC,"Not considering circuit with unknown router."); return 0; /* this circuit is screwed and doesn't know it yet, * or is a rendezvous circuit. */ } if (build_state->onehop_tunnel) { if (!conn->want_onehop) { log_debug(LD_CIRC,"Skipping one-hop circuit."); return 0; } tor_assert(conn->chosen_exit_name); if (build_state->chosen_exit) { char digest[DIGEST_LEN]; if (hexdigest_to_digest(conn->chosen_exit_name, digest) < 0) return 0; /* broken digest, we don't want it */ if (tor_memneq(digest, build_state->chosen_exit->identity_digest, DIGEST_LEN)) return 0; /* this is a circuit to somewhere else */ if (tor_digest_is_zero(digest)) { /* we don't know the digest; have to compare addr:port */ if (family < 0 || !tor_addr_eq(&build_state->chosen_exit->addr, &addr) || build_state->chosen_exit->port != conn->socks_request->port) return 0; } } } else { if (conn->want_onehop) { /* don't use three-hop circuits -- that could hurt our anonymity. */ return 0; } } if (origin_circ->prepend_policy && family != -1) { int r = compare_tor_addr_to_addr_policy(&addr, conn->socks_request->port, origin_circ->prepend_policy); if (r == ADDR_POLICY_REJECTED) return 0; } if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) { /* can't exit from this router */ return 0; } } else { /* not general */ const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); if ((edge_conn->rend_data && !origin_circ->rend_data) || (!edge_conn->rend_data && origin_circ->rend_data) || (edge_conn->rend_data && origin_circ->rend_data && rend_cmp_service_ids(edge_conn->rend_data->onion_address, origin_circ->rend_data->onion_address))) { /* this circ is not for this conn */ return 0; } } if (!connection_edge_compatible_with_circuit(conn, origin_circ)) { /* conn needs to be isolated from other conns that have already used * origin_circ */ return 0; } return 1; } /** Return 1 if circuit a is better than circuit b for * conn, and return 0 otherwise. Used by circuit_get_best. */ static int circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob, const entry_connection_t *conn) { const circuit_t *a = TO_CIRCUIT(oa); const circuit_t *b = TO_CIRCUIT(ob); const uint8_t purpose = ENTRY_TO_CONN(conn)->purpose; int a_bits, b_bits; /* If one of the circuits was allowed to live due to relaxing its timeout, * it is definitely worse (it's probably a much slower path). */ if (oa->relaxed_timeout && !ob->relaxed_timeout) return 0; /* ob is better. It's not relaxed. */ if (!oa->relaxed_timeout && ob->relaxed_timeout) return 1; /* oa is better. It's not relaxed. */ switch (purpose) { case CIRCUIT_PURPOSE_C_GENERAL: /* if it's used but less dirty it's best; * else if it's more recently created it's best */ if (b->timestamp_dirty) { if (a->timestamp_dirty && a->timestamp_dirty > b->timestamp_dirty) return 1; } else { if (a->timestamp_dirty || timercmp(&a->timestamp_began, &b->timestamp_began, >)) return 1; if (ob->build_state->is_internal) /* XXX023 what the heck is this internal thing doing here. I * think we can get rid of it. circuit_is_acceptable() already * makes sure that is_internal is exactly what we need it to * be. -RD */ return 1; } break; case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: /* the closer it is to ack_wait the better it is */ if (a->purpose > b->purpose) return 1; break; case CIRCUIT_PURPOSE_C_REND_JOINED: /* the closer it is to rend_joined the better it is */ if (a->purpose > b->purpose) return 1; break; } /* XXXX023 Maybe this check should get a higher priority to avoid * using up circuits too rapidly. */ a_bits = connection_edge_update_circuit_isolation(conn, (origin_circuit_t*)oa, 1); b_bits = connection_edge_update_circuit_isolation(conn, (origin_circuit_t*)ob, 1); /* if x_bits < 0, then we have not used x for anything; better not to dirty * a connection if we can help it. */ if (a_bits < 0) { return 0; } else if (b_bits < 0) { return 1; } a_bits &= ~ oa->isolation_flags_mixed; a_bits &= ~ ob->isolation_flags_mixed; if (n_bits_set_u8(a_bits) < n_bits_set_u8(b_bits)) { /* The fewer new restrictions we need to make on a circuit for stream * isolation, the better. */ return 1; } return 0; } /** Find the best circ that conn can use, preferably one which is * dirty. Circ must not be too old. * * Conn must be defined. * * If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN. * * circ_purpose specifies what sort of circuit we must have. * It can be C_GENERAL, C_INTRODUCE_ACK_WAIT, or C_REND_JOINED. * * If it's REND_JOINED and must_be_open==0, then return the closest * rendezvous-purposed circuit that you can find. * * If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the * closest introduce-purposed circuit that you can find. */ static origin_circuit_t * circuit_get_best(const entry_connection_t *conn, int must_be_open, uint8_t purpose, int need_uptime, int need_internal) { circuit_t *circ; origin_circuit_t *best=NULL; struct timeval now; int intro_going_on_but_too_old = 0; tor_assert(conn); tor_assert(purpose == CIRCUIT_PURPOSE_C_GENERAL || purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT || purpose == CIRCUIT_PURPOSE_C_REND_JOINED); tor_gettimeofday(&now); for (circ=global_circuitlist;circ;circ = circ->next) { origin_circuit_t *origin_circ; if (!CIRCUIT_IS_ORIGIN(circ)) continue; origin_circ = TO_ORIGIN_CIRCUIT(circ); /* Log an info message if we're going to launch a new intro circ in * parallel */ if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT && !must_be_open && origin_circ->hs_circ_has_timed_out) { intro_going_on_but_too_old = 1; continue; } if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose, need_uptime,need_internal,now.tv_sec)) continue; /* now this is an acceptable circ to hand back. but that doesn't * mean it's the *best* circ to hand back. try to decide. */ if (!best || circuit_is_better(origin_circ,best,conn)) best = origin_circ; } if (!best && intro_going_on_but_too_old) log_info(LD_REND|LD_CIRC, "There is an intro circuit being created " "right now, but it has already taken quite a while. Starting " "one in parallel."); return best; } /** Return the number of not-yet-open general-purpose origin circuits. */ static int count_pending_general_client_circuits(void) { const circuit_t *circ; int count = 0; for (circ = global_circuitlist; circ; circ = circ->next) { if (circ->marked_for_close || circ->state == CIRCUIT_STATE_OPEN || circ->purpose != CIRCUIT_PURPOSE_C_GENERAL || !CIRCUIT_IS_ORIGIN(circ)) continue; ++count; } return count; } #if 0 /** Check whether, according to the policies in options, the * circuit circ makes sense. */ /* XXXX currently only checks Exclude{Exit}Nodes; it should check more. * Also, it doesn't have the right definition of an exit circuit. Also, * it's never called. */ int circuit_conforms_to_options(const origin_circuit_t *circ, const or_options_t *options) { const crypt_path_t *cpath, *cpath_next = NULL; /* first check if it includes any excluded nodes */ for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) { cpath_next = cpath->next; if (routerset_contains_extendinfo(options->ExcludeNodes, cpath->extend_info)) return 0; } /* then consider the final hop */ if (routerset_contains_extendinfo(options->ExcludeExitNodes, circ->cpath->prev->extend_info)) return 0; return 1; } #endif /** Close all circuits that start at us, aren't open, and were born * at least CircuitBuildTimeout seconds ago. */ void circuit_expire_building(void) { circuit_t *victim, *next_circ = global_circuitlist; /* circ_times.timeout_ms and circ_times.close_ms are from * circuit_build_times_get_initial_timeout() if we haven't computed * custom timeouts yet */ struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff, close_cutoff, extremely_old_cutoff, hs_extremely_old_cutoff, cannibalized_cutoff, c_intro_cutoff, s_intro_cutoff, stream_cutoff; const or_options_t *options = get_options(); struct timeval now; cpath_build_state_t *build_state; int any_opened_circs = 0; tor_gettimeofday(&now); /* Check to see if we have any opened circuits. If we don't, * we want to be more lenient with timeouts, in case the * user has relocated and/or changed network connections. * See bug #3443. */ while (next_circ) { if (!CIRCUIT_IS_ORIGIN(next_circ) || /* didn't originate here */ next_circ->marked_for_close) { /* don't mess with marked circs */ next_circ = next_circ->next; continue; } if (TO_ORIGIN_CIRCUIT(next_circ)->has_opened && next_circ->state == CIRCUIT_STATE_OPEN && TO_ORIGIN_CIRCUIT(next_circ)->build_state && TO_ORIGIN_CIRCUIT(next_circ)->build_state->desired_path_len == DEFAULT_ROUTE_LEN) { any_opened_circs = 1; break; } next_circ = next_circ->next; } next_circ = global_circuitlist; #define SET_CUTOFF(target, msec) do { \ long ms = tor_lround(msec); \ struct timeval diff; \ diff.tv_sec = ms / 1000; \ diff.tv_usec = (int)((ms % 1000) * 1000); \ timersub(&now, &diff, &target); \ } while (0) /** * Because circuit build timeout is calculated only based on 3 hop * general purpose circuit construction, we need to scale the timeout * to make it properly apply to longer circuits, and circuits of * certain usage types. The following diagram illustrates how we * derive the scaling below. In short, we calculate the number * of times our telescoping-based circuit construction causes cells * to traverse each link for the circuit purpose types in question, * and then assume each link is equivalent. * * OP --a--> A --b--> B --c--> C * OP --a--> A --b--> B --c--> C --d--> D * * Let h = a = b = c = d * * Three hops (general_cutoff) * RTTs = 3a + 2b + c * RTTs = 6h * Cannibalized: * RTTs = a+b+c+d * RTTs = 4h * Four hops: * RTTs = 4a + 3b + 2c + d * RTTs = 10h * Client INTRODUCE1+ACK: // XXX: correct? * RTTs = 5a + 4b + 3c + 2d * RTTs = 14h * Server intro: * RTTs = 4a + 3b + 2c * RTTs = 9h */ SET_CUTOFF(general_cutoff, circ_times.timeout_ms); SET_CUTOFF(begindir_cutoff, circ_times.timeout_ms); /* > 3hop circs seem to have a 1.0 second delay on their cannibalized * 4th hop. */ SET_CUTOFF(fourhop_cutoff, circ_times.timeout_ms * (10/6.0) + 1000); /* CIRCUIT_PURPOSE_C_ESTABLISH_REND behaves more like a RELAY cell. * Use the stream cutoff (more or less). */ SET_CUTOFF(stream_cutoff, MAX(options->CircuitStreamTimeout,15)*1000 + 1000); /* Be lenient with cannibalized circs. They already survived the official * CBT, and they're usually not performance-critical. */ SET_CUTOFF(cannibalized_cutoff, MAX(circ_times.close_ms*(4/6.0), options->CircuitStreamTimeout * 1000) + 1000); /* Intro circs have an extra round trip (and are also 4 hops long) */ SET_CUTOFF(c_intro_cutoff, circ_times.timeout_ms * (14/6.0) + 1000); /* Server intro circs have an extra round trip */ SET_CUTOFF(s_intro_cutoff, circ_times.timeout_ms * (9/6.0) + 1000); SET_CUTOFF(close_cutoff, circ_times.close_ms); SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000); SET_CUTOFF(hs_extremely_old_cutoff, MAX(circ_times.close_ms*2 + 1000, options->SocksTimeout * 1000)); while (next_circ) { struct timeval cutoff; victim = next_circ; next_circ = next_circ->next; if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */ victim->marked_for_close) /* don't mess with marked circs */ continue; /* If we haven't yet started the first hop, it means we don't have * any orconns available, and thus have not started counting time yet * for this circuit. See circuit_deliver_create_cell() and uses of * timestamp_began. * * Continue to wait in this case. The ORConn should timeout * independently and kill us then. */ if (TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_CLOSED) { continue; } build_state = TO_ORIGIN_CIRCUIT(victim)->build_state; if (build_state && build_state->onehop_tunnel) cutoff = begindir_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) cutoff = close_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING || victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) cutoff = c_intro_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) cutoff = s_intro_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND) cutoff = stream_cutoff; else if (victim->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) cutoff = close_cutoff; else if (TO_ORIGIN_CIRCUIT(victim)->has_opened && victim->state != CIRCUIT_STATE_OPEN) cutoff = cannibalized_cutoff; else if (build_state && build_state->desired_path_len >= 4) cutoff = fourhop_cutoff; else cutoff = general_cutoff; if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) cutoff = hs_extremely_old_cutoff; if (timercmp(&victim->timestamp_began, &cutoff, >)) continue; /* it's still young, leave it alone */ /* We need to double-check the opened state here because * we don't want to consider opened 1-hop dircon circuits for * deciding when to relax the timeout, but we *do* want to relax * those circuits too if nothing else is opened *and* they still * aren't either. */ if (!any_opened_circs && victim->state != CIRCUIT_STATE_OPEN) { /* It's still young enough that we wouldn't close it, right? */ if (timercmp(&victim->timestamp_began, &close_cutoff, >)) { if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) { int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_OPEN; log_info(LD_CIRC, "No circuits are opened. Relaxing timeout for circuit %d " "(a %s %d-hop circuit in state %s with channel state %s). " "%d guards are live.", TO_ORIGIN_CIRCUIT(victim)->global_identifier, circuit_purpose_to_string(victim->purpose), TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len, circuit_state_to_string(victim->state), channel_state_to_string(victim->n_chan->state), num_live_entry_guards(0)); /* We count the timeout here for CBT, because technically this * was a timeout, and the timeout value needs to reset if we * see enough of them. Note this means we also need to avoid * double-counting below, too. */ circuit_build_times_count_timeout(&circ_times, first_hop_succeeded); TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout = 1; } continue; } else { static ratelim_t relax_timeout_limit = RATELIM_INIT(3600); log_fn_ratelim(&relax_timeout_limit, LOG_NOTICE, LD_CIRC, "No circuits are opened. Relaxed timeout for circuit %d " "(a %s %d-hop circuit in state %s with channel state %s) to " "%ldms. However, it appears the circuit has timed out " "anyway. %d guards are live.", TO_ORIGIN_CIRCUIT(victim)->global_identifier, circuit_purpose_to_string(victim->purpose), TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len, circuit_state_to_string(victim->state), channel_state_to_string(victim->n_chan->state), (long)circ_times.close_ms, num_live_entry_guards(0)); } } #if 0 /* some debug logs, to help track bugs */ if (victim->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && victim->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) { if (!victim->timestamp_dirty) log_fn(LOG_DEBUG,"Considering %sopen purpose %d to %s (circid %d)." "(clean).", victim->state == CIRCUIT_STATE_OPEN ? "" : "non", victim->purpose, victim->build_state->chosen_exit_name, victim->n_circ_id); else log_fn(LOG_DEBUG,"Considering %sopen purpose %d to %s (circid %d). " "%d secs since dirty.", victim->state == CIRCUIT_STATE_OPEN ? "" : "non", victim->purpose, victim->build_state->chosen_exit_name, victim->n_circ_id, (int)(now - victim->timestamp_dirty)); } #endif /* if circ is !open, or if it's open but purpose is a non-finished * intro or rend, then mark it for close */ if (victim->state == CIRCUIT_STATE_OPEN) { switch (victim->purpose) { default: /* most open circuits can be left alone. */ continue; /* yes, continue inside a switch refers to the nearest * enclosing loop. C is smart. */ case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: break; /* too old, need to die */ case CIRCUIT_PURPOSE_C_REND_READY: /* it's a rend_ready circ -- has it already picked a query? */ /* c_rend_ready circs measure age since timestamp_dirty, * because that's set when they switch purposes */ if (TO_ORIGIN_CIRCUIT(victim)->rend_data || victim->timestamp_dirty > cutoff.tv_sec) continue; break; case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: /* Open path bias testing circuits are given a long * time to complete the test, but not forever */ TO_ORIGIN_CIRCUIT(victim)->path_state = PATH_STATE_USE_FAILED; break; case CIRCUIT_PURPOSE_C_INTRODUCING: /* We keep old introducing circuits around for * a while in parallel, and they can end up "opened". * We decide below if we're going to mark them timed * out and eventually close them. */ break; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: /* rend and intro circs become dirty each time they * make an introduction attempt. so timestamp_dirty * will reflect the time since the last attempt. */ if (victim->timestamp_dirty > cutoff.tv_sec) continue; break; } } else { /* circuit not open, consider recording failure as timeout */ int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath && TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_OPEN; if (TO_ORIGIN_CIRCUIT(victim)->p_streams != NULL) { log_warn(LD_BUG, "Circuit %d (purpose %d, %s) has timed out, " "yet has attached streams!", TO_ORIGIN_CIRCUIT(victim)->global_identifier, victim->purpose, circuit_purpose_to_string(victim->purpose)); tor_fragile_assert(); continue; } if (circuit_timeout_want_to_count_circ(TO_ORIGIN_CIRCUIT(victim)) && circuit_build_times_enough_to_compute(&circ_times)) { /* Circuits are allowed to last longer for measurement. * Switch their purpose and wait. */ if (victim->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { control_event_circuit_status(TO_ORIGIN_CIRCUIT(victim), CIRC_EVENT_FAILED, END_CIRC_REASON_TIMEOUT); circuit_change_purpose(victim, CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT); /* Record this failure to check for too many timeouts * in a row. This function does not record a time value yet * (we do that later); it only counts the fact that we did * have a timeout. We also want to avoid double-counting * already "relaxed" circuits, which are counted above. */ if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) { circuit_build_times_count_timeout(&circ_times, first_hop_succeeded); } continue; } /* * If the circuit build time is much greater than we would have cut * it off at, we probably had a suspend event along this codepath, * and we should discard the value. */ if (timercmp(&victim->timestamp_began, &extremely_old_cutoff, <)) { log_notice(LD_CIRC, "Extremely large value for circuit build timeout: %lds. " "Assuming clock jump. Purpose %d (%s)", (long)(now.tv_sec - victim->timestamp_began.tv_sec), victim->purpose, circuit_purpose_to_string(victim->purpose)); } else if (circuit_build_times_count_close(&circ_times, first_hop_succeeded, victim->timestamp_created.tv_sec)) { circuit_build_times_set_timeout(&circ_times); } } } /* If this is a hidden service client circuit which is far enough * along in connecting to its destination, and we haven't already * flagged it as 'timed out', and the user has not told us to * close such circs immediately on timeout, flag it as 'timed out' * so we'll launch another intro or rend circ, but don't mark it * for close yet. * * (Circs flagged as 'timed out' are given a much longer timeout * period above, so we won't close them in the next call to * circuit_expire_building.) */ if (!(options->CloseHSClientCircuitsImmediatelyOnTimeout) && !(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) { switch (victim->purpose) { case CIRCUIT_PURPOSE_C_REND_READY: /* We only want to spare a rend circ if it has been specified in * an INTRODUCE1 cell sent to a hidden service. A circ's * pending_final_cpath field is non-NULL iff it is a rend circ * and we have tried to send an INTRODUCE1 cell specifying it. * Thus, if the pending_final_cpath field *is* NULL, then we * want to not spare it. */ if (TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath == NULL) break; /* fallthrough! */ case CIRCUIT_PURPOSE_C_INTRODUCING: /* connection_ap_handshake_attach_circuit() will relaunch for us */ case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: /* If we have reached this line, we want to spare the circ for now. */ log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) " "as timed-out HS circ", (unsigned)victim->n_circ_id, victim->state, circuit_state_to_string(victim->state), victim->purpose); TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; continue; default: break; } } /* If this is a service-side rendezvous circuit which is far * enough along in connecting to its destination, consider sparing * it. */ if (!(options->CloseHSServiceRendCircuitsImmediatelyOnTimeout) && !(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) && victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) " "as timed-out HS circ; relaunching rendezvous attempt.", (unsigned)victim->n_circ_id, victim->state, circuit_state_to_string(victim->state), victim->purpose); TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; rend_service_relaunch_rendezvous(TO_ORIGIN_CIRCUIT(victim)); continue; } if (victim->n_chan) log_info(LD_CIRC, "Abandoning circ %u %s:%d (state %d,%d:%s, purpose %d, " "len %d)", TO_ORIGIN_CIRCUIT(victim)->global_identifier, channel_get_canonical_remote_descr(victim->n_chan), (unsigned)victim->n_circ_id, TO_ORIGIN_CIRCUIT(victim)->has_opened, victim->state, circuit_state_to_string(victim->state), victim->purpose, TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len); else log_info(LD_CIRC, "Abandoning circ %u %d (state %d,%d:%s, purpose %d, len %d)", TO_ORIGIN_CIRCUIT(victim)->global_identifier, (unsigned)victim->n_circ_id, TO_ORIGIN_CIRCUIT(victim)->has_opened, victim->state, circuit_state_to_string(victim->state), victim->purpose, TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len); circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim)); if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) circuit_mark_for_close(victim, END_CIRC_REASON_MEASUREMENT_EXPIRED); else circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT); pathbias_count_timeout(TO_ORIGIN_CIRCUIT(victim)); } } /** Remove any elements in needed_ports that are handled by an * open or in-progress circuit. */ void circuit_remove_handled_ports(smartlist_t *needed_ports) { int i; uint16_t *port; for (i = 0; i < smartlist_len(needed_ports); ++i) { port = smartlist_get(needed_ports, i); tor_assert(*port); if (circuit_stream_is_being_handled(NULL, *port, MIN_CIRCUITS_HANDLING_STREAM)) { // log_debug(LD_CIRC,"Port %d is already being handled; removing.", port); smartlist_del(needed_ports, i--); tor_free(port); } else { log_debug(LD_CIRC,"Port %d is not handled.", *port); } } } /** Return 1 if at least min general-purpose non-internal circuits * will have an acceptable exit node for exit stream conn if it * is defined, else for "*:port". * Else return 0. */ int circuit_stream_is_being_handled(entry_connection_t *conn, uint16_t port, int min) { circuit_t *circ; const node_t *exitnode; int num=0; time_t now = time(NULL); int need_uptime = smartlist_contains_int_as_string( get_options()->LongLivedPorts, conn ? conn->socks_request->port : port); for (circ=global_circuitlist;circ;circ = circ->next) { if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && (!circ->timestamp_dirty || circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) { origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); cpath_build_state_t *build_state = origin_circ->build_state; if (build_state->is_internal || build_state->onehop_tunnel) continue; if (origin_circ->unusable_for_new_conns) continue; exitnode = build_state_get_exit_node(build_state); if (exitnode && (!need_uptime || build_state->need_uptime)) { int ok; if (conn) { ok = connection_ap_can_use_exit(conn, exitnode); } else { addr_policy_result_t r; r = compare_tor_addr_to_node_policy(NULL, port, exitnode); ok = r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED; } if (ok) { if (++num >= min) return 1; } } } } return 0; } /** Don't keep more than this many unused open circuits around. */ #define MAX_UNUSED_OPEN_CIRCUITS 14 /** Figure out how many circuits we have open that are clean. Make * sure it's enough for all the upcoming behaviors we predict we'll have. * But put an upper bound on the total number of circuits. */ static void circuit_predict_and_launch_new(void) { circuit_t *circ; int num=0, num_internal=0, num_uptime_internal=0; int hidserv_needs_uptime=0, hidserv_needs_capacity=1; int port_needs_uptime=0, port_needs_capacity=1; time_t now = time(NULL); int flags = 0; /* First, count how many of each type of circuit we have already. */ for (circ=global_circuitlist;circ;circ = circ->next) { cpath_build_state_t *build_state; origin_circuit_t *origin_circ; if (!CIRCUIT_IS_ORIGIN(circ)) continue; if (circ->marked_for_close) continue; /* don't mess with marked circs */ if (circ->timestamp_dirty) continue; /* only count clean circs */ if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL) continue; /* only pay attention to general-purpose circs */ origin_circ = TO_ORIGIN_CIRCUIT(circ); if (origin_circ->unusable_for_new_conns) continue; build_state = origin_circ->build_state; if (build_state->onehop_tunnel) continue; num++; if (build_state->is_internal) num_internal++; if (build_state->need_uptime && build_state->is_internal) num_uptime_internal++; } /* If that's enough, then stop now. */ if (num >= MAX_UNUSED_OPEN_CIRCUITS) return; /* we already have many, making more probably will hurt */ /* Second, see if we need any more exit circuits. */ /* check if we know of a port that's been requested recently * and no circuit is currently available that can handle it. */ if (!circuit_all_predicted_ports_handled(now, &port_needs_uptime, &port_needs_capacity)) { if (port_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; if (port_needs_capacity) flags |= CIRCLAUNCH_NEED_CAPACITY; log_info(LD_CIRC, "Have %d clean circs (%d internal), need another exit circ.", num, num_internal); circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); return; } /* Third, see if we need any more hidden service (server) circuits. */ if (num_rend_services() && num_uptime_internal < 3) { flags = (CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL); log_info(LD_CIRC, "Have %d clean circs (%d internal), need another internal " "circ for my hidden service.", num, num_internal); circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); return; } /* Fourth, see if we need any more hidden service (client) circuits. */ if (rep_hist_get_predicted_internal(now, &hidserv_needs_uptime, &hidserv_needs_capacity) && ((num_uptime_internal<2 && hidserv_needs_uptime) || num_internal<2)) { if (hidserv_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; if (hidserv_needs_capacity) flags |= CIRCLAUNCH_NEED_CAPACITY; flags |= CIRCLAUNCH_IS_INTERNAL; log_info(LD_CIRC, "Have %d clean circs (%d uptime-internal, %d internal), need" " another hidden service circ.", num, num_uptime_internal, num_internal); circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); return; } /* Finally, check to see if we still need more circuits to learn * a good build timeout. But if we're close to our max number we * want, don't do another -- we want to leave a few slots open so * we can still build circuits preemptively as needed. */ if (num < MAX_UNUSED_OPEN_CIRCUITS-2 && ! circuit_build_times_disabled() && circuit_build_times_needs_circuits_now(&circ_times)) { flags = CIRCLAUNCH_NEED_CAPACITY; log_info(LD_CIRC, "Have %d clean circs need another buildtime test circ.", num); circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); return; } } /** Build a new test circuit every 5 minutes */ #define TESTING_CIRCUIT_INTERVAL 300 /** This function is called once a second, if router_have_min_dir_info() is * true. Its job is to make sure all services we offer have enough circuits * available. Some services just want enough circuits for current tasks, * whereas others want a minimum set of idle circuits hanging around. */ void circuit_build_needed_circs(time_t now) { static time_t time_to_new_circuit = 0; const or_options_t *options = get_options(); /* launch a new circ for any pending streams that need one */ connection_ap_attach_pending(); /* make sure any hidden services have enough intro points */ rend_services_introduce(); if (time_to_new_circuit < now) { circuit_reset_failure_count(1); time_to_new_circuit = now + options->NewCircuitPeriod; if (proxy_mode(get_options())) addressmap_clean(now); circuit_expire_old_circuits_clientside(); #if 0 /* disable for now, until predict-and-launch-new can cull leftovers */ circ = circuit_get_youngest_clean_open(CIRCUIT_PURPOSE_C_GENERAL); if (get_options()->RunTesting && circ && circ->timestamp_began.tv_sec + TESTING_CIRCUIT_INTERVAL < now) { log_fn(LOG_INFO,"Creating a new testing circuit."); circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, 0); } #endif } if (!options->DisablePredictedCircuits) circuit_predict_and_launch_new(); } /** If the stream conn is a member of any of the linked * lists of circ, then remove it from the list. */ void circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) { edge_connection_t *prevconn; tor_assert(circ); tor_assert(conn); if (conn->base_.type == CONN_TYPE_AP) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); entry_conn->may_use_optimistic_data = 0; } conn->cpath_layer = NULL; /* don't keep a stale pointer */ conn->on_circuit = NULL; if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); if (conn == origin_circ->p_streams) { origin_circ->p_streams = conn->next_stream; return; } for (prevconn = origin_circ->p_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ; if (prevconn && prevconn->next_stream) { prevconn->next_stream = conn->next_stream; return; } } else { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); if (conn == or_circ->n_streams) { or_circ->n_streams = conn->next_stream; return; } if (conn == or_circ->resolving_streams) { or_circ->resolving_streams = conn->next_stream; return; } for (prevconn = or_circ->n_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ; if (prevconn && prevconn->next_stream) { prevconn->next_stream = conn->next_stream; return; } for (prevconn = or_circ->resolving_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ; if (prevconn && prevconn->next_stream) { prevconn->next_stream = conn->next_stream; return; } } log_warn(LD_BUG,"Edge connection not in circuit's list."); /* Don't give an error here; it's harmless. */ tor_fragile_assert(); } /** If we haven't yet decided on a good timeout value for circuit * building, we close idles circuits aggressively so we can get more * data points. */ #define IDLE_TIMEOUT_WHILE_LEARNING (10*60) /** Find each circuit that has been unused for too long, or dirty * for too long and has no streams on it: mark it for close. */ static void circuit_expire_old_circuits_clientside(void) { circuit_t *circ; struct timeval cutoff, now; tor_gettimeofday(&now); cutoff = now; if (! circuit_build_times_disabled() && circuit_build_times_needs_circuits(&circ_times)) { /* Circuits should be shorter lived if we need more of them * for learning a good build timeout */ cutoff.tv_sec -= IDLE_TIMEOUT_WHILE_LEARNING; } else { cutoff.tv_sec -= get_options()->CircuitIdleTimeout; } for (circ = global_circuitlist; circ; circ = circ->next) { if (circ->marked_for_close || !CIRCUIT_IS_ORIGIN(circ)) continue; /* If the circuit has been dirty for too long, and there are no streams * on it, mark it for close. */ if (circ->timestamp_dirty && circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now.tv_sec && !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) { log_debug(LD_CIRC, "Closing n_circ_id %u (dirty %ld sec ago, " "purpose %d)", (unsigned)circ->n_circ_id, (long)(now.tv_sec - circ->timestamp_dirty), circ->purpose); /* Don't do this magic for testing circuits. Their death is governed * by circuit_expire_building */ if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) { if (timercmp(&circ->timestamp_began, &cutoff, <)) { if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL || circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT || circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || circ->purpose == CIRCUIT_PURPOSE_TESTING || (circ->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && circ->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) || circ->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { log_debug(LD_CIRC, "Closing circuit that has been unused for %ld msec.", tv_mdiff(&circ->timestamp_began, &now)); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) { /* Server-side rend joined circuits can end up really old, because * they are reused by clients for longer than normal. The client * controls their lifespan. (They never become dirty, because * connection_exit_begin_conn() never marks anything as dirty.) * Similarly, server-side intro circuits last a long time. */ if (circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED && circ->purpose != CIRCUIT_PURPOSE_S_INTRO) { log_notice(LD_CIRC, "Ancient non-dirty circuit %d is still around after " "%ld milliseconds. Purpose: %d (%s)", TO_ORIGIN_CIRCUIT(circ)->global_identifier, tv_mdiff(&circ->timestamp_began, &now), circ->purpose, circuit_purpose_to_string(circ->purpose)); TO_ORIGIN_CIRCUIT(circ)->is_ancient = 1; } } } } } } /** How long do we wait before killing circuits with the properties * described below? * * Probably we could choose a number here as low as 5 to 10 seconds, * since these circs are used for begindir, and a) generally you either * ask another begindir question right after or you don't for a long time, * b) clients at least through 0.2.1.x choose from the whole set of * directory mirrors at each choice, and c) re-establishing a one-hop * circuit via create-fast is a light operation assuming the TLS conn is * still there. * * I expect "b" to go away one day when we move to using directory * guards, but I think "a" and "c" are good enough reasons that a low * number is safe even then. */ #define IDLE_ONE_HOP_CIRC_TIMEOUT 60 /** Find each non-origin circuit that has been unused for too long, * has no streams on it, used a create_fast, and ends here: mark it * for close. */ void circuit_expire_old_circuits_serverside(time_t now) { circuit_t *circ; or_circuit_t *or_circ; time_t cutoff = now - IDLE_ONE_HOP_CIRC_TIMEOUT; for (circ = global_circuitlist; circ; circ = circ->next) { if (circ->marked_for_close || CIRCUIT_IS_ORIGIN(circ)) continue; or_circ = TO_OR_CIRCUIT(circ); /* If the circuit has been idle for too long, and there are no streams * on it, and it ends here, and it used a create_fast, mark it for close. */ if (or_circ->is_first_hop && !circ->n_chan && !or_circ->n_streams && !or_circ->resolving_streams && or_circ->p_chan && channel_when_last_xmit(or_circ->p_chan) <= cutoff) { log_info(LD_CIRC, "Closing circ_id %u (empty %d secs ago)", (unsigned)or_circ->p_circ_id, (int)(now - channel_when_last_xmit(or_circ->p_chan))); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } } } /** Number of testing circuits we want open before testing our bandwidth. */ #define NUM_PARALLEL_TESTING_CIRCS 4 /** True iff we've ever had enough testing circuits open to test our * bandwidth. */ static int have_performed_bandwidth_test = 0; /** Reset have_performed_bandwidth_test, so we'll start building * testing circuits again so we can exercise our bandwidth. */ void reset_bandwidth_test(void) { have_performed_bandwidth_test = 0; } /** Return 1 if we've already exercised our bandwidth, or if we * have fewer than NUM_PARALLEL_TESTING_CIRCS testing circuits * established or on the way. Else return 0. */ int circuit_enough_testing_circs(void) { circuit_t *circ; int num = 0; if (have_performed_bandwidth_test) return 1; for (circ = global_circuitlist; circ; circ = circ->next) { if (!circ->marked_for_close && CIRCUIT_IS_ORIGIN(circ) && circ->purpose == CIRCUIT_PURPOSE_TESTING && circ->state == CIRCUIT_STATE_OPEN) num++; } return num >= NUM_PARALLEL_TESTING_CIRCS; } /** A testing circuit has completed. Take whatever stats we want. * Noticing reachability is taken care of in onionskin_answer(), * so there's no need to record anything here. But if we still want * to do the bandwidth test, and we now have enough testing circuits * open, do it. */ static void circuit_testing_opened(origin_circuit_t *circ) { if (have_performed_bandwidth_test || !check_whether_orport_reachable()) { /* either we've already done everything we want with testing circuits, * or this testing circuit became open due to a fluke, e.g. we picked * a last hop where we already had the connection open due to an * outgoing local circuit. */ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); } else if (circuit_enough_testing_circs()) { router_perform_bandwidth_test(NUM_PARALLEL_TESTING_CIRCS, time(NULL)); have_performed_bandwidth_test = 1; } else consider_testing_reachability(1, 0); } /** A testing circuit has failed to build. Take whatever stats we want. */ static void circuit_testing_failed(origin_circuit_t *circ, int at_last_hop) { if (server_mode(get_options()) && check_whether_orport_reachable()) return; log_info(LD_GENERAL, "Our testing circuit (to see if your ORPort is reachable) " "has failed. I'll try again later."); /* These aren't used yet. */ (void)circ; (void)at_last_hop; } /** The circuit circ has just become open. Take the next * step: for rendezvous circuits, we pass circ to the appropriate * function in rendclient or rendservice. For general circuits, we * call connection_ap_attach_pending, which looks for pending streams * that could use circ. */ void circuit_has_opened(origin_circuit_t *circ) { control_event_circuit_status(circ, CIRC_EVENT_BUILT, 0); /* Remember that this circuit has finished building. Now if we start * it building again later (e.g. by extending it), we will know not * to consider its build time. */ circ->has_opened = 1; switch (TO_CIRCUIT(circ)->purpose) { case CIRCUIT_PURPOSE_C_ESTABLISH_REND: rend_client_rendcirc_has_opened(circ); /* Start building an intro circ if we don't have one yet. */ connection_ap_attach_pending(); /* This isn't a call to circuit_try_attaching_streams because a * circuit in _C_ESTABLISH_REND state isn't connected to its * hidden service yet, thus we can't attach streams to it yet, * thus circuit_try_attaching_streams would always clear the * circuit's isolation state. circuit_try_attaching_streams is * called later, when the rend circ enters _C_REND_JOINED * state. */ break; case CIRCUIT_PURPOSE_C_INTRODUCING: rend_client_introcirc_has_opened(circ); break; case CIRCUIT_PURPOSE_C_GENERAL: /* Tell any AP connections that have been waiting for a new * circuit that one is ready. */ circuit_try_attaching_streams(circ); break; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: /* at Bob, waiting for introductions */ rend_service_intro_has_opened(circ); break; case CIRCUIT_PURPOSE_S_CONNECT_REND: /* at Bob, connecting to rend point */ rend_service_rendezvous_has_opened(circ); break; case CIRCUIT_PURPOSE_TESTING: circuit_testing_opened(circ); break; /* default: * This won't happen in normal operation, but might happen if the * controller did it. Just let it slide. */ } } /** If the stream-isolation state of circ can be cleared, clear * it. Return non-zero iff circ's isolation state was cleared. */ static int circuit_try_clearing_isolation_state(origin_circuit_t *circ) { if (/* The circuit may have become non-open if it was cannibalized.*/ circ->base_.state == CIRCUIT_STATE_OPEN && /* If !isolation_values_set, there is nothing to clear. */ circ->isolation_values_set && /* It's not legal to clear a circuit's isolation info if it's ever had * streams attached */ !circ->isolation_any_streams_attached) { /* If we have any isolation information set on this circuit, and * we didn't manage to attach any streams to it, then we can * and should clear it and try again. */ circuit_clear_isolation(circ); return 1; } else { return 0; } } /** Called when a circuit becomes ready for streams to be attached to * it. */ void circuit_try_attaching_streams(origin_circuit_t *circ) { /* Attach streams to this circuit if we can. */ connection_ap_attach_pending(); /* The call to circuit_try_clearing_isolation_state here will do * nothing and return 0 if we didn't attach any streams to circ * above. */ if (circuit_try_clearing_isolation_state(circ)) { /* Maybe *now* we can attach some streams to this circuit. */ connection_ap_attach_pending(); } } /** Called whenever a circuit could not be successfully built. */ void circuit_build_failed(origin_circuit_t *circ) { channel_t *n_chan = NULL; /* we should examine circ and see if it failed because of * the last hop or an earlier hop. then use this info below. */ int failed_at_last_hop = 0; /* If the last hop isn't open, and the second-to-last is, we failed * at the last hop. */ if (circ->cpath && circ->cpath->prev->state != CPATH_STATE_OPEN && circ->cpath->prev->prev->state == CPATH_STATE_OPEN) { failed_at_last_hop = 1; } if (circ->cpath && circ->cpath->state != CPATH_STATE_OPEN) { /* We failed at the first hop. If there's an OR connection * to blame, blame it. Also, avoid this relay for a while, and * fail any one-hop directory fetches destined for it. */ const char *n_chan_id = circ->cpath->extend_info->identity_digest; int already_marked = 0; if (circ->base_.n_chan) { n_chan = circ->base_.n_chan; if (n_chan->is_bad_for_new_circs) { /* We only want to blame this router when a fresh healthy * connection fails. So don't mark this router as newly failed, * since maybe this was just an old circuit attempt that's * finally timing out now. Also, there's no need to blow away * circuits/streams/etc, since the failure of an unhealthy conn * doesn't tell us much about whether a healthy conn would * succeed. */ already_marked = 1; } log_info(LD_OR, "Our circuit failed to get a response from the first hop " "(%s). I'm going to try to rotate to a better connection.", channel_get_canonical_remote_descr(n_chan)); n_chan->is_bad_for_new_circs = 1; } else { log_info(LD_OR, "Our circuit died before the first hop with no connection"); } if (n_chan_id && !already_marked) { entry_guard_register_connect_status(n_chan_id, 0, 1, time(NULL)); /* if there are any one-hop streams waiting on this circuit, fail * them now so they can retry elsewhere. */ connection_ap_fail_onehop(n_chan_id, circ->build_state); } } switch (circ->base_.purpose) { case CIRCUIT_PURPOSE_C_GENERAL: /* If we never built the circuit, note it as a failure. */ circuit_increment_failure_count(); if (failed_at_last_hop) { /* Make sure any streams that demand our last hop as their exit * know that it's unlikely to happen. */ circuit_discard_optional_exit_enclaves(circ->cpath->prev->extend_info); } break; case CIRCUIT_PURPOSE_TESTING: circuit_testing_failed(circ, failed_at_last_hop); break; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: /* at Bob, waiting for introductions */ if (circ->base_.state != CIRCUIT_STATE_OPEN) { circuit_increment_failure_count(); } /* no need to care here, because bob will rebuild intro * points periodically. */ break; case CIRCUIT_PURPOSE_C_INTRODUCING: /* at Alice, connecting to intro point */ /* Don't increment failure count, since Bob may have picked * the introduction point maliciously */ /* Alice will pick a new intro point when this one dies, if * the stream in question still cares. No need to act here. */ break; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: /* at Alice, waiting for Bob */ circuit_increment_failure_count(); /* Alice will pick a new rend point when this one dies, if * the stream in question still cares. No need to act here. */ break; case CIRCUIT_PURPOSE_S_CONNECT_REND: /* at Bob, connecting to rend point */ /* Don't increment failure count, since Alice may have picked * the rendezvous point maliciously */ log_info(LD_REND, "Couldn't connect to Alice's chosen rend point %s " "(%s hop failed).", escaped(build_state_get_exit_nickname(circ->build_state)), failed_at_last_hop?"last":"non-last"); rend_service_relaunch_rendezvous(circ); break; /* default: * This won't happen in normal operation, but might happen if the * controller did it. Just let it slide. */ } } /** Number of consecutive failures so far; should only be touched by * circuit_launch_new and circuit_*_failure_count. */ static int n_circuit_failures = 0; /** Before the last time we called circuit_reset_failure_count(), were * there a lot of failures? */ static int did_circs_fail_last_period = 0; /** Don't retry launching a new circuit if we try this many times with no * success. */ #define MAX_CIRCUIT_FAILURES 5 /** Launch a new circuit; see circuit_launch_by_extend_info() for * details on arguments. */ origin_circuit_t * circuit_launch(uint8_t purpose, int flags) { return circuit_launch_by_extend_info(purpose, NULL, flags); } /** Launch a new circuit with purpose purpose and exit node * extend_info (or NULL to select a random exit node). If flags * contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If * CIRCLAUNCH_NEED_CAPACITY is set, choose among routers with high bandwidth. * If CIRCLAUNCH_IS_INTERNAL is true, the last hop need not be an exit node. * If CIRCLAUNCH_ONEHOP_TUNNEL is set, the circuit will have only one hop. * Return the newly allocated circuit on success, or NULL on failure. */ origin_circuit_t * circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info, int flags) { origin_circuit_t *circ; int onehop_tunnel = (flags & CIRCLAUNCH_ONEHOP_TUNNEL) != 0; if (!onehop_tunnel && !router_have_minimum_dir_info()) { log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling " "circuit launch."); return NULL; } if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) && purpose != CIRCUIT_PURPOSE_TESTING && !onehop_tunnel) { /* see if there are appropriate circs available to cannibalize. */ /* XXX if we're planning to add a hop, perhaps we want to look for * internal circs rather than exit circs? -RD */ circ = circuit_find_to_cannibalize(purpose, extend_info, flags); if (circ) { uint8_t old_purpose = circ->base_.purpose; struct timeval old_timestamp_began; log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d (%s)", build_state_get_exit_nickname(circ->build_state), purpose, circuit_purpose_to_string(purpose)); if ((purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || purpose == CIRCUIT_PURPOSE_C_INTRODUCING) && circ->path_state == PATH_STATE_BUILD_SUCCEEDED) { /* Path bias: Cannibalized rends pre-emptively count as a * successfully built but unused closed circuit. We don't * wait until the extend (or the close) because the rend * point could be malicious. * * Same deal goes for client side introductions. Clients * can be manipulated to connect repeatedly to them * (especially web clients). * * If we decide to probe the initial portion of these circs, * (up to the adversary's final hop), we need to remove this, * or somehow mark the circuit with a special path state. */ /* This must be called before the purpose change */ pathbias_check_close(circ, END_CIRC_REASON_FINISHED); } circuit_change_purpose(TO_CIRCUIT(circ), purpose); /* Reset the start date of this circ, else expire_building * will see it and think it's been trying to build since it * began. * * Technically, the code should reset this when the * create cell is finally sent, but we're close enough * here. */ tor_gettimeofday(&circ->base_.timestamp_began); control_event_circuit_cannibalized(circ, old_purpose, &old_timestamp_began); switch (purpose) { case CIRCUIT_PURPOSE_C_ESTABLISH_REND: case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: /* it's ready right now */ break; case CIRCUIT_PURPOSE_C_INTRODUCING: case CIRCUIT_PURPOSE_S_CONNECT_REND: case CIRCUIT_PURPOSE_C_GENERAL: /* need to add a new hop */ tor_assert(extend_info); if (circuit_extend_to_new_exit(circ, extend_info) < 0) return NULL; break; default: log_warn(LD_BUG, "unexpected purpose %d when cannibalizing a circ.", purpose); tor_fragile_assert(); return NULL; } return circ; } } if (did_circs_fail_last_period && n_circuit_failures > MAX_CIRCUIT_FAILURES) { /* too many failed circs in a row. don't try. */ // log_fn(LOG_INFO,"%d failures so far, not trying.",n_circuit_failures); return NULL; } /* try a circ. if it fails, circuit_mark_for_close will increment * n_circuit_failures */ return circuit_establish_circuit(purpose, extend_info, flags); } /** Record another failure at opening a general circuit. When we have * too many, we'll stop trying for the remainder of this minute. */ static void circuit_increment_failure_count(void) { ++n_circuit_failures; log_debug(LD_CIRC,"n_circuit_failures now %d.",n_circuit_failures); } /** Reset the failure count for opening general circuits. This means * we will try MAX_CIRCUIT_FAILURES times more (if necessary) before * stopping again. */ void circuit_reset_failure_count(int timeout) { if (timeout && n_circuit_failures > MAX_CIRCUIT_FAILURES) did_circs_fail_last_period = 1; else did_circs_fail_last_period = 0; n_circuit_failures = 0; } /** Find an open circ that we're happy to use for conn and return 1. If * there isn't one, and there isn't one on the way, launch one and return * 0. If it will never work, return -1. * * Write the found or in-progress or launched circ into *circp. */ static int circuit_get_open_circ_or_launch(entry_connection_t *conn, uint8_t desired_circuit_purpose, origin_circuit_t **circp) { origin_circuit_t *circ; int check_exit_policy; int need_uptime, need_internal; int want_onehop; const or_options_t *options = get_options(); tor_assert(conn); tor_assert(circp); tor_assert(ENTRY_TO_CONN(conn)->state == AP_CONN_STATE_CIRCUIT_WAIT); check_exit_policy = conn->socks_request->command == SOCKS_COMMAND_CONNECT && !conn->use_begindir && !connection_edge_is_rendezvous_stream(ENTRY_TO_EDGE_CONN(conn)); want_onehop = conn->want_onehop; need_uptime = !conn->want_onehop && !conn->use_begindir && smartlist_contains_int_as_string(options->LongLivedPorts, conn->socks_request->port); if (desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL) need_internal = 1; else if (conn->use_begindir || conn->want_onehop) need_internal = 1; else need_internal = 0; circ = circuit_get_best(conn, 1, desired_circuit_purpose, need_uptime, need_internal); if (circ) { *circp = circ; return 1; /* we're happy */ } if (!want_onehop && !router_have_minimum_dir_info()) { if (!connection_get_by_type(CONN_TYPE_DIR)) { int severity = LOG_NOTICE; /* FFFF if this is a tunneled directory fetch, don't yell * as loudly. the user doesn't even know it's happening. */ if (entry_list_is_constrained(options) && entries_known_but_down(options)) { log_fn(severity, LD_APP|LD_DIR, "Application request when we haven't used client functionality " "lately. Optimistically trying known %s again.", options->UseBridges ? "bridges" : "entrynodes"); entries_retry_all(options); } else if (!options->UseBridges || any_bridge_descriptors_known()) { log_fn(severity, LD_APP|LD_DIR, "Application request when we haven't used client functionality " "lately. Optimistically trying directory fetches again."); routerlist_retry_directory_downloads(time(NULL)); } } /* the stream will be dealt with when router_have_minimum_dir_info becomes * 1, or when all directory attempts fail and directory_all_unreachable() * kills it. */ return 0; } /* Do we need to check exit policy? */ if (check_exit_policy) { if (!conn->chosen_exit_name) { struct in_addr in; tor_addr_t addr, *addrp=NULL; if (tor_inet_aton(conn->socks_request->address, &in)) { tor_addr_from_in(&addr, &in); addrp = &addr; } if (router_exit_policy_all_nodes_reject(addrp, conn->socks_request->port, need_uptime)) { log_notice(LD_APP, "No Tor server allows exit to %s:%d. Rejecting.", safe_str_client(conn->socks_request->address), conn->socks_request->port); return -1; } } else { /* XXXX024 Duplicates checks in connection_ap_handshake_attach_circuit: * refactor into a single function? */ const node_t *node = node_get_by_nickname(conn->chosen_exit_name, 1); int opt = conn->chosen_exit_optional; if (node && !connection_ap_can_use_exit(conn, node)) { log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, "Requested exit point '%s' is excluded or " "would refuse request. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { conn->chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); /* Try again. */ return circuit_get_open_circ_or_launch(conn, desired_circuit_purpose, circp); } return -1; } } } /* is one already on the way? */ circ = circuit_get_best(conn, 0, desired_circuit_purpose, need_uptime, need_internal); if (circ) log_debug(LD_CIRC, "one on the way!"); if (!circ) { extend_info_t *extend_info=NULL; uint8_t new_circ_purpose; const int n_pending = count_pending_general_client_circuits(); if (n_pending >= options->MaxClientCircuitsPending) { static ratelim_t delay_limit = RATELIM_INIT(10*60); char *m; if ((m = rate_limit_log(&delay_limit, approx_time()))) { log_notice(LD_APP, "We'd like to launch a circuit to handle a " "connection, but we already have %d general-purpose client " "circuits pending. Waiting until some finish.%s", n_pending, m); tor_free(m); } return 0; } if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { /* need to pick an intro point */ rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data; tor_assert(rend_data); extend_info = rend_client_get_random_intro(rend_data); if (!extend_info) { log_info(LD_REND, "No intro points for '%s': re-fetching service descriptor.", safe_str_client(rend_data->onion_address)); rend_client_refetch_v2_renddesc(rend_data); ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_RENDDESC_WAIT; return 0; } log_info(LD_REND,"Chose %s as intro point for '%s'.", extend_info_describe(extend_info), safe_str_client(rend_data->onion_address)); } /* If we have specified a particular exit node for our * connection, then be sure to open a circuit to that exit node. */ if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) { if (conn->chosen_exit_name) { const node_t *r; int opt = conn->chosen_exit_optional; r = node_get_by_nickname(conn->chosen_exit_name, 1); if (r && node_has_descriptor(r)) { /* We might want to connect to an IPv6 bridge for loading descriptors so we use the preferred address rather than the primary. */ extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0); } else { log_debug(LD_DIR, "considering %d, %s", want_onehop, conn->chosen_exit_name); if (want_onehop && conn->chosen_exit_name[0] == '$') { /* We're asking for a one-hop circuit to a router that * we don't have a routerinfo about. Make up an extend_info. */ char digest[DIGEST_LEN]; char *hexdigest = conn->chosen_exit_name+1; tor_addr_t addr; if (strlen(hexdigest) < HEX_DIGEST_LEN || base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN)<0) { log_info(LD_DIR, "Broken exit digest on tunnel conn. Closing."); return -1; } if (tor_addr_parse(&addr, conn->socks_request->address) < 0) { log_info(LD_DIR, "Broken address %s on tunnel conn. Closing.", escaped_safe_str_client(conn->socks_request->address)); return -1; } extend_info = extend_info_new(conn->chosen_exit_name+1, digest, NULL, NULL, &addr, conn->socks_request->port); } else { /* We will need an onion key for the router, and we * don't have one. Refuse or relax requirements. */ log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, "Requested exit point '%s' is not known. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { conn->chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); /* Try again with no requested exit */ return circuit_get_open_circ_or_launch(conn, desired_circuit_purpose, circp); } return -1; } } } } if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED) new_circ_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; else if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) new_circ_purpose = CIRCUIT_PURPOSE_C_INTRODUCING; else new_circ_purpose = desired_circuit_purpose; if (options->Tor2webMode && (new_circ_purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND || new_circ_purpose == CIRCUIT_PURPOSE_C_INTRODUCING)) { want_onehop = 1; } { int flags = CIRCLAUNCH_NEED_CAPACITY; if (want_onehop) flags |= CIRCLAUNCH_ONEHOP_TUNNEL; if (need_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; if (need_internal) flags |= CIRCLAUNCH_IS_INTERNAL; circ = circuit_launch_by_extend_info(new_circ_purpose, extend_info, flags); } extend_info_free(extend_info); if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) { /* We just caused a circuit to get built because of this stream. * If this stream has caused a _lot_ of circuits to be built, that's * a bad sign: we should tell the user. */ if (conn->num_circuits_launched < NUM_CIRCUITS_LAUNCHED_THRESHOLD && ++conn->num_circuits_launched == NUM_CIRCUITS_LAUNCHED_THRESHOLD) log_info(LD_CIRC, "The application request to %s:%d has launched " "%d circuits without finding one it likes.", escaped_safe_str_client(conn->socks_request->address), conn->socks_request->port, conn->num_circuits_launched); } else { /* help predict this next time */ rep_hist_note_used_internal(time(NULL), need_uptime, 1); if (circ) { /* write the service_id into circ */ circ->rend_data = rend_data_dup(ENTRY_TO_EDGE_CONN(conn)->rend_data); if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && circ->base_.state == CIRCUIT_STATE_OPEN) rend_client_rendcirc_has_opened(circ); } } } /* endif (!circ) */ if (circ) { /* Mark the circuit with the isolation fields for this connection. * When the circuit arrives, we'll clear these flags: this is * just some internal bookkeeping to make sure that we have * launched enough circuits. */ connection_edge_update_circuit_isolation(conn, circ, 0); } else { log_info(LD_APP, "No safe circuit (purpose %d) ready for edge " "connection; delaying.", desired_circuit_purpose); } *circp = circ; return 0; } /** Return true iff crypt_path is one of the crypt_paths for * circ. */ static int cpath_is_on_circuit(origin_circuit_t *circ, crypt_path_t *crypt_path) { crypt_path_t *cpath, *cpath_next = NULL; for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) { cpath_next = cpath->next; if (crypt_path == cpath) return 1; } return 0; } /** Return true iff client-side optimistic data is supported. */ static int optimistic_data_enabled(void) { const or_options_t *options = get_options(); if (options->OptimisticData < 0) { /* XXX023 consider having auto default to 1 rather than 0 before * the 0.2.3 branch goes stable. See bug 3617. -RD */ const int32_t enabled = networkstatus_get_param(NULL, "UseOptimisticData", 0, 0, 1); return (int)enabled; } return options->OptimisticData; } /** Attach the AP stream apconn to circ's linked list of * p_streams. Also set apconn's cpath_layer to cpath, or to the last * hop in circ's cpath if cpath is NULL. */ static void link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ, crypt_path_t *cpath) { const node_t *exitnode; /* add it into the linked list of streams on this circuit */ log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.", (unsigned)circ->base_.n_circ_id); /* reset it, so we can measure circ timeouts */ ENTRY_TO_CONN(apconn)->timestamp_lastread = time(NULL); ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams; ENTRY_TO_EDGE_CONN(apconn)->on_circuit = TO_CIRCUIT(circ); /* assert_connection_ok(conn, time(NULL)); */ circ->p_streams = ENTRY_TO_EDGE_CONN(apconn); if (connection_edge_is_rendezvous_stream(ENTRY_TO_EDGE_CONN(apconn))) { /* We are attaching a stream to a rendezvous circuit. That means * that an attempt to connect to a hidden service just * succeeded. Tell rendclient.c. */ rend_client_note_connection_attempt_ended( ENTRY_TO_EDGE_CONN(apconn)->rend_data->onion_address); } if (cpath) { /* we were given one; use it */ tor_assert(cpath_is_on_circuit(circ, cpath)); } else { /* use the last hop in the circuit */ tor_assert(circ->cpath); tor_assert(circ->cpath->prev); tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN); cpath = circ->cpath->prev; } ENTRY_TO_EDGE_CONN(apconn)->cpath_layer = cpath; circ->isolation_any_streams_attached = 1; connection_edge_update_circuit_isolation(apconn, circ, 0); /* See if we can use optimistic data on this circuit */ if (cpath->extend_info && (exitnode = node_get_by_id(cpath->extend_info->identity_digest)) && exitnode->rs) { /* Okay; we know what exit node this is. */ if (optimistic_data_enabled() && circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL && exitnode->rs->version_supports_optimistic_data) apconn->may_use_optimistic_data = 1; else apconn->may_use_optimistic_data = 0; log_info(LD_APP, "Looks like completed circuit to %s %s allow " "optimistic data for connection to %s", safe_str_client(node_describe(exitnode)), apconn->may_use_optimistic_data ? "does" : "doesn't", safe_str_client(apconn->socks_request->address)); } } /** Return true iff address is matched by one of the entries in * TrackHostExits. */ int hostname_in_track_host_exits(const or_options_t *options, const char *address) { if (!options->TrackHostExits) return 0; SMARTLIST_FOREACH_BEGIN(options->TrackHostExits, const char *, cp) { if (cp[0] == '.') { /* match end */ if (cp[1] == '\0' || !strcasecmpend(address, cp) || !strcasecmp(address, &cp[1])) return 1; } else if (strcasecmp(cp, address) == 0) { return 1; } } SMARTLIST_FOREACH_END(cp); return 0; } /** If an exit wasn't explicitly specified for conn, consider saving * the exit that we *did* choose for use by future connections to * conn's destination. */ static void consider_recording_trackhost(const entry_connection_t *conn, const origin_circuit_t *circ) { const or_options_t *options = get_options(); char *new_address = NULL; char fp[HEX_DIGEST_LEN+1]; /* Search the addressmap for this conn's destination. */ /* If he's not in the address map.. */ if (!options->TrackHostExits || addressmap_have_mapping(conn->socks_request->address, options->TrackHostExitsExpire)) return; /* nothing to track, or already mapped */ if (!hostname_in_track_host_exits(options, conn->socks_request->address) || !circ->build_state->chosen_exit) return; /* write down the fingerprint of the chosen exit, not the nickname, * because the chosen exit might not be named. */ base16_encode(fp, sizeof(fp), circ->build_state->chosen_exit->identity_digest, DIGEST_LEN); /* Add this exit/hostname pair to the addressmap. */ tor_asprintf(&new_address, "%s.%s.exit", conn->socks_request->address, fp); addressmap_register(conn->socks_request->address, new_address, time(NULL) + options->TrackHostExitsExpire, ADDRMAPSRC_TRACKEXIT, 0, 0); } /** Attempt to attach the connection conn to circ, and send a * begin or resolve cell as appropriate. Return values are as for * connection_ap_handshake_attach_circuit. The stream will exit from the hop * indicated by cpath, or from the last hop in circ's cpath if * cpath is NULL. */ int connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn, origin_circuit_t *circ, crypt_path_t *cpath) { connection_t *base_conn = ENTRY_TO_CONN(conn); tor_assert(conn); tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT || base_conn->state == AP_CONN_STATE_CONTROLLER_WAIT); tor_assert(conn->socks_request); tor_assert(circ); tor_assert(circ->base_.state == CIRCUIT_STATE_OPEN); base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; if (!circ->base_.timestamp_dirty) circ->base_.timestamp_dirty = time(NULL); pathbias_count_use_attempt(circ); link_apconn_to_circ(conn, circ, cpath); tor_assert(conn->socks_request); if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { if (!conn->use_begindir) consider_recording_trackhost(conn, circ); if (connection_ap_handshake_send_begin(conn) < 0) return -1; } else { if (connection_ap_handshake_send_resolve(conn) < 0) return -1; } return 1; } /** Try to find a safe live circuit for CONN_TYPE_AP connection conn. If * we don't find one: if conn cannot be handled by any known nodes, * warn and return -1 (conn needs to die, and is maybe already marked); * else launch new circuit (if necessary) and return 0. * Otherwise, associate conn with a safe live circuit, do the * right next step, and return 1. */ /* XXXX this function should mark for close whenever it returns -1; * its callers shouldn't have to worry about that. */ int connection_ap_handshake_attach_circuit(entry_connection_t *conn) { connection_t *base_conn = ENTRY_TO_CONN(conn); int retval; int conn_age; int want_onehop; tor_assert(conn); tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(conn->socks_request); want_onehop = conn->want_onehop; conn_age = (int)(time(NULL) - base_conn->timestamp_created); if (conn_age >= get_options()->SocksTimeout) { int severity = (tor_addr_is_null(&base_conn->addr) && !base_conn->port) ? LOG_INFO : LOG_NOTICE; log_fn(severity, LD_APP, "Tried for %d seconds to get a connection to %s:%d. Giving up.", conn_age, safe_str_client(conn->socks_request->address), conn->socks_request->port); return -1; } if (!connection_edge_is_rendezvous_stream(ENTRY_TO_EDGE_CONN(conn))) { /* we're a general conn */ origin_circuit_t *circ=NULL; if (conn->chosen_exit_name) { const node_t *node = node_get_by_nickname(conn->chosen_exit_name, 1); int opt = conn->chosen_exit_optional; if (!node && !want_onehop) { /* We ran into this warning when trying to extend a circuit to a * hidden service directory for which we didn't have a router * descriptor. See flyspray task 767 for more details. We should * keep this in mind when deciding to use BEGIN_DIR cells for other * directory requests as well. -KL*/ log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, "Requested exit point '%s' is not known. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { conn->chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); return 0; } return -1; } if (node && !connection_ap_can_use_exit(conn, node)) { log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, "Requested exit point '%s' is excluded or " "would refuse request. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { conn->chosen_exit_optional = 0; tor_free(conn->chosen_exit_name); return 0; } return -1; } } /* find the circuit that we should use, if there is one. */ retval = circuit_get_open_circ_or_launch( conn, CIRCUIT_PURPOSE_C_GENERAL, &circ); if (retval < 1) // XXX023 if we totally fail, this still returns 0 -RD return retval; log_debug(LD_APP|LD_CIRC, "Attaching apconn to circ %u (stream %d sec old).", (unsigned)circ->base_.n_circ_id, conn_age); /* print the circ's path, so people can figure out which circs are * sucking. */ circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ); /* We have found a suitable circuit for our conn. Hurray. */ return connection_ap_handshake_attach_chosen_circuit(conn, circ, NULL); } else { /* we're a rendezvous conn */ origin_circuit_t *rendcirc=NULL, *introcirc=NULL; tor_assert(!ENTRY_TO_EDGE_CONN(conn)->cpath_layer); /* start by finding a rendezvous circuit for us */ retval = circuit_get_open_circ_or_launch( conn, CIRCUIT_PURPOSE_C_REND_JOINED, &rendcirc); if (retval < 0) return -1; /* failed */ if (retval > 0) { tor_assert(rendcirc); /* one is already established, attach */ log_info(LD_REND, "rend joined circ %d already here. attaching. " "(stream %d sec old)", (unsigned)rendcirc->base_.n_circ_id, conn_age); /* Mark rendezvous circuits as 'newly dirty' every time you use * them, since the process of rebuilding a rendezvous circ is so * expensive. There is a tradeoff between linkability and * feasibility, at this point. */ rendcirc->base_.timestamp_dirty = time(NULL); /* We've also attempted to use them. If they fail, we need to * probe them for path bias */ pathbias_count_use_attempt(rendcirc); link_apconn_to_circ(conn, rendcirc, NULL); if (connection_ap_handshake_send_begin(conn) < 0) return 0; /* already marked, let them fade away */ return 1; } if (rendcirc && (rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) { log_info(LD_REND, "pending-join circ %u already here, with intro ack. " "Stalling. (stream %d sec old)", (unsigned)rendcirc->base_.n_circ_id, conn_age); return 0; } /* it's on its way. find an intro circ. */ retval = circuit_get_open_circ_or_launch( conn, CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, &introcirc); if (retval < 0) return -1; /* failed */ if (retval > 0) { /* one has already sent the intro. keep waiting. */ tor_assert(introcirc); log_info(LD_REND, "Intro circ %u present and awaiting ack (rend %u). " "Stalling. (stream %d sec old)", (unsigned)introcirc->base_.n_circ_id, rendcirc ? (unsigned)rendcirc->base_.n_circ_id : 0, conn_age); return 0; } /* now rendcirc and introcirc are each either undefined or not finished */ if (rendcirc && introcirc && rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY) { log_info(LD_REND, "ready rend circ %u already here (no intro-ack yet on " "intro %u). (stream %d sec old)", (unsigned)rendcirc->base_.n_circ_id, (unsigned)introcirc->base_.n_circ_id, conn_age); tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); if (introcirc->base_.state == CIRCUIT_STATE_OPEN) { log_info(LD_REND,"found open intro circ %u (rend %u); sending " "introduction. (stream %d sec old)", (unsigned)introcirc->base_.n_circ_id, (unsigned)rendcirc->base_.n_circ_id, conn_age); switch (rend_client_send_introduction(introcirc, rendcirc)) { case 0: /* success */ rendcirc->base_.timestamp_dirty = time(NULL); introcirc->base_.timestamp_dirty = time(NULL); pathbias_count_use_attempt(introcirc); pathbias_count_use_attempt(rendcirc); assert_circuit_ok(TO_CIRCUIT(rendcirc)); assert_circuit_ok(TO_CIRCUIT(introcirc)); return 0; case -1: /* transient error */ return 0; case -2: /* permanent error */ return -1; default: /* oops */ tor_fragile_assert(); return -1; } } } log_info(LD_REND, "Intro (%u) and rend (%u) circs are not both ready. " "Stalling conn. (%d sec old)", introcirc ? (unsigned)introcirc->base_.n_circ_id : 0, rendcirc ? (unsigned)rendcirc->base_.n_circ_id : 0, conn_age); return 0; } } /** Change circ's purpose to new_purpose. */ void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose) { uint8_t old_purpose; /* Don't allow an OR circ to become an origin circ or vice versa. */ tor_assert(!!(CIRCUIT_IS_ORIGIN(circ)) == !!(CIRCUIT_PURPOSE_IS_ORIGIN(new_purpose))); if (circ->purpose == new_purpose) return; if (CIRCUIT_IS_ORIGIN(circ)) { char old_purpose_desc[80] = ""; strncpy(old_purpose_desc, circuit_purpose_to_string(circ->purpose), 80-1); old_purpose_desc[80-1] = '\0'; log_debug(LD_CIRC, "changing purpose of origin circ %d " "from \"%s\" (%d) to \"%s\" (%d)", TO_ORIGIN_CIRCUIT(circ)->global_identifier, old_purpose_desc, circ->purpose, circuit_purpose_to_string(new_purpose), new_purpose); } old_purpose = circ->purpose; circ->purpose = new_purpose; if (CIRCUIT_IS_ORIGIN(circ)) { control_event_circuit_purpose_changed(TO_ORIGIN_CIRCUIT(circ), old_purpose); } } /** Mark circ so that no more connections can be attached to it. */ void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ) { const or_options_t *options = get_options(); tor_assert(circ); /* XXXX025 This is a kludge; we're only keeping it around in case there's * something that doesn't check unusable_for_new_conns, and to avoid * deeper refactoring of our expiration logic. */ if (! circ->base_.timestamp_dirty) circ->base_.timestamp_dirty = approx_time(); if (options->MaxCircuitDirtiness >= circ->base_.timestamp_dirty) circ->base_.timestamp_dirty = 1; /* prevent underflow */ else circ->base_.timestamp_dirty -= options->MaxCircuitDirtiness; circ->unusable_for_new_conns = 1; } tor-0.2.4.20/src/or/nodelist.h0000644000175000017500000000675112166112777012706 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file nodelist.h * \brief Header file for nodelist.c. **/ #ifndef TOR_NODELIST_H #define TOR_NODELIST_H #define node_assert_ok(n) STMT_BEGIN { \ tor_assert((n)->ri || (n)->rs); \ } STMT_END node_t *node_get_mutable_by_id(const char *identity_digest); const node_t *node_get_by_id(const char *identity_digest); const node_t *node_get_by_hex_id(const char *identity_digest); node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out); node_t *nodelist_add_microdesc(microdesc_t *md); void nodelist_set_consensus(networkstatus_t *ns); void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md); void nodelist_remove_routerinfo(routerinfo_t *ri); void nodelist_purge(void); void nodelist_free_all(void); void nodelist_assert_ok(void); const node_t *node_get_by_nickname(const char *nickname, int warn_if_unnamed); void node_get_verbose_nickname(const node_t *node, char *verbose_name_out); int node_is_named(const node_t *node); int node_is_dir(const node_t *node); int node_has_descriptor(const node_t *node); int node_get_purpose(const node_t *node); #define node_is_bridge(node) \ (node_get_purpose((node)) == ROUTER_PURPOSE_BRIDGE) int node_is_me(const node_t *node); int node_exit_policy_rejects_all(const node_t *node); int node_exit_policy_is_exact(const node_t *node, sa_family_t family); smartlist_t *node_get_all_orports(const node_t *node); int node_allows_single_hop_exits(const node_t *node); const char *node_get_nickname(const node_t *node); const char *node_get_platform(const node_t *node); uint32_t node_get_prim_addr_ipv4h(const node_t *node); void node_get_address_string(const node_t *node, char *cp, size_t len); long node_get_declared_uptime(const node_t *node); time_t node_get_published_on(const node_t *node); const smartlist_t *node_get_declared_family(const node_t *node); int node_ipv6_preferred(const node_t *node); int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out); int node_has_curve25519_onion_key(const node_t *node); smartlist_t *nodelist_get_list(void); /* Temporary during transition to multiple addresses. */ void node_get_addr(const node_t *node, tor_addr_t *addr_out); #define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n)) void nodelist_refresh_countries(void); void node_set_country(node_t *node); void nodelist_add_node_and_family(smartlist_t *nodes, const node_t *node); int nodes_in_same_family(const node_t *node1, const node_t *node2); const node_t *router_find_exact_exit_enclave(const char *address, uint16_t port); int node_is_unreliable(const node_t *router, int need_uptime, int need_capacity, int need_guard); int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port, int need_uptime); void router_set_status(const char *digest, int up); int router_have_minimum_dir_info(void); void router_dir_info_changed(void); const char *get_dir_info_status_string(void); int count_loading_descriptors_progress(void); #endif tor-0.2.4.20/src/or/connection_edge.c0000644000175000017500000034337012255745673014212 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file connection_edge.c * \brief Handle edge streams. **/ #define CONNECTION_EDGE_PRIVATE #include "or.h" #include "addressmap.h" #include "buffers.h" #include "channel.h" #include "circuitlist.h" #include "circuituse.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "connection_or.h" #include "control.h" #include "dns.h" #include "dnsserv.h" #include "dirserv.h" #include "hibernate.h" #include "main.h" #include "nodelist.h" #include "policies.h" #include "reasons.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" #include "rendservice.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "routerset.h" #include "circuitbuild.h" #ifdef HAVE_LINUX_TYPES_H #include #endif #ifdef HAVE_LINUX_NETFILTER_IPV4_H #include #define TRANS_NETFILTER #endif #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) #include #include #define TRANS_PF #endif #define SOCKS4_GRANTED 90 #define SOCKS4_REJECT 91 static int connection_ap_handshake_process_socks(entry_connection_t *conn); static int connection_ap_process_natd(entry_connection_t *conn); static int connection_exit_connect_dir(edge_connection_t *exitconn); static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port); static int connection_ap_supports_optimistic_data(const entry_connection_t *); static void connection_ap_handshake_socks_resolved_addr( entry_connection_t *conn, const tor_addr_t *answer, int ttl, time_t expires); /** An AP stream has failed/finished. If it hasn't already sent back * a socks reply, send one now (based on endreason). Also set * has_sent_end to 1, and mark the conn. */ void connection_mark_unattached_ap_(entry_connection_t *conn, int endreason, int line, const char *file) { connection_t *base_conn = ENTRY_TO_CONN(conn); edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); tor_assert(base_conn->type == CONN_TYPE_AP); ENTRY_TO_EDGE_CONN(conn)->edge_has_sent_end = 1; /* no circ yet */ /* If this is a rendezvous stream and it is failing without ever * being attached to a circuit, assume that an attempt to connect to * the destination hidden service has just ended. * * XXXX This condition doesn't limit to only streams failing * without ever being attached. That sloppiness should be harmless, * but we should fix it someday anyway. */ if ((edge_conn->on_circuit != NULL || edge_conn->edge_has_sent_end) && connection_edge_is_rendezvous_stream(edge_conn)) { rend_client_note_connection_attempt_ended( edge_conn->rend_data->onion_address); } if (base_conn->marked_for_close) { /* This call will warn as appropriate. */ connection_mark_for_close_(base_conn, line, file); return; } if (!conn->socks_request->has_finished) { if (endreason & END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED) log_warn(LD_BUG, "stream (marked at %s:%d) sending two socks replies?", file, line); if (SOCKS_COMMAND_IS_CONNECT(conn->socks_request->command)) connection_ap_handshake_socks_reply(conn, NULL, 0, endreason); else if (SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR_TRANSIENT, 0, NULL, -1, -1); else /* unknown or no handshake at all. send no response. */ conn->socks_request->has_finished = 1; } connection_mark_and_flush_(base_conn, line, file); ENTRY_TO_EDGE_CONN(conn)->end_reason = endreason; } /** There was an EOF. Send an end and mark the connection for close. */ int connection_edge_reached_eof(edge_connection_t *conn) { if (connection_get_inbuf_len(TO_CONN(conn)) && connection_state_is_open(TO_CONN(conn))) { /* it still has stuff to process. don't let it die yet. */ return 0; } log_info(LD_EDGE,"conn (fd "TOR_SOCKET_T_FORMAT") reached eof. Closing.", conn->base_.s); if (!conn->base_.marked_for_close) { /* only mark it if not already marked. it's possible to * get the 'end' right around when the client hangs up on us. */ connection_edge_end(conn, END_STREAM_REASON_DONE); if (conn->base_.type == CONN_TYPE_AP) { /* eof, so don't send a socks reply back */ if (EDGE_TO_ENTRY_CONN(conn)->socks_request) EDGE_TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; } connection_mark_for_close(TO_CONN(conn)); } return 0; } /** Handle new bytes on conn->inbuf based on state: * - If it's waiting for socks info, try to read another step of the * socks handshake out of conn->inbuf. * - If it's waiting for the original destination, fetch it. * - If it's open, then package more relay cells from the stream. * - Else, leave the bytes on inbuf alone for now. * * Mark and return -1 if there was an unexpected error with the conn, * else return 0. */ int connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) { tor_assert(conn); switch (conn->base_.state) { case AP_CONN_STATE_SOCKS_WAIT: if (connection_ap_handshake_process_socks(EDGE_TO_ENTRY_CONN(conn)) <0) { /* already marked */ return -1; } return 0; case AP_CONN_STATE_NATD_WAIT: if (connection_ap_process_natd(EDGE_TO_ENTRY_CONN(conn)) < 0) { /* already marked */ return -1; } return 0; case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) { /* (We already sent an end cell if possible) */ connection_mark_for_close(TO_CONN(conn)); return -1; } return 0; case AP_CONN_STATE_CONNECT_WAIT: if (connection_ap_supports_optimistic_data(EDGE_TO_ENTRY_CONN(conn))) { log_info(LD_EDGE, "data from edge while in '%s' state. Sending it anyway. " "package_partial=%d, buflen=%ld", conn_state_to_string(conn->base_.type, conn->base_.state), package_partial, (long)connection_get_inbuf_len(TO_CONN(conn))); if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) { /* (We already sent an end cell if possible) */ connection_mark_for_close(TO_CONN(conn)); return -1; } return 0; } /* Fall through if the connection is on a circuit without optimistic * data support. */ case EXIT_CONN_STATE_CONNECTING: case AP_CONN_STATE_RENDDESC_WAIT: case AP_CONN_STATE_CIRCUIT_WAIT: case AP_CONN_STATE_RESOLVE_WAIT: case AP_CONN_STATE_CONTROLLER_WAIT: log_info(LD_EDGE, "data from edge while in '%s' state. Leaving it on buffer.", conn_state_to_string(conn->base_.type, conn->base_.state)); return 0; } log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->base_.state); tor_fragile_assert(); connection_edge_end(conn, END_STREAM_REASON_INTERNAL); connection_mark_for_close(TO_CONN(conn)); return -1; } /** This edge needs to be closed, because its circuit has closed. * Mark it for close and return 0. */ int connection_edge_destroy(circid_t circ_id, edge_connection_t *conn) { if (!conn->base_.marked_for_close) { log_info(LD_EDGE, "CircID %u: At an edge. Marking connection for close.", (unsigned) circ_id); if (conn->base_.type == CONN_TYPE_AP) { entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_DESTROY); control_event_stream_bandwidth(conn); control_event_stream_status(entry_conn, STREAM_EVENT_CLOSED, END_STREAM_REASON_DESTROY); conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED; } else { /* closing the circuit, nothing to send an END to */ conn->edge_has_sent_end = 1; conn->end_reason = END_STREAM_REASON_DESTROY; conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED; connection_mark_and_flush(TO_CONN(conn)); } } conn->cpath_layer = NULL; conn->on_circuit = NULL; return 0; } /** Send a raw end cell to the stream with ID stream_id out over the * circ towards the hop identified with cpath_layer. If this * is not a client connection, set the relay end cell's reason for closing * as reason */ static int relay_send_end_cell_from_edge(streamid_t stream_id, circuit_t *circ, uint8_t reason, crypt_path_t *cpath_layer) { char payload[1]; if (CIRCUIT_PURPOSE_IS_CLIENT(circ->purpose)) { /* Never send the server an informative reason code; it doesn't need to * know why the client stream is failing. */ reason = END_STREAM_REASON_MISC; } payload[0] = (char) reason; return relay_send_command_from_edge(stream_id, circ, RELAY_COMMAND_END, payload, 1, cpath_layer); } /** Send a relay end cell from stream conn down conn's circuit, and * remember that we've done so. If this is not a client connection, set the * relay end cell's reason for closing as reason. * * Return -1 if this function has already been called on this conn, * else return 0. */ int connection_edge_end(edge_connection_t *conn, uint8_t reason) { char payload[RELAY_PAYLOAD_SIZE]; size_t payload_len=1; circuit_t *circ; uint8_t control_reason = reason; if (conn->edge_has_sent_end) { log_warn(LD_BUG,"(Harmless.) Calling connection_edge_end (reason %d) " "on an already ended stream?", reason); tor_fragile_assert(); return -1; } if (conn->base_.marked_for_close) { log_warn(LD_BUG, "called on conn that's already marked for close at %s:%d.", conn->base_.marked_for_close_file, conn->base_.marked_for_close); return 0; } circ = circuit_get_by_edge_conn(conn); if (circ && CIRCUIT_PURPOSE_IS_CLIENT(circ->purpose)) { /* If this is a client circuit, don't send the server an informative * reason code; it doesn't need to know why the client stream is * failing. */ reason = END_STREAM_REASON_MISC; } payload[0] = (char)reason; if (reason == END_STREAM_REASON_EXITPOLICY && !connection_edge_is_rendezvous_stream(conn)) { int addrlen; if (tor_addr_family(&conn->base_.addr) == AF_INET) { set_uint32(payload+1, tor_addr_to_ipv4n(&conn->base_.addr)); addrlen = 4; } else { memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16); addrlen = 16; } set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl))); payload_len += 4+addrlen; } if (circ && !circ->marked_for_close) { log_debug(LD_EDGE,"Sending end on conn (fd "TOR_SOCKET_T_FORMAT").", conn->base_.s); connection_edge_send_command(conn, RELAY_COMMAND_END, payload, payload_len); } else { log_debug(LD_EDGE,"No circ to send end on conn " "(fd "TOR_SOCKET_T_FORMAT").", conn->base_.s); } conn->edge_has_sent_end = 1; conn->end_reason = control_reason; return 0; } /** An error has just occurred on an operation on an edge connection * conn. Extract the errno; convert it to an end reason, and send an * appropriate relay end cell to the other end of the connection's circuit. **/ int connection_edge_end_errno(edge_connection_t *conn) { uint8_t reason; tor_assert(conn); reason = errno_to_stream_end_reason(tor_socket_errno(conn->base_.s)); return connection_edge_end(conn, reason); } /** We just wrote some data to conn; act appropriately. * * (That is, if it's open, consider sending a stream-level sendme cell if we * have just flushed enough.) */ int connection_edge_flushed_some(edge_connection_t *conn) { switch (conn->base_.state) { case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: connection_edge_consider_sending_sendme(conn); break; } return 0; } /** Connection conn has finished writing and has no bytes left on * its outbuf. * * If it's in state 'open', stop writing, consider responding with a * sendme, and return. * Otherwise, stop writing and return. * * If conn is broken, mark it for close and return -1, else * return 0. */ int connection_edge_finished_flushing(edge_connection_t *conn) { tor_assert(conn); switch (conn->base_.state) { case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: connection_edge_consider_sending_sendme(conn); return 0; case AP_CONN_STATE_SOCKS_WAIT: case AP_CONN_STATE_NATD_WAIT: case AP_CONN_STATE_RENDDESC_WAIT: case AP_CONN_STATE_CIRCUIT_WAIT: case AP_CONN_STATE_CONNECT_WAIT: case AP_CONN_STATE_CONTROLLER_WAIT: case AP_CONN_STATE_RESOLVE_WAIT: return 0; default: log_warn(LD_BUG, "Called in unexpected state %d.",conn->base_.state); tor_fragile_assert(); return -1; } return 0; } /** Longest size for the relay payload of a RELAY_CONNECTED cell that we're * able to generate. */ /* 4 zero bytes; 1 type byte; 16 byte IPv6 address; 4 byte TTL. */ #define MAX_CONNECTED_CELL_PAYLOAD_LEN 25 /** Set the buffer at payload_out -- which must have at least * MAX_CONNECTED_CELL_PAYLOAD_LEN bytes available -- to the body of a * RELAY_CONNECTED cell indicating that we have connected to addr, and * that the name resolution that led us to addr will be valid for * ttl seconds. Return -1 on error, or the number of bytes used on * success. */ /* private */int connected_cell_format_payload(uint8_t *payload_out, const tor_addr_t *addr, uint32_t ttl) { const sa_family_t family = tor_addr_family(addr); int connected_payload_len; /* should be needless */ memset(payload_out, 0, MAX_CONNECTED_CELL_PAYLOAD_LEN); if (family == AF_INET) { set_uint32(payload_out, tor_addr_to_ipv4n(addr)); connected_payload_len = 4; } else if (family == AF_INET6) { set_uint32(payload_out, 0); set_uint8(payload_out + 4, 6); memcpy(payload_out + 5, tor_addr_to_in6_addr8(addr), 16); connected_payload_len = 21; } else { return -1; } set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl))); connected_payload_len += 4; tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN); return connected_payload_len; } /** Connected handler for exit connections: start writing pending * data, deliver 'CONNECTED' relay cells as appropriate, and check * any pending data that may have been received. */ int connection_edge_finished_connecting(edge_connection_t *edge_conn) { connection_t *conn; tor_assert(edge_conn); tor_assert(edge_conn->base_.type == CONN_TYPE_EXIT); conn = TO_CONN(edge_conn); tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING); log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.", escaped_safe_str(conn->address), conn->port, safe_str(fmt_and_decorate_addr(&conn->addr))); rep_hist_note_exit_stream_opened(conn->port); conn->state = EXIT_CONN_STATE_OPEN; IF_HAS_NO_BUFFEREVENT(conn) connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */ if (connection_get_outbuf_len(conn)) /* in case there are any queued relay * cells */ connection_start_writing(conn); /* deliver a 'connected' relay cell back through the circuit. */ if (connection_edge_is_rendezvous_stream(edge_conn)) { if (connection_edge_send_command(edge_conn, RELAY_COMMAND_CONNECTED, NULL, 0) < 0) return 0; /* circuit is closed, don't continue */ } else { uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN]; int connected_payload_len = connected_cell_format_payload(connected_payload, &conn->addr, edge_conn->address_ttl); if (connected_payload_len < 0) return -1; if (connection_edge_send_command(edge_conn, RELAY_COMMAND_CONNECTED, (char*)connected_payload, connected_payload_len) < 0) return 0; /* circuit is closed, don't continue */ } tor_assert(edge_conn->package_window > 0); /* in case the server has written anything */ return connection_edge_process_inbuf(edge_conn, 1); } /** Common code to connection_(ap|exit)_about_to_close. */ static void connection_edge_about_to_close(edge_connection_t *edge_conn) { if (!edge_conn->edge_has_sent_end) { connection_t *conn = TO_CONN(edge_conn); log_warn(LD_BUG, "(Harmless.) Edge connection (marked at %s:%d) " "hasn't sent end yet?", conn->marked_for_close_file, conn->marked_for_close); tor_fragile_assert(); } } /** Called when we're about to finally unlink and free an AP (client) * connection: perform necessary accounting and cleanup */ void connection_ap_about_to_close(entry_connection_t *entry_conn) { circuit_t *circ; edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn); connection_t *conn = ENTRY_TO_CONN(entry_conn); if (entry_conn->socks_request->has_finished == 0) { /* since conn gets removed right after this function finishes, * there's no point trying to send back a reply at this point. */ log_warn(LD_BUG,"Closing stream (marked at %s:%d) without sending" " back a socks reply.", conn->marked_for_close_file, conn->marked_for_close); } if (!edge_conn->end_reason) { log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having" " set end_reason.", conn->marked_for_close_file, conn->marked_for_close); } if (entry_conn->dns_server_request) { log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having" " replied to DNS request.", conn->marked_for_close_file, conn->marked_for_close); dnsserv_reject_request(entry_conn); } control_event_stream_bandwidth(edge_conn); control_event_stream_status(entry_conn, STREAM_EVENT_CLOSED, edge_conn->end_reason); circ = circuit_get_by_edge_conn(edge_conn); if (circ) circuit_detach_stream(circ, edge_conn); } /** Called when we're about to finally unlink and free an exit * connection: perform necessary accounting and cleanup */ void connection_exit_about_to_close(edge_connection_t *edge_conn) { circuit_t *circ; connection_t *conn = TO_CONN(edge_conn); connection_edge_about_to_close(edge_conn); circ = circuit_get_by_edge_conn(edge_conn); if (circ) circuit_detach_stream(circ, edge_conn); if (conn->state == EXIT_CONN_STATE_RESOLVING) { connection_dns_remove(edge_conn); } } /** Define a schedule for how long to wait between retrying * application connections. Rather than waiting a fixed amount of * time between each retry, we wait 10 seconds each for the first * two tries, and 15 seconds for each retry after * that. Hopefully this will improve the expected user experience. */ static int compute_retry_timeout(entry_connection_t *conn) { int timeout = get_options()->CircuitStreamTimeout; if (timeout) /* if our config options override the default, use them */ return timeout; if (conn->num_socks_retries < 2) /* try 0 and try 1 */ return 10; return 15; } /** Find all general-purpose AP streams waiting for a response that sent their * begin/resolve cell too long ago. Detach from their current circuit, and * mark their current circuit as unsuitable for new streams. Then call * connection_ap_handshake_attach_circuit() to attach to a new circuit (if * available) or launch a new one. * * For rendezvous streams, simply give up after SocksTimeout seconds (with no * retry attempt). */ void connection_ap_expire_beginning(void) { edge_connection_t *conn; entry_connection_t *entry_conn; circuit_t *circ; time_t now = time(NULL); const or_options_t *options = get_options(); int severity; int cutoff; int seconds_idle, seconds_since_born; smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { if (base_conn->type != CONN_TYPE_AP || base_conn->marked_for_close) continue; entry_conn = TO_ENTRY_CONN(base_conn); conn = ENTRY_TO_EDGE_CONN(entry_conn); /* if it's an internal linked connection, don't yell its status. */ severity = (tor_addr_is_null(&base_conn->addr) && !base_conn->port) ? LOG_INFO : LOG_NOTICE; seconds_idle = (int)( now - base_conn->timestamp_lastread ); seconds_since_born = (int)( now - base_conn->timestamp_created ); if (base_conn->state == AP_CONN_STATE_OPEN) continue; /* We already consider SocksTimeout in * connection_ap_handshake_attach_circuit(), but we need to consider * it here too because controllers that put streams in controller_wait * state never ask Tor to attach the circuit. */ if (AP_CONN_STATE_IS_UNATTACHED(base_conn->state)) { if (seconds_since_born >= options->SocksTimeout) { log_fn(severity, LD_APP, "Tried for %d seconds to get a connection to %s:%d. " "Giving up. (%s)", seconds_since_born, safe_str_client(entry_conn->socks_request->address), entry_conn->socks_request->port, conn_state_to_string(CONN_TYPE_AP, base_conn->state)); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); } continue; } /* We're in state connect_wait or resolve_wait now -- waiting for a * reply to our relay cell. See if we want to retry/give up. */ cutoff = compute_retry_timeout(entry_conn); if (seconds_idle < cutoff) continue; circ = circuit_get_by_edge_conn(conn); if (!circ) { /* it's vanished? */ log_info(LD_APP,"Conn is waiting (address %s), but lost its circ.", safe_str_client(entry_conn->socks_request->address)); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); continue; } if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { if (seconds_idle >= options->SocksTimeout) { log_fn(severity, LD_REND, "Rend stream is %d seconds late. Giving up on address" " '%s.onion'.", seconds_idle, safe_str_client(entry_conn->socks_request->address)); /* Roll back path bias use state so that we probe the circuit * if nothing else succeeds on it */ pathbias_mark_use_rollback(TO_ORIGIN_CIRCUIT(circ)); connection_edge_end(conn, END_STREAM_REASON_TIMEOUT); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); } continue; } if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL && circ->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT && circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { log_warn(LD_BUG, "circuit->purpose == CIRCUIT_PURPOSE_C_GENERAL failed. " "The purpose on the circuit was %s; it was in state %s, " "path_state %s.", circuit_purpose_to_string(circ->purpose), circuit_state_to_string(circ->state), CIRCUIT_IS_ORIGIN(circ) ? pathbias_state_to_string(TO_ORIGIN_CIRCUIT(circ)->path_state) : "none"); } log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP, "We tried for %d seconds to connect to '%s' using exit %s." " Retrying on a new circuit.", seconds_idle, safe_str_client(entry_conn->socks_request->address), conn->cpath_layer ? extend_info_describe(conn->cpath_layer->extend_info): "*unnamed*"); /* send an end down the circuit */ connection_edge_end(conn, END_STREAM_REASON_TIMEOUT); /* un-mark it as ending, since we're going to reuse it */ conn->edge_has_sent_end = 0; conn->end_reason = 0; /* make us not try this circuit again, but allow * current streams on it to survive if they can */ mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ)); /* give our stream another 'cutoff' seconds to try */ conn->base_.timestamp_lastread += cutoff; if (entry_conn->num_socks_retries < 250) /* avoid overflow */ entry_conn->num_socks_retries++; /* move it back into 'pending' state, and try to attach. */ if (connection_ap_detach_retriable(entry_conn, TO_ORIGIN_CIRCUIT(circ), END_STREAM_REASON_TIMEOUT)<0) { if (!base_conn->marked_for_close) connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_CANT_ATTACH); } } SMARTLIST_FOREACH_END(base_conn); } /** Tell any AP streams that are waiting for a new circuit to try again, * either attaching to an available circ or launching a new one. */ void connection_ap_attach_pending(void) { entry_connection_t *entry_conn; smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { if (conn->marked_for_close || conn->type != CONN_TYPE_AP || conn->state != AP_CONN_STATE_CIRCUIT_WAIT) continue; entry_conn = TO_ENTRY_CONN(conn); if (connection_ap_handshake_attach_circuit(entry_conn) < 0) { if (!conn->marked_for_close) connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_CANT_ATTACH); } } SMARTLIST_FOREACH_END(conn); } /** Tell any AP streams that are waiting for a one-hop tunnel to * failed_digest that they are going to fail. */ /* XXX024 We should get rid of this function, and instead attach * one-hop streams to circ->p_streams so they get marked in * circuit_mark_for_close like normal p_streams. */ void connection_ap_fail_onehop(const char *failed_digest, cpath_build_state_t *build_state) { entry_connection_t *entry_conn; char digest[DIGEST_LEN]; smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { if (conn->marked_for_close || conn->type != CONN_TYPE_AP || conn->state != AP_CONN_STATE_CIRCUIT_WAIT) continue; entry_conn = TO_ENTRY_CONN(conn); if (!entry_conn->want_onehop) continue; if (hexdigest_to_digest(entry_conn->chosen_exit_name, digest) < 0 || tor_memneq(digest, failed_digest, DIGEST_LEN)) continue; if (tor_digest_is_zero(digest)) { /* we don't know the digest; have to compare addr:port */ tor_addr_t addr; if (!build_state || !build_state->chosen_exit || !entry_conn->socks_request || !entry_conn->socks_request->address) continue; if (tor_addr_parse(&addr, entry_conn->socks_request->address)<0 || !tor_addr_eq(&build_state->chosen_exit->addr, &addr) || build_state->chosen_exit->port != entry_conn->socks_request->port) continue; } log_info(LD_APP, "Closing one-hop stream to '%s/%s' because the OR conn " "just failed.", entry_conn->chosen_exit_name, entry_conn->socks_request->address); connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); } SMARTLIST_FOREACH_END(conn); } /** A circuit failed to finish on its last hop info. If there * are any streams waiting with this exit node in mind, but they * don't absolutely require it, make them give up on it. */ void circuit_discard_optional_exit_enclaves(extend_info_t *info) { entry_connection_t *entry_conn; const node_t *r1, *r2; smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { if (conn->marked_for_close || conn->type != CONN_TYPE_AP || conn->state != AP_CONN_STATE_CIRCUIT_WAIT) continue; entry_conn = TO_ENTRY_CONN(conn); if (!entry_conn->chosen_exit_optional && !entry_conn->chosen_exit_retries) continue; r1 = node_get_by_nickname(entry_conn->chosen_exit_name, 0); r2 = node_get_by_id(info->identity_digest); if (!r1 || !r2 || r1 != r2) continue; tor_assert(entry_conn->socks_request); if (entry_conn->chosen_exit_optional) { log_info(LD_APP, "Giving up on enclave exit '%s' for destination %s.", safe_str_client(entry_conn->chosen_exit_name), escaped_safe_str_client(entry_conn->socks_request->address)); entry_conn->chosen_exit_optional = 0; tor_free(entry_conn->chosen_exit_name); /* clears it */ /* if this port is dangerous, warn or reject it now that we don't * think it'll be using an enclave. */ consider_plaintext_ports(entry_conn, entry_conn->socks_request->port); } if (entry_conn->chosen_exit_retries) { if (--entry_conn->chosen_exit_retries == 0) { /* give up! */ clear_trackexithost_mappings(entry_conn->chosen_exit_name); tor_free(entry_conn->chosen_exit_name); /* clears it */ /* if this port is dangerous, warn or reject it now that we don't * think it'll be using an enclave. */ consider_plaintext_ports(entry_conn, entry_conn->socks_request->port); } } } SMARTLIST_FOREACH_END(conn); } /** The AP connection conn has just failed while attaching or * sending a BEGIN or resolving on circ, but another circuit * might work. Detach the circuit, and either reattach it, launch a * new circuit, tell the controller, or give up as appropriate. * * Returns -1 on err, 1 on success, 0 on not-yet-sure. */ int connection_ap_detach_retriable(entry_connection_t *conn, origin_circuit_t *circ, int reason) { control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason); ENTRY_TO_CONN(conn)->timestamp_lastread = time(NULL); /* Roll back path bias use state so that we probe the circuit * if nothing else succeeds on it */ pathbias_mark_use_rollback(circ); if (conn->pending_optimistic_data) { generic_buffer_set_to_copy(&conn->sending_optimistic_data, conn->pending_optimistic_data); } if (!get_options()->LeaveStreamsUnattached || conn->use_begindir) { /* If we're attaching streams ourself, or if this connection is * a tunneled directory connection, then just attach it. */ ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CIRCUIT_WAIT; circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn)); return connection_ap_handshake_attach_circuit(conn); } else { ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn)); return 0; } } /** Check if conn is using a dangerous port. Then warn and/or * reject depending on our config options. */ static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port) { const or_options_t *options = get_options(); int reject = smartlist_contains_int_as_string( options->RejectPlaintextPorts, port); if (smartlist_contains_int_as_string(options->WarnPlaintextPorts, port)) { log_warn(LD_APP, "Application request to port %d: this port is " "commonly used for unencrypted protocols. Please make sure " "you don't send anything you would mind the rest of the " "Internet reading!%s", port, reject ? " Closing." : ""); control_event_client_status(LOG_WARN, "DANGEROUS_PORT PORT=%d RESULT=%s", port, reject ? "REJECT" : "WARN"); } if (reject) { log_info(LD_APP, "Port %d listed in RejectPlaintextPorts. Closing.", port); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; } return 0; } /** How many times do we try connecting with an exit configured via * TrackHostExits before concluding that it won't work any more and trying a * different one? */ #define TRACKHOSTEXITS_RETRIES 5 /** Call connection_ap_handshake_rewrite_and_attach() unless a controller * asked us to leave streams unattached. Return 0 in that case. * * See connection_ap_handshake_rewrite_and_attach()'s * documentation for arguments and return value. */ int connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn, origin_circuit_t *circ, crypt_path_t *cpath) { const or_options_t *options = get_options(); if (options->LeaveStreamsUnattached) { ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; return 0; } return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath); } /** Connection conn just finished its socks handshake, or the * controller asked us to take care of it. If circ is defined, * then that's where we'll want to attach it. Otherwise we have to * figure it out ourselves. * * First, parse whether it's a .exit address, remap it, and so on. Then * if it's for a general circuit, try to attach it to a circuit (or launch * one as needed), else if it's for a rendezvous circuit, fetch a * rendezvous descriptor first (or attach/launch a circuit if the * rendezvous descriptor is already here and fresh enough). * * The stream will exit from the hop * indicated by cpath, or from the last hop in circ's cpath if * cpath is NULL. */ int connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, origin_circuit_t *circ, crypt_path_t *cpath) { socks_request_t *socks = conn->socks_request; hostname_type_t addresstype; const or_options_t *options = get_options(); tor_addr_t addr_tmp; /* We set this to true if this is an address we should automatically * remap to a local address in VirtualAddrNetwork */ int automap = 0; char orig_address[MAX_SOCKS_ADDR_LEN]; time_t map_expires = TIME_MAX; time_t now = time(NULL); connection_t *base_conn = ENTRY_TO_CONN(conn); addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE; tor_strlower(socks->address); /* normalize it */ strlcpy(orig_address, socks->address, sizeof(orig_address)); log_debug(LD_APP,"Client asked for %s:%d", safe_str_client(socks->address), socks->port); if (!strcmpend(socks->address, ".exit") && !options->AllowDotExit) { log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to " "security risks. Set AllowDotExit in your torrc to enable " "it (at your own risk)."); control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } if (! conn->original_dest_address) conn->original_dest_address = tor_strdup(conn->socks_request->address); if (socks->command == SOCKS_COMMAND_RESOLVE && tor_addr_parse(&addr_tmp, socks->address)<0 && options->AutomapHostsOnResolve) { automap = addressmap_address_should_automap(socks->address, options); if (automap) { const char *new_addr; int addr_type = RESOLVED_TYPE_IPV4; if (conn->socks_request->socks_version != 4) { if (!conn->ipv4_traffic_ok || (conn->ipv6_traffic_ok && conn->prefer_ipv6_traffic) || conn->prefer_ipv6_virtaddr) addr_type = RESOLVED_TYPE_IPV6; } new_addr = addressmap_register_virtual_address( addr_type, tor_strdup(socks->address)); if (! new_addr) { log_warn(LD_APP, "Unable to automap address %s", escaped_safe_str(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL); return -1; } log_info(LD_APP, "Automapping %s to %s", escaped_safe_str_client(socks->address), safe_str_client(new_addr)); strlcpy(socks->address, new_addr, sizeof(socks->address)); } } if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) { unsigned rewrite_flags = 0; if (conn->use_cached_ipv4_answers) rewrite_flags |= AMR_FLAG_USE_IPV4_DNS; if (conn->use_cached_ipv6_answers) rewrite_flags |= AMR_FLAG_USE_IPV6_DNS; if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address), rewrite_flags, &map_expires)) { char *result = tor_strdup(socks->address); /* remember _what_ is supposed to have been resolved. */ tor_snprintf(socks->address, sizeof(socks->address), "REVERSE[%s]", orig_address); connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_HOSTNAME, strlen(result), (uint8_t*)result, -1, map_expires); connection_mark_unattached_ap(conn, END_STREAM_REASON_DONE | END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); return 0; } if (options->ClientDNSRejectInternalAddresses) { /* Don't let people try to do a reverse lookup on 10.0.0.1. */ tor_addr_t addr; int ok; ok = tor_addr_parse_PTR_name( &addr, socks->address, AF_UNSPEC, 1); if (ok == 1 && tor_addr_is_internal(&addr, 0)) { connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR, 0, NULL, -1, TIME_MAX); connection_mark_unattached_ap(conn, END_STREAM_REASON_SOCKSPROTOCOL | END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); return -1; } } } else if (!automap) { /* For address map controls, remap the address. */ unsigned rewrite_flags = 0; if (conn->use_cached_ipv4_answers) rewrite_flags |= AMR_FLAG_USE_IPV4_DNS; if (conn->use_cached_ipv6_answers) rewrite_flags |= AMR_FLAG_USE_IPV6_DNS; if (addressmap_rewrite(socks->address, sizeof(socks->address), rewrite_flags, &map_expires, &exit_source)) { control_event_stream_status(conn, STREAM_EVENT_REMAP, REMAP_STREAM_SOURCE_CACHE); } } if (!automap && address_is_in_virtual_range(socks->address)) { /* This address was probably handed out by client_dns_get_unmapped_address, * but the mapping was discarded for some reason. We *don't* want to send * the address through Tor; that's likely to fail, and may leak * information. */ log_warn(LD_APP,"Missing mapping for virtual address '%s'. Refusing.", safe_str_client(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL); return -1; } /* Parse the address provided by SOCKS. Modify it in-place if it * specifies a hidden-service (.onion) or particular exit node (.exit). */ addresstype = parse_extended_hostname(socks->address); if (addresstype == BAD_HOSTNAME) { control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } if (addresstype == EXIT_HOSTNAME) { /* foo.exit -- modify conn->chosen_exit_node to specify the exit * node, and conn->address to hold only the address portion. */ char *s = strrchr(socks->address,'.'); /* If StrictNodes is not set, then .exit overrides ExcludeNodes. */ routerset_t *excludeset = options->StrictNodes ? options->ExcludeExitNodesUnion_ : options->ExcludeExitNodes; const node_t *node; if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) { /* Whoops; this one is stale. It must have gotten added earlier, * when AllowDotExit was on. */ log_warn(LD_APP,"Stale automapped address for '%s.exit', with " "AllowDotExit disabled. Refusing.", safe_str_client(socks->address)); control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } if (exit_source == ADDRMAPSRC_DNS || (exit_source == ADDRMAPSRC_NONE && !options->AllowDotExit)) { /* It shouldn't be possible to get a .exit address from any of these * sources. */ log_warn(LD_BUG,"Address '%s.exit', with impossible source for the " ".exit part. Refusing.", safe_str_client(socks->address)); control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } tor_assert(!automap); if (s) { /* The address was of the form "(stuff).(name).exit */ if (s[1] != '\0') { conn->chosen_exit_name = tor_strdup(s+1); node = node_get_by_nickname(conn->chosen_exit_name, 1); if (exit_source == ADDRMAPSRC_TRACKEXIT) { /* We 5 tries before it expires the addressmap */ conn->chosen_exit_retries = TRACKHOSTEXITS_RETRIES; } *s = 0; } else { /* Oops, the address was (stuff)..exit. That's not okay. */ log_warn(LD_APP,"Malformed exit address '%s.exit'. Refusing.", safe_str_client(socks->address)); control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } } else { /* It looks like they just asked for "foo.exit". */ conn->chosen_exit_name = tor_strdup(socks->address); node = node_get_by_nickname(conn->chosen_exit_name, 1); if (node) { *socks->address = 0; node_get_address_string(node, socks->address, sizeof(socks->address)); } } /* Now make sure that the chosen exit exists... */ if (!node) { log_warn(LD_APP, "Unrecognized relay in exit address '%s.exit'. Refusing.", safe_str_client(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } /* ...and make sure that it isn't excluded. */ if (routerset_contains_node(excludeset, node)) { log_warn(LD_APP, "Excluded relay in exit address '%s.exit'. Refusing.", safe_str_client(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } /* XXXX024-1090 Should we also allow foo.bar.exit if ExitNodes is set and Bar is not listed in it? I say yes, but our revised manpage branch implies no. */ } if (addresstype != ONION_HOSTNAME) { /* not a hidden-service request (i.e. normal or .exit) */ if (address_is_invalid_destination(socks->address, 1)) { control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); log_warn(LD_APP, "Destination '%s' seems to be an invalid hostname. Failing.", safe_str_client(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } if (options->Tor2webMode) { log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname %s " "because tor2web mode is enabled.", safe_str_client(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; } if (socks->command == SOCKS_COMMAND_RESOLVE) { tor_addr_t answer; /* Reply to resolves immediately if we can. */ if (tor_addr_parse(&answer, socks->address) >= 0) {/* is it an IP? */ /* remember _what_ is supposed to have been resolved. */ strlcpy(socks->address, orig_address, sizeof(socks->address)); connection_ap_handshake_socks_resolved_addr(conn, &answer, -1, map_expires); connection_mark_unattached_ap(conn, END_STREAM_REASON_DONE | END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); return 0; } tor_assert(!automap); rep_hist_note_used_resolve(now); /* help predict this next time */ } else if (socks->command == SOCKS_COMMAND_CONNECT) { tor_assert(!automap); if (socks->port == 0) { log_notice(LD_APP,"Application asked to connect to port 0. Refusing."); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } if (options->ClientRejectInternalAddresses && !conn->use_begindir && !conn->chosen_exit_name && !circ) { tor_addr_t addr; if (tor_addr_hostname_is_local(socks->address) || (tor_addr_parse(&addr, socks->address) >= 0 && tor_addr_is_internal(&addr, 0))) { /* If this is an explicit private address with no chosen exit node, * then we really don't want to try to connect to it. That's * probably an error. */ if (conn->is_transparent_ap) { #define WARN_INTRVL_LOOP 300 static ratelim_t loop_warn_limit = RATELIM_INIT(WARN_INTRVL_LOOP); char *m; if ((m = rate_limit_log(&loop_warn_limit, approx_time()))) { log_warn(LD_NET, "Rejecting request for anonymous connection to private " "address %s on a TransPort or NATDPort. Possible loop " "in your NAT rules?%s", safe_str_client(socks->address), m); tor_free(m); } } else { #define WARN_INTRVL_PRIV 300 static ratelim_t priv_warn_limit = RATELIM_INIT(WARN_INTRVL_PRIV); char *m; if ((m = rate_limit_log(&priv_warn_limit, approx_time()))) { log_warn(LD_NET, "Rejecting SOCKS request for anonymous connection to " "private address %s.%s", safe_str_client(socks->address),m); tor_free(m); } } connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR); return -1; } } { tor_addr_t addr; /* XXX Duplicate call to tor_addr_parse. */ if (tor_addr_parse(&addr, socks->address) >= 0) { sa_family_t family = tor_addr_family(&addr); if ((family == AF_INET && ! conn->ipv4_traffic_ok) || (family == AF_INET6 && ! conn->ipv4_traffic_ok)) { log_warn(LD_NET, "Rejecting SOCKS request for an IP address " "family that this listener does not support."); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; } else if (family == AF_INET6 && socks->socks_version == 4) { log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address."); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; } else if (socks->socks_version == 4 && !conn->ipv4_traffic_ok) { log_warn(LD_NET, "Rejecting SOCKS4 request on a listener with " "no IPv4 traffic supported."); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; } else if (family == AF_INET6) { conn->ipv4_traffic_ok = 0; } else if (family == AF_INET) { conn->ipv6_traffic_ok = 0; } } } if (socks->socks_version == 4) conn->ipv6_traffic_ok = 0; if (!conn->use_begindir && !conn->chosen_exit_name && !circ) { /* see if we can find a suitable enclave exit */ const node_t *r = router_find_exact_exit_enclave(socks->address, socks->port); if (r) { log_info(LD_APP, "Redirecting address %s to exit at enclave router %s", safe_str_client(socks->address), node_describe(r)); /* use the hex digest, not nickname, in case there are two routers with this nickname */ conn->chosen_exit_name = tor_strdup(hex_str(r->identity, DIGEST_LEN)); conn->chosen_exit_optional = 1; } } /* warn or reject if it's using a dangerous port */ if (!conn->use_begindir && !conn->chosen_exit_name && !circ) if (consider_plaintext_ports(conn, socks->port) < 0) return -1; if (!conn->use_begindir) { /* help predict this next time */ rep_hist_note_used_port(now, socks->port); } } else if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) { rep_hist_note_used_resolve(now); /* help predict this next time */ /* no extra processing needed */ } else { tor_fragile_assert(); } base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; if ((circ && connection_ap_handshake_attach_chosen_circuit( conn, circ, cpath) < 0) || (!circ && connection_ap_handshake_attach_circuit(conn) < 0)) { if (!base_conn->marked_for_close) connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); return -1; } return 0; } else { /* it's a hidden-service request */ rend_cache_entry_t *entry; int r; rend_service_authorization_t *client_auth; rend_data_t *rend_data; tor_assert(!automap); if (SOCKS_COMMAND_IS_RESOLVE(socks->command)) { /* if it's a resolve request, fail it right now, rather than * building all the circuits and then realizing it won't work. */ log_warn(LD_APP, "Resolve requests to hidden services not allowed. Failing."); connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR, 0,NULL,-1,TIME_MAX); connection_mark_unattached_ap(conn, END_STREAM_REASON_SOCKSPROTOCOL | END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); return -1; } if (circ) { log_warn(LD_CONTROL, "Attachstream to a circuit is not " "supported for .onion addresses currently. Failing."); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } ENTRY_TO_EDGE_CONN(conn)->rend_data = rend_data = tor_malloc_zero(sizeof(rend_data_t)); strlcpy(rend_data->onion_address, socks->address, sizeof(rend_data->onion_address)); log_info(LD_REND,"Got a hidden service request for ID '%s'", safe_str_client(rend_data->onion_address)); /* see if we already have it cached */ r = rend_cache_lookup_entry(rend_data->onion_address, -1, &entry); if (r<0) { log_warn(LD_BUG,"Invalid service name '%s'", safe_str_client(rend_data->onion_address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } /* Help predict this next time. We're not sure if it will need * a stable circuit yet, but we know we'll need *something*. */ rep_hist_note_used_internal(now, 0, 1); /* Look up if we have client authorization for it. */ client_auth = rend_client_lookup_service_authorization( rend_data->onion_address); if (client_auth) { log_info(LD_REND, "Using previously configured client authorization " "for hidden service request."); memcpy(rend_data->descriptor_cookie, client_auth->descriptor_cookie, REND_DESC_COOKIE_LEN); rend_data->auth_type = client_auth->auth_type; } if (r==0) { base_conn->state = AP_CONN_STATE_RENDDESC_WAIT; log_info(LD_REND, "Unknown descriptor %s. Fetching.", safe_str_client(rend_data->onion_address)); rend_client_refetch_v2_renddesc(rend_data); } else { /* r > 0 */ base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; log_info(LD_REND, "Descriptor is here. Great."); if (connection_ap_handshake_attach_circuit(conn) < 0) { if (!base_conn->marked_for_close) connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); return -1; } } return 0; } return 0; /* unreached but keeps the compiler happy */ } #ifdef TRANS_PF static int pf_socket = -1; int get_pf_socket(void) { int pf; /* This should be opened before dropping privileges. */ if (pf_socket >= 0) return pf_socket; #ifdef OPENBSD /* only works on OpenBSD */ pf = tor_open_cloexec("/dev/pf", O_RDONLY, 0); #else /* works on NetBSD and FreeBSD */ pf = tor_open_cloexec("/dev/pf", O_RDWR, 0); #endif if (pf < 0) { log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno)); return -1; } pf_socket = pf; return pf_socket; } #endif /** Fetch the original destination address and port from a * system-specific interface and put them into a * socks_request_t as if they came from a socks request. * * Return -1 if an error prevents fetching the destination, * else return 0. */ static int connection_ap_get_original_destination(entry_connection_t *conn, socks_request_t *req) { #ifdef TRANS_NETFILTER /* Linux 2.4+ */ struct sockaddr_storage orig_dst; socklen_t orig_dst_len = sizeof(orig_dst); tor_addr_t addr; if (getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr*)&orig_dst, &orig_dst_len) < 0) { int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s); log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e)); return -1; } tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port); tor_addr_to_str(req->address, &addr, sizeof(req->address), 1); return 0; #elif defined(TRANS_PF) struct sockaddr_storage proxy_addr; socklen_t proxy_addr_len = sizeof(proxy_addr); struct sockaddr *proxy_sa = (struct sockaddr*) &proxy_addr; struct pfioc_natlook pnl; tor_addr_t addr; int pf = -1; if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&proxy_addr, &proxy_addr_len) < 0) { int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s); log_warn(LD_NET, "getsockname() to determine transocks destination " "failed: %s", tor_socket_strerror(e)); return -1; } memset(&pnl, 0, sizeof(pnl)); pnl.proto = IPPROTO_TCP; pnl.direction = PF_OUT; if (proxy_sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)proxy_sa; pnl.af = AF_INET; pnl.saddr.v4.s_addr = tor_addr_to_ipv4n(&ENTRY_TO_CONN(conn)->addr); pnl.sport = htons(ENTRY_TO_CONN(conn)->port); pnl.daddr.v4.s_addr = sin->sin_addr.s_addr; pnl.dport = sin->sin_port; } else if (proxy_sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)proxy_sa; pnl.af = AF_INET6; memcpy(&pnl.saddr.v6, tor_addr_to_in6(&ENTRY_TO_CONN(conn)->addr), sizeof(struct in6_addr)); pnl.sport = htons(ENTRY_TO_CONN(conn)->port); memcpy(&pnl.daddr.v6, &sin6->sin6_addr, sizeof(struct in6_addr)); pnl.dport = sin6->sin6_port; } else { log_warn(LD_NET, "getsockname() gave an unexpected address family (%d)", (int)proxy_sa->sa_family); return -1; } pf = get_pf_socket(); if (pf<0) return -1; if (ioctl(pf, DIOCNATLOOK, &pnl) < 0) { log_warn(LD_NET, "ioctl(DIOCNATLOOK) failed: %s", strerror(errno)); return -1; } if (pnl.af == AF_INET) { tor_addr_from_ipv4n(&addr, pnl.rdaddr.v4.s_addr); } else if (pnl.af == AF_INET6) { tor_addr_from_in6(&addr, &pnl.rdaddr.v6); } else { tor_fragile_assert(); return -1; } tor_addr_to_str(req->address, &addr, sizeof(req->address), 1); req->port = ntohs(pnl.rdport); return 0; #else (void)conn; (void)req; log_warn(LD_BUG, "Called connection_ap_get_original_destination, but no " "transparent proxy method was configured."); return -1; #endif } /** connection_edge_process_inbuf() found a conn in state * socks_wait. See if conn->inbuf has the right bytes to proceed with * the socks handshake. * * If the handshake is complete, send it to * connection_ap_handshake_rewrite_and_attach(). * * Return -1 if an unexpected error with conn occurs (and mark it for close), * else return 0. */ static int connection_ap_handshake_process_socks(entry_connection_t *conn) { socks_request_t *socks; int sockshere; const or_options_t *options = get_options(); int had_reply = 0; connection_t *base_conn = ENTRY_TO_CONN(conn); tor_assert(conn); tor_assert(base_conn->type == CONN_TYPE_AP); tor_assert(base_conn->state == AP_CONN_STATE_SOCKS_WAIT); tor_assert(conn->socks_request); socks = conn->socks_request; log_debug(LD_APP,"entered."); IF_HAS_BUFFEREVENT(base_conn, { struct evbuffer *input = bufferevent_get_input(base_conn->bufev); sockshere = fetch_from_evbuffer_socks(input, socks, options->TestSocks, options->SafeSocks); }) ELSE_IF_NO_BUFFEREVENT { sockshere = fetch_from_buf_socks(base_conn->inbuf, socks, options->TestSocks, options->SafeSocks); }; if (socks->replylen) { had_reply = 1; connection_write_to_buf((const char*)socks->reply, socks->replylen, base_conn); socks->replylen = 0; if (sockshere == -1) { /* An invalid request just got a reply, no additional * one is necessary. */ socks->has_finished = 1; } } if (sockshere == 0) { log_debug(LD_APP,"socks handshake not all here yet."); return 0; } else if (sockshere == -1) { if (!had_reply) { log_warn(LD_APP,"Fetching socks handshake failed. Closing."); connection_ap_handshake_socks_reply(conn, NULL, 0, END_STREAM_REASON_SOCKSPROTOCOL); } connection_mark_unattached_ap(conn, END_STREAM_REASON_SOCKSPROTOCOL | END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); return -1; } /* else socks handshake is done, continue processing */ if (SOCKS_COMMAND_IS_CONNECT(socks->command)) control_event_stream_status(conn, STREAM_EVENT_NEW, 0); else control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE, 0); return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } /** connection_init_accepted_conn() found a new trans AP conn. * Get the original destination and send it to * connection_ap_handshake_rewrite_and_attach(). * * Return -1 if an unexpected error with conn (and it should be marked * for close), else return 0. */ int connection_ap_process_transparent(entry_connection_t *conn) { socks_request_t *socks; tor_assert(conn); tor_assert(conn->socks_request); socks = conn->socks_request; /* pretend that a socks handshake completed so we don't try to * send a socks reply down a transparent conn */ socks->command = SOCKS_COMMAND_CONNECT; socks->has_finished = 1; log_debug(LD_APP,"entered."); if (connection_ap_get_original_destination(conn, socks) < 0) { log_warn(LD_APP,"Fetching original destination failed. Closing."); connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_FETCH_ORIG_DEST); return -1; } /* we have the original destination */ control_event_stream_status(conn, STREAM_EVENT_NEW, 0); return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } /** connection_edge_process_inbuf() found a conn in state natd_wait. See if * conn-\>inbuf has the right bytes to proceed. See FreeBSD's libalias(3) and * ProxyEncodeTcpStream() in src/lib/libalias/alias_proxy.c for the encoding * form of the original destination. * * If the original destination is complete, send it to * connection_ap_handshake_rewrite_and_attach(). * * Return -1 if an unexpected error with conn (and it should be marked * for close), else return 0. */ static int connection_ap_process_natd(entry_connection_t *conn) { char tmp_buf[36], *tbuf, *daddr; size_t tlen = 30; int err, port_ok; socks_request_t *socks; tor_assert(conn); tor_assert(ENTRY_TO_CONN(conn)->state == AP_CONN_STATE_NATD_WAIT); tor_assert(conn->socks_request); socks = conn->socks_request; log_debug(LD_APP,"entered."); /* look for LF-terminated "[DEST ip_addr port]" * where ip_addr is a dotted-quad and port is in string form */ err = connection_fetch_from_buf_line(ENTRY_TO_CONN(conn), tmp_buf, &tlen); if (err == 0) return 0; if (err < 0) { log_warn(LD_APP,"NATD handshake failed (DEST too long). Closing"); connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); return -1; } if (strcmpstart(tmp_buf, "[DEST ")) { log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client " "said: %s", escaped(tmp_buf)); connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); return -1; } daddr = tbuf = &tmp_buf[0] + 6; /* after end of "[DEST " */ if (!(tbuf = strchr(tbuf, ' '))) { log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client " "said: %s", escaped(tmp_buf)); connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); return -1; } *tbuf++ = '\0'; /* pretend that a socks handshake completed so we don't try to * send a socks reply down a natd conn */ strlcpy(socks->address, daddr, sizeof(socks->address)); socks->port = (uint16_t) tor_parse_long(tbuf, 10, 1, 65535, &port_ok, &daddr); if (!port_ok) { log_warn(LD_APP,"NATD handshake failed; port %s is ill-formed or out " "of range.", escaped(tbuf)); connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); return -1; } socks->command = SOCKS_COMMAND_CONNECT; socks->has_finished = 1; control_event_stream_status(conn, STREAM_EVENT_NEW, 0); ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CIRCUIT_WAIT; return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } /** Iterate over the two bytes of stream_id until we get one that is not * already in use; return it. Return 0 if can't get a unique stream_id. */ streamid_t get_unique_stream_id_by_circ(origin_circuit_t *circ) { edge_connection_t *tmpconn; streamid_t test_stream_id; uint32_t attempts=0; again: test_stream_id = circ->next_stream_id++; if (++attempts > 1<<16) { /* Make sure we don't loop forever if all stream_id's are used. */ log_warn(LD_APP,"No unused stream IDs. Failing."); return 0; } if (test_stream_id == 0) goto again; for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) if (tmpconn->stream_id == test_stream_id) goto again; return test_stream_id; } /** Return true iff conn is linked to a circuit and configured to use * an exit that supports optimistic data. */ static int connection_ap_supports_optimistic_data(const entry_connection_t *conn) { const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); /* We can only send optimistic data if we're connected to an open general circuit. */ if (edge_conn->on_circuit == NULL || edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN || edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL) return 0; return conn->may_use_optimistic_data; } /** Return a bitmask of BEGIN_FLAG_* flags that we should transmit in the * RELAY_BEGIN cell for ap_conn. */ static uint32_t connection_ap_get_begincell_flags(entry_connection_t *ap_conn) { edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); const node_t *exitnode = NULL; const crypt_path_t *cpath_layer = edge_conn->cpath_layer; uint32_t flags = 0; /* No flags for begindir */ if (ap_conn->use_begindir) return 0; /* No flags for hidden services. */ if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL) return 0; /* If only IPv4 is supported, no flags */ if (ap_conn->ipv4_traffic_ok && !ap_conn->ipv6_traffic_ok) return 0; if (! cpath_layer || ! cpath_layer->extend_info) return 0; if (!ap_conn->ipv4_traffic_ok) flags |= BEGIN_FLAG_IPV4_NOT_OK; exitnode = node_get_by_id(cpath_layer->extend_info->identity_digest); if (ap_conn->ipv6_traffic_ok && exitnode) { tor_addr_t a; tor_addr_make_null(&a, AF_INET6); if (compare_tor_addr_to_node_policy(&a, ap_conn->socks_request->port, exitnode) != ADDR_POLICY_REJECTED) { /* Only say "IPv6 OK" if the exit node supports IPv6. Otherwise there's * no point. */ flags |= BEGIN_FLAG_IPV6_OK; } } if (flags == BEGIN_FLAG_IPV6_OK) { /* When IPv4 and IPv6 are both allowed, consider whether to say we * prefer IPv6. Otherwise there's no point in declaring a preference */ if (ap_conn->prefer_ipv6_traffic) flags |= BEGIN_FLAG_IPV6_PREFERRED; } if (flags == BEGIN_FLAG_IPV4_NOT_OK) { log_warn(LD_EDGE, "I'm about to ask a node for a connection that I " "am telling it to fulfil with neither IPv4 nor IPv6. That's " "not going to work. Did you perhaps ask for an IPv6 address " "on an IPv4Only port, or vice versa?"); } return flags; } /** Write a relay begin cell, using destaddr and destport from ap_conn's * socks_request field, and send it down circ. * * If ap_conn is broken, mark it for close and return -1. Else return 0. */ int connection_ap_handshake_send_begin(entry_connection_t *ap_conn) { char payload[CELL_PAYLOAD_SIZE]; int payload_len; int begin_type; origin_circuit_t *circ; edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); connection_t *base_conn = TO_CONN(edge_conn); tor_assert(edge_conn->on_circuit); circ = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit); tor_assert(base_conn->type == CONN_TYPE_AP); tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); tor_assert(SOCKS_COMMAND_IS_CONNECT(ap_conn->socks_request->command)); edge_conn->stream_id = get_unique_stream_id_by_circ(circ); if (edge_conn->stream_id==0) { /* XXXX024 Instead of closing this stream, we should make it get * retried on another circuit. */ connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); /* Mark this circuit "unusable for new streams". */ mark_circuit_unusable_for_new_conns(circ); return -1; } /* Set up begin cell flags. */ edge_conn->begincell_flags = connection_ap_get_begincell_flags(ap_conn); tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL) ? ap_conn->socks_request->address : "", ap_conn->socks_request->port); payload_len = (int)strlen(payload)+1; if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) { set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags)); payload_len += 4; } log_info(LD_APP, "Sending relay cell %d to begin stream %d.", (int)ap_conn->use_begindir, edge_conn->stream_id); begin_type = ap_conn->use_begindir ? RELAY_COMMAND_BEGIN_DIR : RELAY_COMMAND_BEGIN; if (begin_type == RELAY_COMMAND_BEGIN) { #ifndef NON_ANONYMOUS_MODE_ENABLED tor_assert(circ->build_state->onehop_tunnel == 0); #endif } if (connection_edge_send_command(edge_conn, begin_type, begin_type == RELAY_COMMAND_BEGIN ? payload : NULL, begin_type == RELAY_COMMAND_BEGIN ? payload_len : 0) < 0) return -1; /* circuit is closed, don't continue */ edge_conn->package_window = STREAMWINDOW_START; edge_conn->deliver_window = STREAMWINDOW_START; base_conn->state = AP_CONN_STATE_CONNECT_WAIT; log_info(LD_APP,"Address/port sent, ap socket "TOR_SOCKET_T_FORMAT ", n_circ_id %u", base_conn->s, (unsigned)circ->base_.n_circ_id); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0); /* If there's queued-up data, send it now */ if ((connection_get_inbuf_len(base_conn) || ap_conn->sending_optimistic_data) && connection_ap_supports_optimistic_data(ap_conn)) { log_info(LD_APP, "Sending up to %ld + %ld bytes of queued-up data", (long)connection_get_inbuf_len(base_conn), ap_conn->sending_optimistic_data ? (long)generic_buffer_len(ap_conn->sending_optimistic_data) : 0); if (connection_edge_package_raw_inbuf(edge_conn, 1, NULL) < 0) { connection_mark_for_close(base_conn); } } return 0; } /** Write a relay resolve cell, using destaddr and destport from ap_conn's * socks_request field, and send it down circ. * * If ap_conn is broken, mark it for close and return -1. Else return 0. */ int connection_ap_handshake_send_resolve(entry_connection_t *ap_conn) { int payload_len, command; const char *string_addr; char inaddr_buf[REVERSE_LOOKUP_NAME_BUF_LEN]; origin_circuit_t *circ; edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); connection_t *base_conn = TO_CONN(edge_conn); tor_assert(edge_conn->on_circuit); circ = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit); tor_assert(base_conn->type == CONN_TYPE_AP); tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL); command = ap_conn->socks_request->command; tor_assert(SOCKS_COMMAND_IS_RESOLVE(command)); edge_conn->stream_id = get_unique_stream_id_by_circ(circ); if (edge_conn->stream_id==0) { /* XXXX024 Instead of closing this stream, we should make it get * retried on another circuit. */ connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); /* Mark this circuit "unusable for new streams". */ mark_circuit_unusable_for_new_conns(circ); return -1; } if (command == SOCKS_COMMAND_RESOLVE) { string_addr = ap_conn->socks_request->address; payload_len = (int)strlen(string_addr)+1; } else { /* command == SOCKS_COMMAND_RESOLVE_PTR */ const char *a = ap_conn->socks_request->address; tor_addr_t addr; int r; /* We're doing a reverse lookup. The input could be an IP address, or * could be an .in-addr.arpa or .ip6.arpa address */ r = tor_addr_parse_PTR_name(&addr, a, AF_UNSPEC, 1); if (r <= 0) { log_warn(LD_APP, "Rejecting ill-formed reverse lookup of %s", safe_str_client(a)); connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); return -1; } r = tor_addr_to_PTR_name(inaddr_buf, sizeof(inaddr_buf), &addr); if (r < 0) { log_warn(LD_BUG, "Couldn't generate reverse lookup hostname of %s", safe_str_client(a)); connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); return -1; } string_addr = inaddr_buf; payload_len = (int)strlen(inaddr_buf)+1; tor_assert(payload_len <= (int)sizeof(inaddr_buf)); } log_debug(LD_APP, "Sending relay cell to begin stream %d.", edge_conn->stream_id); if (connection_edge_send_command(edge_conn, RELAY_COMMAND_RESOLVE, string_addr, payload_len) < 0) return -1; /* circuit is closed, don't continue */ if (!base_conn->address) { /* This might be unnecessary. XXXX */ base_conn->address = tor_dup_addr(&base_conn->addr); } base_conn->state = AP_CONN_STATE_RESOLVE_WAIT; log_info(LD_APP,"Address sent for resolve, ap socket "TOR_SOCKET_T_FORMAT ", n_circ_id %u", base_conn->s, (unsigned)circ->base_.n_circ_id); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0); return 0; } /** Make an AP connection_t linked to the connection_t partner. make a * new linked connection pair, and attach one side to the conn, connection_add * it, initialize it to circuit_wait, and call * connection_ap_handshake_attach_circuit(conn) on it. * * Return the newly created end of the linked connection pair, or -1 if error. */ entry_connection_t * connection_ap_make_link(connection_t *partner, char *address, uint16_t port, const char *digest, int session_group, int isolation_flags, int use_begindir, int want_onehop) { entry_connection_t *conn; connection_t *base_conn; log_info(LD_APP,"Making internal %s tunnel to %s:%d ...", want_onehop ? "direct" : "anonymized", safe_str_client(address), port); conn = entry_connection_new(CONN_TYPE_AP, tor_addr_family(&partner->addr)); base_conn = ENTRY_TO_CONN(conn); base_conn->linked = 1; /* so that we can add it safely below. */ /* populate conn->socks_request */ /* leave version at zero, so the socks_reply is empty */ conn->socks_request->socks_version = 0; conn->socks_request->has_finished = 0; /* waiting for 'connected' */ strlcpy(conn->socks_request->address, address, sizeof(conn->socks_request->address)); conn->socks_request->port = port; conn->socks_request->command = SOCKS_COMMAND_CONNECT; conn->want_onehop = want_onehop; conn->use_begindir = use_begindir; if (use_begindir) { conn->chosen_exit_name = tor_malloc(HEX_DIGEST_LEN+2); conn->chosen_exit_name[0] = '$'; tor_assert(digest); base16_encode(conn->chosen_exit_name+1,HEX_DIGEST_LEN+1, digest, DIGEST_LEN); } /* Populate isolation fields. */ conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER; conn->original_dest_address = tor_strdup(address); conn->session_group = session_group; conn->isolation_flags = isolation_flags; base_conn->address = tor_strdup("(Tor_internal)"); tor_addr_make_unspec(&base_conn->addr); base_conn->port = 0; connection_link_connections(partner, base_conn); if (connection_add(base_conn) < 0) { /* no space, forget it */ connection_free(base_conn); return NULL; } base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; control_event_stream_status(conn, STREAM_EVENT_NEW, 0); /* attaching to a dirty circuit is fine */ if (connection_ap_handshake_attach_circuit(conn) < 0) { if (!base_conn->marked_for_close) connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); return NULL; } log_info(LD_APP,"... application connection created and linked."); return conn; } /** Notify any interested controller connections about a new hostname resolve * or resolve error. Takes the same arguments as does * connection_ap_handshake_socks_resolved(). */ static void tell_controller_about_resolved_result(entry_connection_t *conn, int answer_type, size_t answer_len, const char *answer, int ttl, time_t expires) { expires = time(NULL) + ttl; if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) { char *cp = tor_dup_ip(ntohl(get_uint32(answer))); control_event_address_mapped(conn->socks_request->address, cp, expires, NULL, 0); tor_free(cp); } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { char *cp = tor_strndup(answer, answer_len); control_event_address_mapped(conn->socks_request->address, cp, expires, NULL, 0); tor_free(cp); } else { control_event_address_mapped(conn->socks_request->address, "", time(NULL)+ttl, "error=yes", 0); } } /** * As connection_ap_handshake_socks_resolved, but take a tor_addr_t to send * as the answer. */ static void connection_ap_handshake_socks_resolved_addr(entry_connection_t *conn, const tor_addr_t *answer, int ttl, time_t expires) { if (tor_addr_family(answer) == AF_INET) { uint32_t a = tor_addr_to_ipv4n(answer); /* network order */ connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4, (uint8_t*)&a, ttl, expires); } else if (tor_addr_family(answer) == AF_INET6) { const uint8_t *a = tor_addr_to_in6_addr8(answer); connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV6,16, a, ttl, expires); } else { log_warn(LD_BUG, "Got called with address of unexpected family %d", tor_addr_family(answer)); connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR,0,NULL,-1,-1); } } /** Send an answer to an AP connection that has requested a DNS lookup via * SOCKS. The type should be one of RESOLVED_TYPE_(IPV4|IPV6|HOSTNAME) or -1 * for unreachable; the answer should be in the format specified in the socks * extensions document. ttl is the ttl for the answer, or -1 on * certain errors or for values that didn't come via DNS. expires is * a time when the answer expires, or -1 or TIME_MAX if there's a good TTL. **/ /* XXXX the use of the ttl and expires fields is nutty. Let's make this * interface and those that use it less ugly. */ void connection_ap_handshake_socks_resolved(entry_connection_t *conn, int answer_type, size_t answer_len, const uint8_t *answer, int ttl, time_t expires) { char buf[384]; size_t replylen; if (ttl >= 0) { if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { tor_addr_t a; tor_addr_from_ipv4n(&a, get_uint32(answer)); if (! tor_addr_is_null(&a)) { client_dns_set_addressmap(conn, conn->socks_request->address, &a, conn->chosen_exit_name, ttl); } } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) { tor_addr_t a; tor_addr_from_ipv6_bytes(&a, (char*)answer); if (! tor_addr_is_null(&a)) { client_dns_set_addressmap(conn, conn->socks_request->address, &a, conn->chosen_exit_name, ttl); } } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { char *cp = tor_strndup((char*)answer, answer_len); client_dns_set_reverse_addressmap(conn, conn->socks_request->address, cp, conn->chosen_exit_name, ttl); tor_free(cp); } } if (ENTRY_TO_EDGE_CONN(conn)->is_dns_request) { if (conn->dns_server_request) { /* We had a request on our DNS port: answer it. */ dnsserv_resolved(conn, answer_type, answer_len, (char*)answer, ttl); conn->socks_request->has_finished = 1; return; } else { /* This must be a request from the controller. Since answers to those * requests are not cached, they do not generate an ADDRMAP event on * their own. */ tell_controller_about_resolved_result(conn, answer_type, answer_len, (char*)answer, ttl, expires); conn->socks_request->has_finished = 1; return; } /* We shouldn't need to free conn here; it gets marked by the caller. */ } if (conn->socks_request->socks_version == 4) { buf[0] = 0x00; /* version */ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { buf[1] = SOCKS4_GRANTED; set_uint16(buf+2, 0); memcpy(buf+4, answer, 4); /* address */ replylen = SOCKS4_NETWORK_LEN; } else { /* "error" */ buf[1] = SOCKS4_REJECT; memset(buf+2, 0, 6); replylen = SOCKS4_NETWORK_LEN; } } else if (conn->socks_request->socks_version == 5) { /* SOCKS5 */ buf[0] = 0x05; /* version */ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { buf[1] = SOCKS5_SUCCEEDED; buf[2] = 0; /* reserved */ buf[3] = 0x01; /* IPv4 address type */ memcpy(buf+4, answer, 4); /* address */ set_uint16(buf+8, 0); /* port == 0. */ replylen = 10; } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) { buf[1] = SOCKS5_SUCCEEDED; buf[2] = 0; /* reserved */ buf[3] = 0x04; /* IPv6 address type */ memcpy(buf+4, answer, 16); /* address */ set_uint16(buf+20, 0); /* port == 0. */ replylen = 22; } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { buf[1] = SOCKS5_SUCCEEDED; buf[2] = 0; /* reserved */ buf[3] = 0x03; /* Domainname address type */ buf[4] = (char)answer_len; memcpy(buf+5, answer, answer_len); /* address */ set_uint16(buf+5+answer_len, 0); /* port == 0. */ replylen = 5+answer_len+2; } else { buf[1] = SOCKS5_HOST_UNREACHABLE; memset(buf+2, 0, 8); replylen = 10; } } else { /* no socks version info; don't send anything back */ return; } connection_ap_handshake_socks_reply(conn, buf, replylen, (answer_type == RESOLVED_TYPE_IPV4 || answer_type == RESOLVED_TYPE_IPV6 || answer_type == RESOLVED_TYPE_HOSTNAME) ? 0 : END_STREAM_REASON_RESOLVEFAILED); } /** Send a socks reply to stream conn, using the appropriate * socks version, etc, and mark conn as completed with SOCKS * handshaking. * * If reply is defined, then write replylen bytes of it to conn * and return, else reply based on endreason (one of * END_STREAM_REASON_*). If reply is undefined, endreason can't * be 0 or REASON_DONE. Send endreason to the controller, if appropriate. */ void connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, size_t replylen, int endreason) { char buf[256]; socks5_reply_status_t status = stream_end_reason_to_socks5_response(endreason); tor_assert(conn->socks_request); /* make sure it's an AP stream */ if (!SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) { control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED, endreason); } /* Flag this stream's circuit as having completed a stream successfully * (for path bias) */ if (status == SOCKS5_SUCCEEDED || endreason == END_STREAM_REASON_RESOLVEFAILED || endreason == END_STREAM_REASON_CONNECTREFUSED || endreason == END_STREAM_REASON_CONNRESET || endreason == END_STREAM_REASON_NOROUTE || endreason == END_STREAM_REASON_RESOURCELIMIT) { if (!conn->edge_.on_circuit || !CIRCUIT_IS_ORIGIN(conn->edge_.on_circuit)) { // DNS remaps can trigger this. So can failed hidden service // lookups. log_info(LD_BUG, "No origin circuit for successful SOCKS stream "U64_FORMAT ". Reason: %d", U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier), endreason); } else { // XXX: Hrmm. It looks like optimistic data can't go through this // codepath, but someone should probably test it and make sure. // We don't want to mark optimistically opened streams as successful. pathbias_mark_use_success(TO_ORIGIN_CIRCUIT(conn->edge_.on_circuit)); } } if (conn->socks_request->has_finished) { log_warn(LD_BUG, "(Harmless.) duplicate calls to " "connection_ap_handshake_socks_reply."); return; } if (replylen) { /* we already have a reply in mind */ connection_write_to_buf(reply, replylen, ENTRY_TO_CONN(conn)); conn->socks_request->has_finished = 1; return; } if (conn->socks_request->socks_version == 4) { memset(buf,0,SOCKS4_NETWORK_LEN); buf[1] = (status==SOCKS5_SUCCEEDED ? SOCKS4_GRANTED : SOCKS4_REJECT); /* leave version, destport, destip zero */ connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, ENTRY_TO_CONN(conn)); } else if (conn->socks_request->socks_version == 5) { buf[0] = 5; /* version 5 */ buf[1] = (char)status; buf[2] = 0; buf[3] = 1; /* ipv4 addr */ memset(buf+4,0,6); /* Set external addr/port to 0. The spec doesn't seem to say what to do here. -RD */ connection_write_to_buf(buf,10,ENTRY_TO_CONN(conn)); } /* If socks_version isn't 4 or 5, don't send anything. * This can happen in the case of AP bridges. */ conn->socks_request->has_finished = 1; return; } /** Read a RELAY_BEGIN or RELAY_BEGINDIR cell from cell, decode it, and * place the result in bcell. On success return 0; on failure return * <0 and set *end_reason_out to the end reason we should send back to * the client. * * Return -1 in the case where want to send a RELAY_END cell, and < -1 when * we don't. **/ /* static */ int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, uint8_t *end_reason_out) { relay_header_t rh; const uint8_t *body, *nul; memset(bcell, 0, sizeof(*bcell)); *end_reason_out = END_STREAM_REASON_MISC; relay_header_unpack(&rh, cell->payload); if (rh.length > RELAY_PAYLOAD_SIZE) { return -2; /*XXXX why not TORPROTOCOL? */ } bcell->stream_id = rh.stream_id; if (rh.command == RELAY_COMMAND_BEGIN_DIR) { bcell->is_begindir = 1; return 0; } else if (rh.command != RELAY_COMMAND_BEGIN) { log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command); *end_reason_out = END_STREAM_REASON_INTERNAL; return -1; } body = cell->payload + RELAY_HEADER_SIZE; nul = memchr(body, 0, rh.length); if (! nul) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay begin cell has no \\0. Closing."); *end_reason_out = END_STREAM_REASON_TORPROTOCOL; return -1; } if (tor_addr_port_split(LOG_PROTOCOL_WARN, (char*)(body), &bcell->address,&bcell->port)<0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Unable to parse addr:port in relay begin cell. Closing."); *end_reason_out = END_STREAM_REASON_TORPROTOCOL; return -1; } if (bcell->port == 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Missing port in relay begin cell. Closing."); tor_free(bcell->address); *end_reason_out = END_STREAM_REASON_TORPROTOCOL; return -1; } if (body + rh.length >= nul + 4) bcell->flags = ntohl(get_uint32(nul+1)); return 0; } /** A relay 'begin' or 'begin_dir' cell has arrived, and either we are * an exit hop for the circuit, or we are the origin and it is a * rendezvous begin. * * Launch a new exit connection and initialize things appropriately. * * If it's a rendezvous stream, call connection_exit_connect() on * it. * * For general streams, call dns_resolve() on it first, and only call * connection_exit_connect() if the dns answer is already known. * * Note that we don't call connection_add() on the new stream! We wait * for connection_exit_connect() to do that. * * Return -(some circuit end reason) if we want to tear down circ. * Else return 0. */ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { edge_connection_t *n_stream; relay_header_t rh; char *address = NULL; uint16_t port = 0; or_circuit_t *or_circ = NULL; const or_options_t *options = get_options(); begin_cell_t bcell; int r; uint8_t end_reason=0; assert_circuit_ok(circ); if (!CIRCUIT_IS_ORIGIN(circ)) or_circ = TO_OR_CIRCUIT(circ); relay_header_unpack(&rh, cell->payload); if (rh.length > RELAY_PAYLOAD_SIZE) return -1; /* Note: we have to use relay_send_command_from_edge here, not * connection_edge_end or connection_edge_send_command, since those require * that we have a stream connected to a circuit, and we don't connect to a * circuit until we have a pending/successful resolve. */ if (!server_mode(options) && circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay begin cell at non-server. Closing."); relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_EXITPOLICY, NULL); return 0; } r = begin_cell_parse(cell, &bcell, &end_reason); if (r < -1) { return -1; } else if (r == -1) { tor_free(bcell.address); relay_send_end_cell_from_edge(rh.stream_id, circ, end_reason, NULL); return 0; } if (! bcell.is_begindir) { /* Steal reference */ address = bcell.address; port = bcell.port; if (or_circ && or_circ->p_chan) { if (!options->AllowSingleHopExits && (or_circ->is_first_hop || (!connection_or_digest_is_known_relay( or_circ->p_chan->identity_digest) && should_refuse_unknown_exits(options)))) { /* Don't let clients use us as a single-hop proxy, unless the user * has explicitly allowed that in the config. It attracts attackers * and users who'd be better off with, well, single-hop proxies. */ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Attempt by %s to open a stream %s. Closing.", safe_str(channel_get_canonical_remote_descr(or_circ->p_chan)), or_circ->is_first_hop ? "on first hop of circuit" : "from unknown relay"); relay_send_end_cell_from_edge(rh.stream_id, circ, or_circ->is_first_hop ? END_STREAM_REASON_TORPROTOCOL : END_STREAM_REASON_MISC, NULL); tor_free(address); return 0; } } } else if (rh.command == RELAY_COMMAND_BEGIN_DIR) { if (!directory_permits_begindir_requests(options) || circ->purpose != CIRCUIT_PURPOSE_OR) { relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_NOTDIRECTORY, NULL); return 0; } /* Make sure to get the 'real' address of the previous hop: the * caller might want to know whether his IP address has changed, and * we might already have corrected base_.addr[ess] for the relay's * canonical IP address. */ if (or_circ && or_circ->p_chan) address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan)); else address = tor_strdup("127.0.0.1"); port = 1; /* XXXX This value is never actually used anywhere, and there * isn't "really" a connection here. But we * need to set it to something nonzero. */ } else { log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command); relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_INTERNAL, NULL); return 0; } if (! options->IPv6Exit) { /* I don't care if you prefer IPv6; I can't give you any. */ bcell.flags &= ~BEGIN_FLAG_IPV6_PREFERRED; /* If you don't want IPv4, I can't help. */ if (bcell.flags & BEGIN_FLAG_IPV4_NOT_OK) { tor_free(address); relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_EXITPOLICY, NULL); return 0; } } log_debug(LD_EXIT,"Creating new exit connection."); /* The 'AF_INET' here is temporary; we might need to change it later in * connection_exit_connect(). */ n_stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET); /* Remember the tunneled request ID in the new edge connection, so that * we can measure download times. */ n_stream->dirreq_id = circ->dirreq_id; n_stream->base_.purpose = EXIT_PURPOSE_CONNECT; n_stream->begincell_flags = bcell.flags; n_stream->stream_id = rh.stream_id; n_stream->base_.port = port; /* leave n_stream->s at -1, because it's not yet valid */ n_stream->package_window = STREAMWINDOW_START; n_stream->deliver_window = STREAMWINDOW_START; if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); log_info(LD_REND,"begin is for rendezvous. configuring stream."); n_stream->base_.address = tor_strdup("(rendezvous)"); n_stream->base_.state = EXIT_CONN_STATE_CONNECTING; n_stream->rend_data = rend_data_dup(origin_circ->rend_data); tor_assert(connection_edge_is_rendezvous_stream(n_stream)); assert_circuit_ok(circ); if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) { log_info(LD_REND,"Didn't find rendezvous service (port %d)", n_stream->base_.port); relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_EXITPOLICY, origin_circ->cpath->prev); connection_free(TO_CONN(n_stream)); tor_free(address); return 0; } assert_circuit_ok(circ); log_debug(LD_REND,"Finished assigning addr/port"); n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */ /* add it into the linked list of p_streams on this circuit */ n_stream->next_stream = origin_circ->p_streams; n_stream->on_circuit = circ; origin_circ->p_streams = n_stream; assert_circuit_ok(circ); connection_exit_connect(n_stream); /* For path bias: This circuit was used successfully */ pathbias_mark_use_success(origin_circ); tor_free(address); return 0; } tor_strlower(address); n_stream->base_.address = address; n_stream->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; /* default to failed, change in dns_resolve if it turns out not to fail */ if (we_are_hibernating()) { relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_HIBERNATING, NULL); connection_free(TO_CONN(n_stream)); return 0; } n_stream->on_circuit = circ; if (rh.command == RELAY_COMMAND_BEGIN_DIR) { tor_addr_t tmp_addr; tor_assert(or_circ); if (or_circ->p_chan && channel_get_addr_if_possible(or_circ->p_chan, &tmp_addr)) { tor_addr_copy(&n_stream->base_.addr, &tmp_addr); } return connection_exit_connect_dir(n_stream); } log_debug(LD_EXIT,"about to start the dns_resolve()."); /* send it off to the gethostbyname farm */ switch (dns_resolve(n_stream)) { case 1: /* resolve worked; now n_stream is attached to circ. */ assert_circuit_ok(circ); log_debug(LD_EXIT,"about to call connection_exit_connect()."); connection_exit_connect(n_stream); return 0; case -1: /* resolve failed */ relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_RESOLVEFAILED, NULL); /* n_stream got freed. don't touch it. */ break; case 0: /* resolve added to pending list */ assert_circuit_ok(circ); break; } return 0; } /** * Called when we receive a RELAY_COMMAND_RESOLVE cell 'cell' along the * circuit circ; * begin resolving the hostname, and (eventually) reply with a RESOLVED cell. */ int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) { edge_connection_t *dummy_conn; relay_header_t rh; assert_circuit_ok(TO_CIRCUIT(circ)); relay_header_unpack(&rh, cell->payload); if (rh.length > RELAY_PAYLOAD_SIZE) return -1; /* This 'dummy_conn' only exists to remember the stream ID * associated with the resolve request; and to make the * implementation of dns.c more uniform. (We really only need to * remember the circuit, the stream ID, and the hostname to be * resolved; but if we didn't store them in a connection like this, * the housekeeping in dns.c would get way more complicated.) */ dummy_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET); dummy_conn->stream_id = rh.stream_id; dummy_conn->base_.address = tor_strndup( (char*)cell->payload+RELAY_HEADER_SIZE, rh.length); dummy_conn->base_.port = 0; dummy_conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; dummy_conn->base_.purpose = EXIT_PURPOSE_RESOLVE; dummy_conn->on_circuit = TO_CIRCUIT(circ); /* send it off to the gethostbyname farm */ switch (dns_resolve(dummy_conn)) { case -1: /* Impossible to resolve; a resolved cell was sent. */ /* Connection freed; don't touch it. */ return 0; case 1: /* The result was cached; a resolved cell was sent. */ if (!dummy_conn->base_.marked_for_close) connection_free(TO_CONN(dummy_conn)); return 0; case 0: /* resolve added to pending list */ assert_circuit_ok(TO_CIRCUIT(circ)); break; } return 0; } /** Connect to conn's specified addr and port. If it worked, conn * has now been added to the connection_array. * * Send back a connected cell. Include the resolved IP of the destination * address, but only if it's a general exit stream. (Rendezvous * streams must not reveal what IP they connected to.) */ void connection_exit_connect(edge_connection_t *edge_conn) { const tor_addr_t *addr; uint16_t port; connection_t *conn = TO_CONN(edge_conn); int socket_error = 0; if ( (!connection_edge_is_rendezvous_stream(edge_conn) && router_compare_to_my_exit_policy(&edge_conn->base_.addr, edge_conn->base_.port)) || (tor_addr_family(&conn->addr) == AF_INET6 && ! get_options()->IPv6Exit)) { log_info(LD_EXIT,"%s:%d failed exit policy. Closing.", escaped_safe_str_client(conn->address), conn->port); connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); connection_free(conn); return; } addr = &conn->addr; port = conn->port; if (tor_addr_family(addr) == AF_INET6) conn->socket_family = AF_INET6; log_debug(LD_EXIT,"about to try connecting"); switch (connection_connect(conn, conn->address, addr, port, &socket_error)) { case -1: { int reason = errno_to_stream_end_reason(socket_error); connection_edge_end(edge_conn, reason); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); connection_free(conn); return; } case 0: conn->state = EXIT_CONN_STATE_CONNECTING; connection_watch_events(conn, READ_EVENT | WRITE_EVENT); /* writable indicates finish; * readable/error indicates broken link in windows-land. */ return; /* case 1: fall through */ } conn->state = EXIT_CONN_STATE_OPEN; if (connection_get_outbuf_len(conn)) { /* in case there are any queued data cells, from e.g. optimistic data */ IF_HAS_NO_BUFFEREVENT(conn) connection_watch_events(conn, READ_EVENT|WRITE_EVENT); } else { IF_HAS_NO_BUFFEREVENT(conn) connection_watch_events(conn, READ_EVENT); } /* also, deliver a 'connected' cell back through the circuit. */ if (connection_edge_is_rendezvous_stream(edge_conn)) { /* rendezvous stream */ /* don't send an address back! */ connection_edge_send_command(edge_conn, RELAY_COMMAND_CONNECTED, NULL, 0); } else { /* normal stream */ uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN]; int connected_payload_len = connected_cell_format_payload(connected_payload, &conn->addr, edge_conn->address_ttl); if (connected_payload_len < 0) { connection_edge_end(edge_conn, END_STREAM_REASON_INTERNAL); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); connection_free(conn); return; } connection_edge_send_command(edge_conn, RELAY_COMMAND_CONNECTED, (char*)connected_payload, connected_payload_len); } } /** Given an exit conn that should attach to us as a directory server, open a * bridge connection with a linked connection pair, create a new directory * conn, and join them together. Return 0 on success (or if there was an * error we could send back an end cell for). Return -(some circuit end * reason) if the circuit needs to be torn down. Either connects * exitconn, frees it, or marks it, as appropriate. */ static int connection_exit_connect_dir(edge_connection_t *exitconn) { dir_connection_t *dirconn = NULL; or_circuit_t *circ = TO_OR_CIRCUIT(exitconn->on_circuit); log_info(LD_EXIT, "Opening local connection for anonymized directory exit"); exitconn->base_.state = EXIT_CONN_STATE_OPEN; dirconn = dir_connection_new(tor_addr_family(&exitconn->base_.addr)); tor_addr_copy(&dirconn->base_.addr, &exitconn->base_.addr); dirconn->base_.port = 0; dirconn->base_.address = tor_strdup(exitconn->base_.address); dirconn->base_.type = CONN_TYPE_DIR; dirconn->base_.purpose = DIR_PURPOSE_SERVER; dirconn->base_.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT; /* Note that the new dir conn belongs to the same tunneled request as * the edge conn, so that we can measure download times. */ dirconn->dirreq_id = exitconn->dirreq_id; connection_link_connections(TO_CONN(dirconn), TO_CONN(exitconn)); if (connection_add(TO_CONN(exitconn))<0) { connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT); connection_free(TO_CONN(exitconn)); connection_free(TO_CONN(dirconn)); return 0; } /* link exitconn to circ, now that we know we can use it. */ exitconn->next_stream = circ->n_streams; circ->n_streams = exitconn; if (connection_add(TO_CONN(dirconn))<0) { connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT); connection_close_immediate(TO_CONN(exitconn)); connection_mark_for_close(TO_CONN(exitconn)); connection_free(TO_CONN(dirconn)); return 0; } connection_start_reading(TO_CONN(dirconn)); connection_start_reading(TO_CONN(exitconn)); if (connection_edge_send_command(exitconn, RELAY_COMMAND_CONNECTED, NULL, 0) < 0) { connection_mark_for_close(TO_CONN(exitconn)); connection_mark_for_close(TO_CONN(dirconn)); return 0; } return 0; } /** Return 1 if conn is a rendezvous stream, or 0 if * it is a general stream. */ int connection_edge_is_rendezvous_stream(edge_connection_t *conn) { tor_assert(conn); if (conn->rend_data) return 1; return 0; } /** Return 1 if router exit is likely to allow stream conn * to exit from it, or 0 if it probably will not allow it. * (We might be uncertain if conn's destination address has not yet been * resolved.) */ int connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit) { const or_options_t *options = get_options(); tor_assert(conn); tor_assert(conn->socks_request); tor_assert(exit); /* If a particular exit node has been requested for the new connection, * make sure the exit node of the existing circuit matches exactly. */ if (conn->chosen_exit_name) { const node_t *chosen_exit = node_get_by_nickname(conn->chosen_exit_name, 1); if (!chosen_exit || tor_memneq(chosen_exit->identity, exit->identity, DIGEST_LEN)) { /* doesn't match */ // log_debug(LD_APP,"Requested node '%s', considering node '%s'. No.", // conn->chosen_exit_name, exit->nickname); return 0; } } if (conn->use_begindir) { /* Internal directory fetches do not count as exiting. */ return 1; } if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { tor_addr_t addr, *addrp = NULL; addr_policy_result_t r; if (0 == tor_addr_parse(&addr, conn->socks_request->address)) { addrp = &addr; } else if (!conn->ipv4_traffic_ok && conn->ipv6_traffic_ok) { tor_addr_make_null(&addr, AF_INET6); addrp = &addr; } else if (conn->ipv4_traffic_ok && !conn->ipv6_traffic_ok) { tor_addr_make_null(&addr, AF_INET); addrp = &addr; } r = compare_tor_addr_to_node_policy(addrp, conn->socks_request->port,exit); if (r == ADDR_POLICY_REJECTED) return 0; /* We know the address, and the exit policy rejects it. */ if (r == ADDR_POLICY_PROBABLY_REJECTED && !conn->chosen_exit_name) return 0; /* We don't know the addr, but the exit policy rejects most * addresses with this port. Since the user didn't ask for * this node, err on the side of caution. */ } else if (SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) { /* Don't send DNS requests to non-exit servers by default. */ if (!conn->chosen_exit_name && node_exit_policy_rejects_all(exit)) return 0; } if (routerset_contains_node(options->ExcludeExitNodesUnion_, exit)) { /* Not a suitable exit. Refuse it. */ return 0; } return 1; } /** If address is of the form "y.onion" with a well-formed handle y: * Put a NUL after y, lower-case it, and return ONION_HOSTNAME. * * If address is of the form "x.y.onion" with a well-formed handle x: * Drop "x.", put a NUL after y, lower-case it, and return ONION_HOSTNAME. * * If address is of the form "y.onion" with a badly-formed handle y: * Return BAD_HOSTNAME and log a message. * * If address is of the form "y.exit": * Put a NUL after y and return EXIT_HOSTNAME. * * Otherwise: * Return NORMAL_HOSTNAME and change nothing. */ hostname_type_t parse_extended_hostname(char *address) { char *s; char *q; char query[REND_SERVICE_ID_LEN_BASE32+1]; s = strrchr(address,'.'); if (!s) return NORMAL_HOSTNAME; /* no dot, thus normal */ if (!strcmp(s+1,"exit")) { *s = 0; /* NUL-terminate it */ return EXIT_HOSTNAME; /* .exit */ } if (strcmp(s+1,"onion")) return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */ /* so it is .onion */ *s = 0; /* NUL-terminate it */ /* locate a 'sub-domain' component, in order to remove it */ q = strrchr(address, '.'); if (q == address) { goto failed; /* reject sub-domain, as DNS does */ } q = (NULL == q) ? address : q + 1; if (strlcpy(query, q, REND_SERVICE_ID_LEN_BASE32+1) >= REND_SERVICE_ID_LEN_BASE32+1) goto failed; if (q != address) { memmove(address, q, strlen(q) + 1 /* also get \0 */); } if (rend_valid_service_id(query)) { return ONION_HOSTNAME; /* success */ } failed: /* otherwise, return to previous state and return 0 */ *s = '.'; log_warn(LD_APP, "Invalid onion hostname %s; rejecting", safe_str_client(address)); return BAD_HOSTNAME; } /** Return true iff the (possibly NULL) alen-byte chunk of memory at * a is equal to the (possibly NULL) blen-byte chunk of memory * at b. */ static int memeq_opt(const char *a, size_t alen, const char *b, size_t blen) { if (a == NULL) { return (b == NULL); } else if (b == NULL) { return 0; } else if (alen != blen) { return 0; } else { return tor_memeq(a, b, alen); } } /** * Return true iff none of the isolation flags and fields in conn * should prevent it from being attached to circ. */ int connection_edge_compatible_with_circuit(const entry_connection_t *conn, const origin_circuit_t *circ) { const uint8_t iso = conn->isolation_flags; const socks_request_t *sr = conn->socks_request; /* If circ has never been used for an isolated connection, we can * totally use it for this one. */ if (!circ->isolation_values_set) return 1; /* If circ has been used for connections having more than one value * for some field f, it will have the corresponding bit set in * isolation_flags_mixed. If isolation_flags_mixed has any bits * in common with iso, then conn must be isolated from at least * one stream that has been attached to circ. */ if ((iso & circ->isolation_flags_mixed) != 0) { /* For at least one field where conn is isolated, the circuit * already has mixed streams. */ return 0; } if (! conn->original_dest_address) { log_warn(LD_BUG, "Reached connection_edge_compatible_with_circuit without " "having set conn->original_dest_address"); ((entry_connection_t*)conn)->original_dest_address = tor_strdup(conn->socks_request->address); } if ((iso & ISO_STREAM) && (circ->associated_isolated_stream_global_id != ENTRY_TO_CONN(conn)->global_identifier)) return 0; if ((iso & ISO_DESTPORT) && conn->socks_request->port != circ->dest_port) return 0; if ((iso & ISO_DESTADDR) && strcasecmp(conn->original_dest_address, circ->dest_address)) return 0; if ((iso & ISO_SOCKSAUTH) && (! memeq_opt(sr->username, sr->usernamelen, circ->socks_username, circ->socks_username_len) || ! memeq_opt(sr->password, sr->passwordlen, circ->socks_password, circ->socks_password_len))) return 0; if ((iso & ISO_CLIENTPROTO) && (conn->socks_request->listener_type != circ->client_proto_type || conn->socks_request->socks_version != circ->client_proto_socksver)) return 0; if ((iso & ISO_CLIENTADDR) && !tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr)) return 0; if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group) return 0; if ((iso & ISO_NYM_EPOCH) && conn->nym_epoch != circ->nym_epoch) return 0; return 1; } /** * If dry_run is false, update circ's isolation flags and fields * to reflect having had conn attached to it, and return 0. Otherwise, * if dry_run is true, then make no changes to circ, and return * a bitfield of isolation flags that we would have to set in * isolation_flags_mixed to add conn to circ, or -1 if * circ has had no streams attached to it. */ int connection_edge_update_circuit_isolation(const entry_connection_t *conn, origin_circuit_t *circ, int dry_run) { const socks_request_t *sr = conn->socks_request; if (! conn->original_dest_address) { log_warn(LD_BUG, "Reached connection_update_circuit_isolation without " "having set conn->original_dest_address"); ((entry_connection_t*)conn)->original_dest_address = tor_strdup(conn->socks_request->address); } if (!circ->isolation_values_set) { if (dry_run) return -1; circ->associated_isolated_stream_global_id = ENTRY_TO_CONN(conn)->global_identifier; circ->dest_port = conn->socks_request->port; circ->dest_address = tor_strdup(conn->original_dest_address); circ->client_proto_type = conn->socks_request->listener_type; circ->client_proto_socksver = conn->socks_request->socks_version; tor_addr_copy(&circ->client_addr, &ENTRY_TO_CONN(conn)->addr); circ->session_group = conn->session_group; circ->nym_epoch = conn->nym_epoch; circ->socks_username = sr->username ? tor_memdup(sr->username, sr->usernamelen) : NULL; circ->socks_password = sr->password ? tor_memdup(sr->password, sr->passwordlen) : NULL; circ->socks_username_len = sr->usernamelen; circ->socks_password_len = sr->passwordlen; circ->isolation_values_set = 1; return 0; } else { uint8_t mixed = 0; if (conn->socks_request->port != circ->dest_port) mixed |= ISO_DESTPORT; if (strcasecmp(conn->original_dest_address, circ->dest_address)) mixed |= ISO_DESTADDR; if (!memeq_opt(sr->username, sr->usernamelen, circ->socks_username, circ->socks_username_len) || !memeq_opt(sr->password, sr->passwordlen, circ->socks_password, circ->socks_password_len)) mixed |= ISO_SOCKSAUTH; if ((conn->socks_request->listener_type != circ->client_proto_type || conn->socks_request->socks_version != circ->client_proto_socksver)) mixed |= ISO_CLIENTPROTO; if (!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr)) mixed |= ISO_CLIENTADDR; if (conn->session_group != circ->session_group) mixed |= ISO_SESSIONGRP; if (conn->nym_epoch != circ->nym_epoch) mixed |= ISO_NYM_EPOCH; if (dry_run) return mixed; if ((mixed & conn->isolation_flags) != 0) { log_warn(LD_BUG, "Updating a circuit with seemingly incompatible " "isolation flags."); } circ->isolation_flags_mixed |= mixed; return 0; } } /** * Clear the isolation settings on circ. * * This only works on an open circuit that has never had a stream attached to * it, and whose isolation settings are hypothetical. (We set hypothetical * isolation settings on circuits as we're launching them, so that we * know whether they can handle more streams or whether we need to launch * even more circuits. Once the circuit is open, if it turns out that * we no longer have any streams to attach to it, we clear the isolation flags * and data so that other streams can have a chance.) */ void circuit_clear_isolation(origin_circuit_t *circ) { if (circ->isolation_any_streams_attached) { log_warn(LD_BUG, "Tried to clear the isolation status of a dirty circuit"); return; } if (TO_CIRCUIT(circ)->state != CIRCUIT_STATE_OPEN) { log_warn(LD_BUG, "Tried to clear the isolation status of a non-open " "circuit"); return; } circ->isolation_values_set = 0; circ->isolation_flags_mixed = 0; circ->associated_isolated_stream_global_id = 0; circ->client_proto_type = 0; circ->client_proto_socksver = 0; circ->dest_port = 0; tor_addr_make_unspec(&circ->client_addr); tor_free(circ->dest_address); circ->session_group = -1; circ->nym_epoch = 0; if (circ->socks_username) { memwipe(circ->socks_username, 0x11, circ->socks_username_len); tor_free(circ->socks_username); } if (circ->socks_password) { memwipe(circ->socks_password, 0x05, circ->socks_password_len); tor_free(circ->socks_password); } circ->socks_username_len = circ->socks_password_len = 0; } tor-0.2.4.20/src/or/networkstatus.h0000644000175000017500000001447212166112777014021 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file networkstatus.h * \brief Header file for networkstatus.c. **/ #ifndef TOR_NETWORKSTATUS_H #define TOR_NETWORKSTATUS_H /** How old do we allow a v2 network-status to get before removing it * completely? */ #define MAX_NETWORKSTATUS_AGE (10*24*60*60) void networkstatus_reset_warnings(void); void networkstatus_reset_download_failures(void); int router_reload_v2_networkstatus(void); int router_reload_consensus_networkstatus(void); void routerstatus_free(routerstatus_t *rs); void networkstatus_v2_free(networkstatus_v2_t *ns); void networkstatus_vote_free(networkstatus_t *ns); networkstatus_voter_info_t *networkstatus_get_voter_by_id( networkstatus_t *vote, const char *identity); int networkstatus_check_consensus_signature(networkstatus_t *consensus, int warn); int networkstatus_check_document_signature(const networkstatus_t *consensus, document_signature_t *sig, const authority_cert_t *cert); char *networkstatus_get_cache_filename(const char *identity_digest); int router_set_networkstatus_v2(const char *s, time_t arrived_at, v2_networkstatus_source_t source, smartlist_t *requested_fingerprints); void networkstatus_v2_list_clean(time_t now); int compare_digest_to_routerstatus_entry(const void *_key, const void **_member); int compare_digest_to_vote_routerstatus_entry(const void *_key, const void **_member); const routerstatus_t *networkstatus_v2_find_entry(networkstatus_v2_t *ns, const char *digest); const routerstatus_t *networkstatus_vote_find_entry(networkstatus_t *ns, const char *digest); routerstatus_t *networkstatus_v2_find_mutable_entry(networkstatus_v2_t *ns, const char *digest); routerstatus_t *networkstatus_vote_find_mutable_entry(networkstatus_t *ns, const char *digest); int networkstatus_vote_find_entry_idx(networkstatus_t *ns, const char *digest, int *found_out); const smartlist_t *networkstatus_get_v2_list(void); download_status_t *router_get_dl_status_by_descriptor_digest(const char *d); const routerstatus_t *router_get_consensus_status_by_id(const char *digest); routerstatus_t *router_get_mutable_consensus_status_by_id( const char *digest); const routerstatus_t *router_get_consensus_status_by_descriptor_digest( networkstatus_t *consensus, const char *digest); routerstatus_t *router_get_mutable_consensus_status_by_descriptor_digest( networkstatus_t *consensus, const char *digest); const routerstatus_t *router_get_consensus_status_by_nickname( const char *nickname, int warn_if_unnamed); const char *networkstatus_get_router_digest_by_nickname(const char *nickname); int networkstatus_nickname_is_unnamed(const char *nickname); void networkstatus_consensus_download_failed(int status_code, const char *flavname); void update_consensus_networkstatus_fetch_time(time_t now); int should_delay_dir_fetches(const or_options_t *options); void update_networkstatus_downloads(time_t now); void update_certificate_downloads(time_t now); int consensus_is_waiting_for_certs(void); int client_would_use_router(const routerstatus_t *rs, time_t now, const or_options_t *options); networkstatus_t *networkstatus_get_latest_consensus(void); networkstatus_t *networkstatus_get_latest_consensus_by_flavor( consensus_flavor_t f); networkstatus_t *networkstatus_get_live_consensus(time_t now); networkstatus_t *networkstatus_get_reasonably_live_consensus(time_t now, int flavor); #define NSSET_FROM_CACHE 1 #define NSSET_WAS_WAITING_FOR_CERTS 2 #define NSSET_DONT_DOWNLOAD_CERTS 4 #define NSSET_ACCEPT_OBSOLETE 8 #define NSSET_REQUIRE_FLAVOR 16 int networkstatus_set_current_consensus(const char *consensus, const char *flavor, unsigned flags); void networkstatus_note_certs_arrived(void); void routers_update_all_from_networkstatus(time_t now, int dir_version); void routers_update_status_from_consensus_networkstatus(smartlist_t *routers, int reset_failures); void signed_descs_update_status_from_consensus_networkstatus( smartlist_t *descs); char *networkstatus_getinfo_helper_single(const routerstatus_t *rs); char *networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now); void networkstatus_dump_bridge_status_to_file(time_t now); int32_t networkstatus_get_param(const networkstatus_t *ns, const char *param_name, int32_t default_val, int32_t min_val, int32_t max_val); int getinfo_helper_networkstatus(control_connection_t *conn, const char *question, char **answer, const char **errmsg); int32_t networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight, int32_t default_val); const char *networkstatus_get_flavor_name(consensus_flavor_t flav); int networkstatus_parse_flavor_name(const char *flavname); void document_signature_free(document_signature_t *sig); document_signature_t *document_signature_dup(const document_signature_t *sig); void networkstatus_free_all(void); int networkstatus_get_weight_scale_param(networkstatus_t *ns); #endif tor-0.2.4.20/src/or/onion.c0000644000175000017500000011267212255745673012210 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file onion.c * \brief Functions to queue create cells, wrap the various onionskin types, * and parse and create the CREATE cell and its allies. **/ #include "or.h" #include "circuitlist.h" #include "config.h" #include "cpuworker.h" #include "networkstatus.h" #include "onion.h" #include "onion_fast.h" #include "onion_ntor.h" #include "onion_tap.h" #include "relay.h" #include "rephist.h" #include "router.h" #include "tor_queue.h" /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ typedef struct onion_queue_t { TOR_TAILQ_ENTRY(onion_queue_t) next; or_circuit_t *circ; uint16_t handshake_type; create_cell_t *onionskin; time_t when_added; } onion_queue_t; /** 5 seconds on the onion queue til we just send back a destroy */ #define ONIONQUEUE_WAIT_CUTOFF 5 /** Array of queues of circuits waiting for CPU workers. An element is NULL * if that queue is empty.*/ TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) ol_list[MAX_ONION_HANDSHAKE_TYPE+1] = { TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */ TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */ TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */ }; /** Number of entries of each type currently in each element of ol_list[]. */ static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1]; static int num_ntors_per_tap(void); static void onion_queue_entry_remove(onion_queue_t *victim); /* XXXX024 Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN. * * (By which I think I meant, "make sure that no * X_ONIONSKIN_CHALLENGE/REPLY_LEN is greater than * MAX_ONIONSKIN_CHALLENGE/REPLY_LEN." Also, make sure that we can pass * over-large values via EXTEND2/EXTENDED2, for future-compatibility.*/ /** Return true iff we have room to queue another oninoskin of type * type. */ static int have_room_for_onionskin(uint16_t type) { const or_options_t *options = get_options(); int num_cpus; uint64_t tap_usec, ntor_usec; uint64_t ntor_during_tap_usec, tap_during_ntor_usec; /* If we've got fewer than 50 entries, we always have room for one more. */ if (ol_entries[type] < 50) return 1; num_cpus = get_num_cpus(options); /* Compute how many microseconds we'd expect to need to clear all * onionskins in various combinations of the queues. */ /* How long would it take to process all the TAP cells in the queue? */ tap_usec = estimated_usec_for_onionskins( ol_entries[ONION_HANDSHAKE_TYPE_TAP], ONION_HANDSHAKE_TYPE_TAP) / num_cpus; /* How long would it take to process all the NTor cells in the queue? */ ntor_usec = estimated_usec_for_onionskins( ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; /* How long would it take to process the tap cells that we expect to * process while draining the ntor queue? */ tap_during_ntor_usec = estimated_usec_for_onionskins( MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP], ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()), ONION_HANDSHAKE_TYPE_TAP) / num_cpus; /* How long would it take to process the ntor cells that we expect to * process while draining the tap queue? */ ntor_during_tap_usec = estimated_usec_for_onionskins( MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()), ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue * this. */ if (type == ONION_HANDSHAKE_TYPE_NTOR && (ntor_usec + tap_during_ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay) return 0; if (type == ONION_HANDSHAKE_TYPE_TAP && (tap_usec + ntor_during_tap_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay) return 0; #ifdef CURVE25519_ENABLED /* If we support the ntor handshake, then don't let TAP handshakes use * more than 2/3 of the space on the queue. */ if (type == ONION_HANDSHAKE_TYPE_TAP && tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3) return 0; #else (void) type; #endif return 1; } /** Add circ to the end of ol_list and return 0, except * if ol_list is too long, in which case do nothing and return -1. */ int onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) { onion_queue_t *tmp; time_t now = time(NULL); if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) { log_warn(LD_BUG, "Handshake %d out of range! Dropping.", onionskin->handshake_type); return -1; } tmp = tor_malloc_zero(sizeof(onion_queue_t)); tmp->circ = circ; tmp->handshake_type = onionskin->handshake_type; tmp->onionskin = onionskin; tmp->when_added = now; if (!have_room_for_onionskin(onionskin->handshake_type)) { #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); char *m; if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR && (m = rate_limit_log(&last_warned, approx_time()))) { log_warn(LD_GENERAL, "Your computer is too slow to handle this many circuit " "creation requests! Please consider using the " "MaxAdvertisedBandwidth config option or choosing a more " "restricted exit policy.%s",m); tor_free(m); } tor_free(tmp); return -1; } ++ol_entries[onionskin->handshake_type]; log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.", onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ol_entries[ONION_HANDSHAKE_TYPE_TAP]); circ->onionqueue_entry = tmp; TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next); /* cull elderly requests. */ while (1) { onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]); if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF) break; circ = head->circ; circ->onionqueue_entry = NULL; onion_queue_entry_remove(head); log_info(LD_CIRC, "Circuit create request is too old; canceling due to overload."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); } return 0; } /** Return a fairness parameter, to prefer processing NTOR style * handshakes but still slowly drain the TAP queue so we don't starve * it entirely. */ static int num_ntors_per_tap(void) { #define DEFAULT_NUM_NTORS_PER_TAP 10 #define MIN_NUM_NTORS_PER_TAP 1 #define MAX_NUM_NTORS_PER_TAP 100000 return networkstatus_get_param(NULL, "NumNTorsPerTAP", DEFAULT_NUM_NTORS_PER_TAP, MIN_NUM_NTORS_PER_TAP, MAX_NUM_NTORS_PER_TAP); } /** Choose which onion queue we'll pull from next. If one is empty choose * the other; if they both have elements, load balance across them but * favoring NTOR. */ static uint16_t decide_next_handshake_type(void) { /* The number of times we've chosen ntor lately when both were available. */ static int recently_chosen_ntors = 0; if (!ol_entries[ONION_HANDSHAKE_TYPE_NTOR]) return ONION_HANDSHAKE_TYPE_TAP; /* no ntors? try tap */ if (!ol_entries[ONION_HANDSHAKE_TYPE_TAP]) { /* Nick wants us to prioritize new tap requests when there aren't * any in the queue and we've processed k ntor cells since the last * tap cell. This strategy is maybe a good idea, since it starves tap * less in the case where tap is rare, or maybe a poor idea, since it * makes the new tap cell unfairly jump in front of ntor cells that * got here first. In any case this edge case will only become relevant * once tap is rare. We should reevaluate whether we like this decision * once tap gets more rare. */ if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] && recently_chosen_ntors <= num_ntors_per_tap()) ++recently_chosen_ntors; return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */ } /* They both have something queued. Pick ntor if we haven't done that * too much lately. */ if (++recently_chosen_ntors <= num_ntors_per_tap()) { return ONION_HANDSHAKE_TYPE_NTOR; } /* Else, it's time to let tap have its turn. */ recently_chosen_ntors = 0; return ONION_HANDSHAKE_TYPE_TAP; } /** Remove the highest priority item from ol_list[] and return it, or * return NULL if the lists are empty. */ or_circuit_t * onion_next_task(create_cell_t **onionskin_out) { or_circuit_t *circ; uint16_t handshake_to_choose = decide_next_handshake_type(); onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[handshake_to_choose]); if (!head) return NULL; /* no onions pending, we're done */ tor_assert(head->circ); tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE); // tor_assert(head->circ->p_chan); /* make sure it's still valid */ /* XXX I only commented out the above line to make the unit tests * more manageable. That's probably not good long-term. -RD */ circ = head->circ; if (head->onionskin) --ol_entries[head->handshake_type]; log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.", head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", ol_entries[ONION_HANDSHAKE_TYPE_NTOR], ol_entries[ONION_HANDSHAKE_TYPE_TAP]); *onionskin_out = head->onionskin; head->onionskin = NULL; /* prevent free. */ circ->onionqueue_entry = NULL; onion_queue_entry_remove(head); return circ; } /** Return the number of handshake_type-style create requests pending. */ int onion_num_pending(uint16_t handshake_type) { return ol_entries[handshake_type]; } /** Go through ol_list, find the onion_queue_t element which points to * circ, remove and free that element. Leave circ itself alone. */ void onion_pending_remove(or_circuit_t *circ) { onion_queue_t *victim; if (!circ) return; victim = circ->onionqueue_entry; if (victim) onion_queue_entry_remove(victim); } /** Remove a queue entry victim from the queue, unlinking it from * its circuit and freeing it and any structures it owns.*/ static void onion_queue_entry_remove(onion_queue_t *victim) { if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) { log_warn(LD_BUG, "Handshake %d out of range! Dropping.", victim->handshake_type); /* XXX leaks */ return; } TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next); if (victim->circ) victim->circ->onionqueue_entry = NULL; if (victim->onionskin) --ol_entries[victim->handshake_type]; tor_free(victim->onionskin); tor_free(victim); } /** Remove all circuits from the pending list. Called from tor_free_all. */ void clear_pending_onions(void) { onion_queue_t *victim; int i; for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) { while ((victim = TOR_TAILQ_FIRST(&ol_list[i]))) { onion_queue_entry_remove(victim); } } memset(ol_entries, 0, sizeof(ol_entries)); } /* ============================================================ */ /** Fill in a server_onion_keys_t object at keys with all of the keys * and other info we might need to do onion handshakes. (We make a copy of * our keys for each cpuworker to avoid race conditions with the main thread, * and to avoid locking) */ void setup_server_onion_keys(server_onion_keys_t *keys) { memset(keys, 0, sizeof(server_onion_keys_t)); memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN); dup_onion_keys(&keys->onion_key, &keys->last_onion_key); #ifdef CURVE25519_ENABLED keys->curve25519_key_map = construct_ntor_key_map(); keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t)); curve25519_keypair_generate(keys->junk_keypair, 0); #endif } /** Release all storage held in keys, but do not free keys * itself (as it's likely to be stack-allocated.) */ void release_server_onion_keys(server_onion_keys_t *keys) { if (! keys) return; crypto_pk_free(keys->onion_key); crypto_pk_free(keys->last_onion_key); #ifdef CURVE25519_ENABLED ntor_key_map_free(keys->curve25519_key_map); tor_free(keys->junk_keypair); #endif memset(keys, 0, sizeof(server_onion_keys_t)); } /** Release whatever storage is held in state, depending on its * type, and clear its pointer. */ void onion_handshake_state_release(onion_handshake_state_t *state) { switch (state->tag) { case ONION_HANDSHAKE_TYPE_TAP: crypto_dh_free(state->u.tap); state->u.tap = NULL; break; case ONION_HANDSHAKE_TYPE_FAST: fast_handshake_state_free(state->u.fast); state->u.fast = NULL; break; #ifdef CURVE25519_ENABLED case ONION_HANDSHAKE_TYPE_NTOR: ntor_handshake_state_free(state->u.ntor); state->u.ntor = NULL; break; #endif default: log_warn(LD_BUG, "called with unknown handshake state type %d", (int)state->tag); tor_fragile_assert(); } } /** Perform the first step of a circuit-creation handshake of type type * (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in * onion_skin_out, and store any state information in state_out. * Return -1 on failure, and the length of the onionskin on acceptance. */ int onion_skin_create(int type, const extend_info_t *node, onion_handshake_state_t *state_out, uint8_t *onion_skin_out) { int r = -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (!node->onion_key) return -1; if (onion_skin_TAP_create(node->onion_key, &state_out->u.tap, (char*)onion_skin_out) < 0) return -1; r = TAP_ONIONSKIN_CHALLENGE_LEN; break; case ONION_HANDSHAKE_TYPE_FAST: if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0) return -1; r = CREATE_FAST_LEN; break; case ONION_HANDSHAKE_TYPE_NTOR: #ifdef CURVE25519_ENABLED if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key, CURVE25519_PUBKEY_LEN)) return -1; if (onion_skin_ntor_create((const uint8_t*)node->identity_digest, &node->curve25519_onion_key, &state_out->u.ntor, onion_skin_out) < 0) return -1; r = NTOR_ONIONSKIN_LEN; #else return -1; #endif break; default: log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); r = -1; } if (r > 0) state_out->tag = (uint16_t) type; return r; } /** Perform the second (server-side) step of a circuit-creation handshake of * type type, responding to the client request in onion_skin * using the keys in keys. On success, write our response into * reply_out, generate keys_out_len bytes worth of key material * in keys_out_len, a hidden service nonce to rend_nonce_out, * and return the length of the reply. On failure, return -1. */ int onion_skin_server_handshake(int type, const uint8_t *onion_skin, size_t onionskin_len, const server_onion_keys_t *keys, uint8_t *reply_out, uint8_t *keys_out, size_t keys_out_len, uint8_t *rend_nonce_out) { int r = -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN) return -1; if (onion_skin_TAP_server_handshake((const char*)onion_skin, keys->onion_key, keys->last_onion_key, (char*)reply_out, (char*)keys_out, keys_out_len)<0) return -1; r = TAP_ONIONSKIN_REPLY_LEN; memcpy(rend_nonce_out, reply_out+DH_KEY_LEN, DIGEST_LEN); break; case ONION_HANDSHAKE_TYPE_FAST: if (onionskin_len != CREATE_FAST_LEN) return -1; if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0) return -1; r = CREATED_FAST_LEN; memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN); break; case ONION_HANDSHAKE_TYPE_NTOR: #ifdef CURVE25519_ENABLED if (onionskin_len < NTOR_ONIONSKIN_LEN) return -1; { size_t keys_tmp_len = keys_out_len + DIGEST_LEN; uint8_t *keys_tmp = tor_malloc(keys_out_len + DIGEST_LEN); if (onion_skin_ntor_server_handshake( onion_skin, keys->curve25519_key_map, keys->junk_keypair, keys->my_identity, reply_out, keys_tmp, keys_tmp_len)<0) { tor_free(keys_tmp); return -1; } memcpy(keys_out, keys_tmp, keys_out_len); memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN); memwipe(keys_tmp, 0, keys_tmp_len); tor_free(keys_tmp); r = NTOR_REPLY_LEN; } #else return -1; #endif break; default: log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); return -1; } return r; } /** Perform the final (client-side) step of a circuit-creation handshake of * type type, using our state in handshake_state and the * server's response in reply. On success, generate keys_out_len * bytes worth of key material in keys_out_len, set * rend_authenticator_out to the "KH" field that can be used to * establish introduction points at this hop, and return 0. On failure, * return -1. */ int onion_skin_client_handshake(int type, const onion_handshake_state_t *handshake_state, const uint8_t *reply, size_t reply_len, uint8_t *keys_out, size_t keys_out_len, uint8_t *rend_authenticator_out) { if (handshake_state->tag != type) return -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (reply_len != TAP_ONIONSKIN_REPLY_LEN) return -1; if (onion_skin_TAP_client_handshake(handshake_state->u.tap, (const char*)reply, (char *)keys_out, keys_out_len) < 0) return -1; memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN); return 0; case ONION_HANDSHAKE_TYPE_FAST: if (reply_len != CREATED_FAST_LEN) return -1; if (fast_client_handshake(handshake_state->u.fast, reply, keys_out, keys_out_len) < 0) return -1; memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN); return 0; #ifdef CURVE25519_ENABLED case ONION_HANDSHAKE_TYPE_NTOR: if (reply_len < NTOR_REPLY_LEN) return -1; { size_t keys_tmp_len = keys_out_len + DIGEST_LEN; uint8_t *keys_tmp = tor_malloc(keys_tmp_len); if (onion_skin_ntor_client_handshake(handshake_state->u.ntor, reply, keys_tmp, keys_tmp_len) < 0) { tor_free(keys_tmp); return -1; } memcpy(keys_out, keys_tmp, keys_out_len); memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN); memwipe(keys_tmp, 0, keys_tmp_len); tor_free(keys_tmp); } return 0; #endif default: log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); return -1; } } /** Helper: return 0 if cell appears valid, -1 otherwise. If * unknown_ok is true, allow cells with handshake types we don't * recognize. */ static int check_create_cell(const create_cell_t *cell, int unknown_ok) { switch (cell->cell_type) { case CELL_CREATE: if (cell->handshake_type != ONION_HANDSHAKE_TYPE_TAP && cell->handshake_type != ONION_HANDSHAKE_TYPE_NTOR) return -1; break; case CELL_CREATE_FAST: if (cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) return -1; break; case CELL_CREATE2: break; default: return -1; } switch (cell->handshake_type) { case ONION_HANDSHAKE_TYPE_TAP: if (cell->handshake_len != TAP_ONIONSKIN_CHALLENGE_LEN) return -1; break; case ONION_HANDSHAKE_TYPE_FAST: if (cell->handshake_len != CREATE_FAST_LEN) return -1; break; #ifdef CURVE25519_ENABLED case ONION_HANDSHAKE_TYPE_NTOR: if (cell->handshake_len != NTOR_ONIONSKIN_LEN) return -1; break; #endif default: if (! unknown_ok) return -1; } return 0; } /** Write the various parameters into the create cell. Separate from * create_cell_parse() to make unit testing easier. */ void create_cell_init(create_cell_t *cell_out, uint8_t cell_type, uint16_t handshake_type, uint16_t handshake_len, const uint8_t *onionskin) { memset(cell_out, 0, sizeof(*cell_out)); cell_out->cell_type = cell_type; cell_out->handshake_type = handshake_type; cell_out->handshake_len = handshake_len; memcpy(cell_out->onionskin, onionskin, handshake_len); } /** Helper: parse the CREATE2 payload at p, which could be up to * p_len bytes long, and use it to fill the fields of * cell_out. Return 0 on success and -1 on failure. * * Note that part of the body of an EXTEND2 cell is a CREATE2 payload, so * this function is also used for parsing those. */ static int parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len) { uint16_t handshake_type, handshake_len; if (p_len < 4) return -1; handshake_type = ntohs(get_uint16(p)); handshake_len = ntohs(get_uint16(p+2)); if (handshake_len > CELL_PAYLOAD_SIZE - 4 || handshake_len > p_len - 4) return -1; if (handshake_type == ONION_HANDSHAKE_TYPE_FAST) return -1; create_cell_init(cell_out, CELL_CREATE2, handshake_type, handshake_len, p+4); return 0; } /** Magic string which, in a CREATE or EXTEND cell, indicates that a seeming * TAP payload is really an ntor payload. We'd do away with this if every * relay supported EXTEND2, but we want to be able to extend from A to B with * ntor even when A doesn't understand EXTEND2 and so can't generate a * CREATE2 cell. **/ #define NTOR_CREATE_MAGIC "ntorNTORntorNTOR" /** Parse a CREATE, CREATE_FAST, or CREATE2 cell from cell_in into * cell_out. Return 0 on success, -1 on failure. (We reject some * syntactically valid CREATE2 cells that we can't generate or react to.) */ int create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in) { switch (cell_in->command) { case CELL_CREATE: if (tor_memeq(cell_in->payload, NTOR_CREATE_MAGIC, 16)) { create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, NTOR_ONIONSKIN_LEN, cell_in->payload+16); } else { create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP, TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->payload); } break; case CELL_CREATE_FAST: create_cell_init(cell_out, CELL_CREATE_FAST, ONION_HANDSHAKE_TYPE_FAST, CREATE_FAST_LEN, cell_in->payload); break; case CELL_CREATE2: if (parse_create2_payload(cell_out, cell_in->payload, CELL_PAYLOAD_SIZE) < 0) return -1; break; default: return -1; } return check_create_cell(cell_out, 0); } /** Helper: return 0 if cell appears valid, -1 otherwise. */ static int check_created_cell(const created_cell_t *cell) { switch (cell->cell_type) { case CELL_CREATED: if (cell->handshake_len != TAP_ONIONSKIN_REPLY_LEN && cell->handshake_len != NTOR_REPLY_LEN) return -1; break; case CELL_CREATED_FAST: if (cell->handshake_len != CREATED_FAST_LEN) return -1; break; case CELL_CREATED2: if (cell->handshake_len > RELAY_PAYLOAD_SIZE-2) return -1; break; } return 0; } /** Parse a CREATED, CREATED_FAST, or CREATED2 cell from cell_in into * cell_out. Return 0 on success, -1 on failure. */ int created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in) { memset(cell_out, 0, sizeof(*cell_out)); switch (cell_in->command) { case CELL_CREATED: cell_out->cell_type = CELL_CREATED; cell_out->handshake_len = TAP_ONIONSKIN_REPLY_LEN; memcpy(cell_out->reply, cell_in->payload, TAP_ONIONSKIN_REPLY_LEN); break; case CELL_CREATED_FAST: cell_out->cell_type = CELL_CREATED_FAST; cell_out->handshake_len = CREATED_FAST_LEN; memcpy(cell_out->reply, cell_in->payload, CREATED_FAST_LEN); break; case CELL_CREATED2: { const uint8_t *p = cell_in->payload; cell_out->cell_type = CELL_CREATED2; cell_out->handshake_len = ntohs(get_uint16(p)); if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 2) return -1; memcpy(cell_out->reply, p+2, cell_out->handshake_len); break; } } return check_created_cell(cell_out); } /** Helper: return 0 if cell appears valid, -1 otherwise. */ static int check_extend_cell(const extend_cell_t *cell) { if (tor_digest_is_zero((const char*)cell->node_id)) return -1; /* We don't currently allow EXTEND2 cells without an IPv4 address */ if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC) return -1; if (cell->create_cell.cell_type == CELL_CREATE) { if (cell->cell_type != RELAY_COMMAND_EXTEND) return -1; } else if (cell->create_cell.cell_type == CELL_CREATE2) { if (cell->cell_type != RELAY_COMMAND_EXTEND2 && cell->cell_type != RELAY_COMMAND_EXTEND) return -1; } else { /* In particular, no CREATE_FAST cells are allowed */ return -1; } if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST) return -1; return check_create_cell(&cell->create_cell, 1); } /** Protocol constants for specifier types in EXTEND2 * @{ */ #define SPECTYPE_IPV4 0 #define SPECTYPE_IPV6 1 #define SPECTYPE_LEGACY_ID 2 /** @} */ /** Parse an EXTEND or EXTEND2 cell (according to command) from the * payload_length bytes of payload into cell_out. Return * 0 on success, -1 on failure. */ int extend_cell_parse(extend_cell_t *cell_out, const uint8_t command, const uint8_t *payload, size_t payload_length) { const uint8_t *eop; memset(cell_out, 0, sizeof(*cell_out)); if (payload_length > RELAY_PAYLOAD_SIZE) return -1; eop = payload + payload_length; switch (command) { case RELAY_COMMAND_EXTEND: { if (payload_length != 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN) return -1; cell_out->cell_type = RELAY_COMMAND_EXTEND; tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr, get_uint32(payload)); cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4)); tor_addr_make_unspec(&cell_out->orport_ipv6.addr); if (tor_memeq(payload + 6, NTOR_CREATE_MAGIC, 16)) { cell_out->create_cell.cell_type = CELL_CREATE2; cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR; cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN; memcpy(cell_out->create_cell.onionskin, payload + 22, NTOR_ONIONSKIN_LEN); } else { cell_out->create_cell.cell_type = CELL_CREATE; cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP; cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN; memcpy(cell_out->create_cell.onionskin, payload + 6, TAP_ONIONSKIN_CHALLENGE_LEN); } memcpy(cell_out->node_id, payload + 6 + TAP_ONIONSKIN_CHALLENGE_LEN, DIGEST_LEN); break; } case RELAY_COMMAND_EXTEND2: { uint8_t n_specs = *payload, spectype, speclen; int i; int found_ipv4 = 0, found_ipv6 = 0, found_id = 0; tor_addr_make_unspec(&cell_out->orport_ipv4.addr); tor_addr_make_unspec(&cell_out->orport_ipv6.addr); cell_out->cell_type = RELAY_COMMAND_EXTEND2; ++payload; /* Parse the specifiers. We'll only take the first IPv4 and first IPv6 * addres, and the node ID, and ignore everything else */ for (i = 0; i < n_specs; ++i) { if (eop - payload < 2) return -1; spectype = payload[0]; speclen = payload[1]; payload += 2; if (eop - payload < speclen) return -1; switch (spectype) { case SPECTYPE_IPV4: if (speclen != 6) return -1; if (!found_ipv4) { tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr, get_uint32(payload)); cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4)); found_ipv4 = 1; } break; case SPECTYPE_IPV6: if (speclen != 18) return -1; if (!found_ipv6) { tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr, (const char*)payload); cell_out->orport_ipv6.port = ntohs(get_uint16(payload+16)); found_ipv6 = 1; } break; case SPECTYPE_LEGACY_ID: if (speclen != 20) return -1; if (found_id) return -1; memcpy(cell_out->node_id, payload, 20); found_id = 1; break; } payload += speclen; } if (!found_id || !found_ipv4) return -1; if (parse_create2_payload(&cell_out->create_cell,payload,eop-payload)<0) return -1; break; } default: return -1; } return check_extend_cell(cell_out); } /** Helper: return 0 if cell appears valid, -1 otherwise. */ static int check_extended_cell(const extended_cell_t *cell) { if (cell->created_cell.cell_type == CELL_CREATED) { if (cell->cell_type != RELAY_COMMAND_EXTENDED) return -1; } else if (cell->created_cell.cell_type == CELL_CREATED2) { if (cell->cell_type != RELAY_COMMAND_EXTENDED2) return -1; } else { return -1; } return check_created_cell(&cell->created_cell); } /** Parse an EXTENDED or EXTENDED2 cell (according to command) from the * payload_length bytes of payload into cell_out. Return * 0 on success, -1 on failure. */ int extended_cell_parse(extended_cell_t *cell_out, const uint8_t command, const uint8_t *payload, size_t payload_len) { memset(cell_out, 0, sizeof(*cell_out)); if (payload_len > RELAY_PAYLOAD_SIZE) return -1; switch (command) { case RELAY_COMMAND_EXTENDED: if (payload_len != TAP_ONIONSKIN_REPLY_LEN) return -1; cell_out->cell_type = RELAY_COMMAND_EXTENDED; cell_out->created_cell.cell_type = CELL_CREATED; cell_out->created_cell.handshake_len = TAP_ONIONSKIN_REPLY_LEN; memcpy(cell_out->created_cell.reply, payload, TAP_ONIONSKIN_REPLY_LEN); break; case RELAY_COMMAND_EXTENDED2: { cell_out->cell_type = RELAY_COMMAND_EXTENDED2; cell_out->created_cell.cell_type = CELL_CREATED2; cell_out->created_cell.handshake_len = ntohs(get_uint16(payload)); if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE - 2 || cell_out->created_cell.handshake_len > payload_len - 2) return -1; memcpy(cell_out->created_cell.reply, payload+2, cell_out->created_cell.handshake_len); } break; default: return -1; } return check_extended_cell(cell_out); } /** Fill cell_out with a correctly formatted version of the * CREATE{,_FAST,2} cell in cell_in. Return 0 on success, -1 on * failure. This is a cell we didn't originate if relayed is true. */ static int create_cell_format_impl(cell_t *cell_out, const create_cell_t *cell_in, int relayed) { uint8_t *p; size_t space; if (check_create_cell(cell_in, relayed) < 0) return -1; memset(cell_out->payload, 0, sizeof(cell_out->payload)); cell_out->command = cell_in->cell_type; p = cell_out->payload; space = sizeof(cell_out->payload); switch (cell_in->cell_type) { case CELL_CREATE: if (cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { memcpy(p, NTOR_CREATE_MAGIC, 16); p += 16; space -= 16; } /* Fall through */ case CELL_CREATE_FAST: tor_assert(cell_in->handshake_len <= space); memcpy(p, cell_in->onionskin, cell_in->handshake_len); break; case CELL_CREATE2: tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-4); set_uint16(cell_out->payload, htons(cell_in->handshake_type)); set_uint16(cell_out->payload+2, htons(cell_in->handshake_len)); memcpy(cell_out->payload + 4, cell_in->onionskin, cell_in->handshake_len); break; default: return -1; } return 0; } int create_cell_format(cell_t *cell_out, const create_cell_t *cell_in) { return create_cell_format_impl(cell_out, cell_in, 0); } int create_cell_format_relayed(cell_t *cell_out, const create_cell_t *cell_in) { return create_cell_format_impl(cell_out, cell_in, 1); } /** Fill cell_out with a correctly formatted version of the * CREATED{,_FAST,2} cell in cell_in. Return 0 on success, -1 on * failure. */ int created_cell_format(cell_t *cell_out, const created_cell_t *cell_in) { if (check_created_cell(cell_in) < 0) return -1; memset(cell_out->payload, 0, sizeof(cell_out->payload)); cell_out->command = cell_in->cell_type; switch (cell_in->cell_type) { case CELL_CREATED: case CELL_CREATED_FAST: tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)); memcpy(cell_out->payload, cell_in->reply, cell_in->handshake_len); break; case CELL_CREATED2: tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-2); set_uint16(cell_out->payload, htons(cell_in->handshake_len)); memcpy(cell_out->payload + 2, cell_in->reply, cell_in->handshake_len); break; default: return -1; } return 0; } /** Format the EXTEND{,2} cell in cell_in, storing its relay payload in * payload_out, the number of bytes used in *len_out, and the * relay command in *command_out. The payload_out must have * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extend_cell_t *cell_in) { uint8_t *p, *eop; if (check_extend_cell(cell_in) < 0) return -1; p = payload_out; eop = payload_out + RELAY_PAYLOAD_SIZE; memset(p, 0, RELAY_PAYLOAD_SIZE); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTEND: { *command_out = RELAY_COMMAND_EXTEND; *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN; set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); set_uint16(p+4, ntohs(cell_in->orport_ipv4.port)); if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { memcpy(p+6, NTOR_CREATE_MAGIC, 16); memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN); } else { memcpy(p+6, cell_in->create_cell.onionskin, TAP_ONIONSKIN_CHALLENGE_LEN); } memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN); } break; case RELAY_COMMAND_EXTEND2: { uint8_t n = 2; *command_out = RELAY_COMMAND_EXTEND2; *p++ = n; /* 2 identifiers */ *p++ = SPECTYPE_IPV4; /* First is IPV4. */ *p++ = 6; /* It's 6 bytes long. */ set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); set_uint16(p+4, htons(cell_in->orport_ipv4.port)); p += 6; *p++ = SPECTYPE_LEGACY_ID; /* Next is an identity digest. */ *p++ = 20; /* It's 20 bytes long */ memcpy(p, cell_in->node_id, DIGEST_LEN); p += 20; /* Now we can send the handshake */ set_uint16(p, htons(cell_in->create_cell.handshake_type)); set_uint16(p+2, htons(cell_in->create_cell.handshake_len)); p += 4; if (cell_in->create_cell.handshake_len > eop - p) return -1; memcpy(p, cell_in->create_cell.onionskin, cell_in->create_cell.handshake_len); p += cell_in->create_cell.handshake_len; *len_out = p - payload_out; } break; default: return -1; } return 0; } /** Format the EXTENDED{,2} cell in cell_in, storing its relay payload * in payload_out, the number of bytes used in *len_out, and the * relay command in *command_out. The payload_out must have * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ int extended_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extended_cell_t *cell_in) { uint8_t *p; if (check_extended_cell(cell_in) < 0) return -1; p = payload_out; memset(p, 0, RELAY_PAYLOAD_SIZE); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTENDED: { *command_out = RELAY_COMMAND_EXTENDED; *len_out = TAP_ONIONSKIN_REPLY_LEN; memcpy(payload_out, cell_in->created_cell.reply, TAP_ONIONSKIN_REPLY_LEN); } break; case RELAY_COMMAND_EXTENDED2: { *command_out = RELAY_COMMAND_EXTENDED2; *len_out = 2 + cell_in->created_cell.handshake_len; set_uint16(payload_out, htons(cell_in->created_cell.handshake_len)); if (2+cell_in->created_cell.handshake_len > RELAY_PAYLOAD_SIZE) return -1; memcpy(payload_out+2, cell_in->created_cell.reply, cell_in->created_cell.handshake_len); } break; default: return -1; } return 0; } tor-0.2.4.20/src/or/onion_ntor.h0000644000175000017500000000412112166112777013236 00000000000000/* Copyright (c) 2012-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ONION_NTOR_H #define TOR_ONION_NTOR_H #include "torint.h" #include "crypto_curve25519.h" #include "di_ops.h" /** State to be maintained by a client between sending an ntor onionskin * and receiving a reply. */ typedef struct ntor_handshake_state_t ntor_handshake_state_t; /** Length of an ntor onionskin, as sent from the client to server. */ #define NTOR_ONIONSKIN_LEN 84 /** Length of an ntor reply, as sent from server to client. */ #define NTOR_REPLY_LEN 64 #ifdef CURVE25519_ENABLED void ntor_handshake_state_free(ntor_handshake_state_t *state); int onion_skin_ntor_create(const uint8_t *router_id, const curve25519_public_key_t *router_key, ntor_handshake_state_t **handshake_state_out, uint8_t *onion_skin_out); int onion_skin_ntor_server_handshake(const uint8_t *onion_skin, const di_digest256_map_t *private_keys, const curve25519_keypair_t *junk_keypair, const uint8_t *my_node_id, uint8_t *handshake_reply_out, uint8_t *key_out, size_t key_out_len); int onion_skin_ntor_client_handshake( const ntor_handshake_state_t *handshake_state, const uint8_t *handshake_reply, uint8_t *key_out, size_t key_out_len); #ifdef ONION_NTOR_PRIVATE /** Storage held by a client while waiting for an ntor reply from a server. */ struct ntor_handshake_state_t { /** Identity digest of the router we're talking to. */ uint8_t router_id[DIGEST_LEN]; /** Onion key of the router we're talking to. */ curve25519_public_key_t pubkey_B; /** * Short-lived keypair for use with this handshake. * @{ */ curve25519_secret_key_t seckey_x; curve25519_public_key_t pubkey_X; /** @} */ }; #endif #endif #endif tor-0.2.4.20/src/or/dirserv.c0000644000175000017500000043126412255745673012545 00000000000000/* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRSERV_PRIVATE #include "or.h" #include "buffers.h" #include "config.h" #include "confparse.h" #include "channel.h" #include "channeltls.h" #include "command.h" #include "connection.h" #include "connection_or.h" #include "control.h" #include "directory.h" #include "dirserv.h" #include "dirvote.h" #include "hibernate.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "policies.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" /** * \file dirserv.c * \brief Directory server core implementation. Manages directory * contents and generates directories. */ /** How far in the future do we allow a router to get? (seconds) */ #define ROUTER_ALLOW_SKEW (60*60*12) /** How many seconds do we wait before regenerating the directory? */ #define DIR_REGEN_SLACK_TIME 30 /** If we're a cache, keep this many networkstatuses around from non-trusted * directory authorities. */ #define MAX_UNTRUSTED_NETWORKSTATUSES 16 /** If a v1 directory is older than this, discard it. */ #define MAX_V1_DIRECTORY_AGE (30*24*60*60) /** If a v1 running-routers is older than this, discard it. */ #define MAX_V1_RR_AGE (7*24*60*60) extern time_t time_of_process_start; /* from main.c */ extern long stats_n_seconds_working; /* from main.c */ /** Do we need to regenerate the v1 directory when someone asks for it? */ static time_t the_directory_is_dirty = 1; /** Do we need to regenerate the v1 runningrouters document when somebody * asks for it? */ static time_t runningrouters_is_dirty = 1; /** Do we need to regenerate our v2 networkstatus document when somebody asks * for it? */ static time_t the_v2_networkstatus_is_dirty = 1; /** Most recently generated encoded signed v1 directory. (v1 auth dirservers * only.) */ static cached_dir_t *the_directory = NULL; /** For authoritative directories: the current (v1) network status. */ static cached_dir_t the_runningrouters; /** Total number of routers with measured bandwidth; this is set by * dirserv_count_measured_bws() before the loop in * dirserv_generate_networkstatus_vote_obj() and checked by * dirserv_get_credible_bandwidth() and * dirserv_compute_performance_thresholds() */ static int routers_with_measured_bw = 0; static void directory_remove_invalid(void); static cached_dir_t *dirserv_regenerate_directory(void); static char *format_versions_list(config_line_t *ln); struct authdir_config_t; static int add_fingerprint_to_dir(const char *nickname, const char *fp, struct authdir_config_t *list); static uint32_t dirserv_get_status_impl(const char *fp, const char *nickname, const char *address, uint32_t addr, uint16_t or_port, const char *platform, const char *contact, const char **msg, int should_log); static void clear_cached_dir(cached_dir_t *d); static const signed_descriptor_t *get_signed_descriptor_by_fp( const char *fp, int extrainfo, time_t publish_cutoff); static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei, const char **msg); static uint32_t dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri); static uint32_t dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri); /************** Fingerprint handling code ************/ #define FP_NAMED 1 /**< Listed in fingerprint file. */ #define FP_INVALID 2 /**< Believed invalid. */ #define FP_REJECT 4 /**< We will not publish this router. */ #define FP_BADDIR 8 /**< We'll tell clients to avoid using this as a dir. */ #define FP_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */ #define FP_UNNAMED 32 /**< Another router has this name in fingerprint file. */ /** Encapsulate a nickname and an FP_* status; target of status_by_digest * map. */ typedef struct router_status_t { char nickname[MAX_NICKNAME_LEN+1]; uint32_t status; } router_status_t; /** List of nickname-\>identity fingerprint mappings for all the routers * that we name. Used to prevent router impersonation. */ typedef struct authdir_config_t { strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */ digestmap_t *status_by_digest; /**< Map from digest to router_status_t. */ } authdir_config_t; /** Should be static; exposed for testing. */ static authdir_config_t *fingerprint_list = NULL; /** Allocate and return a new, empty, authdir_config_t. */ static authdir_config_t * authdir_config_new(void) { authdir_config_t *list = tor_malloc_zero(sizeof(authdir_config_t)); list->fp_by_name = strmap_new(); list->status_by_digest = digestmap_new(); return list; } /** Add the fingerprint fp for nickname to * the smartlist of fingerprint_entry_t's list. Return 0 if it's * new, or 1 if we replaced the old value. */ /* static */ int add_fingerprint_to_dir(const char *nickname, const char *fp, authdir_config_t *list) { char *fingerprint; char d[DIGEST_LEN]; router_status_t *status; tor_assert(nickname); tor_assert(fp); tor_assert(list); fingerprint = tor_strdup(fp); tor_strstrip(fingerprint, " "); if (base16_decode(d, DIGEST_LEN, fingerprint, strlen(fingerprint))) { log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"", escaped(fp)); tor_free(fingerprint); return 0; } if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) { log_warn(LD_DIRSERV, "Tried to add a mapping for reserved nickname %s", UNNAMED_ROUTER_NICKNAME); tor_free(fingerprint); return 0; } status = digestmap_get(list->status_by_digest, d); if (!status) { status = tor_malloc_zero(sizeof(router_status_t)); digestmap_set(list->status_by_digest, d, status); } if (nickname[0] != '!') { char *old_fp = strmap_get_lc(list->fp_by_name, nickname); if (old_fp && !strcasecmp(fingerprint, old_fp)) { tor_free(fingerprint); } else { tor_free(old_fp); strmap_set_lc(list->fp_by_name, nickname, fingerprint); } status->status |= FP_NAMED; strlcpy(status->nickname, nickname, sizeof(status->nickname)); } else { tor_free(fingerprint); if (!strcasecmp(nickname, "!reject")) { status->status |= FP_REJECT; } else if (!strcasecmp(nickname, "!invalid")) { status->status |= FP_INVALID; } else if (!strcasecmp(nickname, "!baddir")) { status->status |= FP_BADDIR; } else if (!strcasecmp(nickname, "!badexit")) { status->status |= FP_BADEXIT; } } return 0; } /** Add the nickname and fingerprint for this OR to the * global list of recognized identity key fingerprints. */ int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk) { char fp[FINGERPRINT_LEN+1]; if (crypto_pk_get_fingerprint(pk, fp, 0)<0) { log_err(LD_BUG, "Error computing fingerprint"); return -1; } if (!fingerprint_list) fingerprint_list = authdir_config_new(); add_fingerprint_to_dir(nickname, fp, fingerprint_list); return 0; } /** Load the nickname-\>fingerprint mappings stored in the approved-routers * file. The file format is line-based, with each non-blank holding one * nickname, some space, and a fingerprint for that nickname. On success, * replace the current fingerprint list with the new list and return 0. On * failure, leave the current fingerprint list untouched, and return -1. */ int dirserv_load_fingerprint_file(void) { char *fname; char *cf; char *nickname, *fingerprint; authdir_config_t *fingerprint_list_new; int result; config_line_t *front=NULL, *list; const or_options_t *options = get_options(); fname = get_datadir_fname("approved-routers"); log_info(LD_GENERAL, "Reloading approved fingerprints from \"%s\"...", fname); cf = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); if (!cf) { if (options->NamingAuthoritativeDir) { log_warn(LD_FS, "Cannot open fingerprint file '%s'. Failing.", fname); tor_free(fname); return -1; } else { log_info(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname); tor_free(fname); return 0; } } tor_free(fname); result = config_get_lines(cf, &front, 0); tor_free(cf); if (result < 0) { log_warn(LD_CONFIG, "Error reading from fingerprint file"); return -1; } fingerprint_list_new = authdir_config_new(); for (list=front; list; list=list->next) { char digest_tmp[DIGEST_LEN]; nickname = list->key; fingerprint = list->value; if (strlen(nickname) > MAX_NICKNAME_LEN) { log_notice(LD_CONFIG, "Nickname '%s' too long in fingerprint file. Skipping.", nickname); continue; } if (!is_legal_nickname(nickname) && strcasecmp(nickname, "!reject") && strcasecmp(nickname, "!invalid") && strcasecmp(nickname, "!badexit")) { log_notice(LD_CONFIG, "Invalid nickname '%s' in fingerprint file. Skipping.", nickname); continue; } tor_strstrip(fingerprint, " "); /* remove spaces */ if (strlen(fingerprint) != HEX_DIGEST_LEN || base16_decode(digest_tmp, sizeof(digest_tmp), fingerprint, HEX_DIGEST_LEN) < 0) { log_notice(LD_CONFIG, "Invalid fingerprint (nickname '%s', " "fingerprint %s). Skipping.", nickname, fingerprint); continue; } if (0==strcasecmp(nickname, DEFAULT_CLIENT_NICKNAME)) { /* If you approved an OR called "client", then clients who use * the default nickname could all be rejected. That's no good. */ log_notice(LD_CONFIG, "Authorizing nickname '%s' would break " "many clients; skipping.", DEFAULT_CLIENT_NICKNAME); continue; } if (0==strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) { /* If you approved an OR called "unnamed", then clients will be * confused. */ log_notice(LD_CONFIG, "Authorizing nickname '%s' is not allowed; skipping.", UNNAMED_ROUTER_NICKNAME); continue; } if (add_fingerprint_to_dir(nickname, fingerprint, fingerprint_list_new) != 0) log_notice(LD_CONFIG, "Duplicate nickname '%s'.", nickname); } config_free_lines(front); dirserv_free_fingerprint_list(); fingerprint_list = fingerprint_list_new; /* Delete any routers whose fingerprints we no longer recognize */ directory_remove_invalid(); return 0; } /** Check whether router has a nickname/identity key combination that * we recognize from the fingerprint list, or an IP we automatically act on * according to our configuration. Return the appropriate router status. * * If the status is 'FP_REJECT' and msg is provided, set * *msg to an explanation of why. */ uint32_t dirserv_router_get_status(const routerinfo_t *router, const char **msg) { char d[DIGEST_LEN]; if (crypto_pk_get_digest(router->identity_pkey, d)) { log_warn(LD_BUG,"Error computing fingerprint"); if (msg) *msg = "Bug: Error computing fingerprint"; return FP_REJECT; } return dirserv_get_status_impl(d, router->nickname, router->address, router->addr, router->or_port, router->platform, router->contact_info, msg, 1); } /** Return true if there is no point in downloading the router described by * rs because this directory would reject it. */ int dirserv_would_reject_router(const routerstatus_t *rs) { uint32_t res; res = dirserv_get_status_impl(rs->identity_digest, rs->nickname, "", /* address is only used in logs */ rs->addr, rs->or_port, NULL, NULL, NULL, 0); return (res & FP_REJECT) != 0; } /** Helper: Based only on the ID/Nickname combination, * return FP_UNNAMED (unnamed), FP_NAMED (named), or 0 (neither). */ static uint32_t dirserv_get_name_status(const char *id_digest, const char *nickname) { char fp[HEX_DIGEST_LEN+1]; char *fp_by_name; base16_encode(fp, sizeof(fp), id_digest, DIGEST_LEN); if ((fp_by_name = strmap_get_lc(fingerprint_list->fp_by_name, nickname))) { if (!strcasecmp(fp, fp_by_name)) { return FP_NAMED; } else { return FP_UNNAMED; /* Wrong fingerprint. */ } } return 0; } /** Helper: As dirserv_router_get_status, but takes the router fingerprint * (hex, no spaces), nickname, address (used for logging only), IP address, OR * port, platform (logging only) and contact info (logging only) as arguments. * * If should_log is false, do not log messages. (There's not much point in * logging that we're rejecting servers we'll not download.) */ static uint32_t dirserv_get_status_impl(const char *id_digest, const char *nickname, const char *address, uint32_t addr, uint16_t or_port, const char *platform, const char *contact, const char **msg, int should_log) { int reject_unlisted = get_options()->AuthDirRejectUnlisted; uint32_t result; router_status_t *status_by_digest; if (!fingerprint_list) fingerprint_list = authdir_config_new(); if (should_log) log_debug(LD_DIRSERV, "%d fingerprints, %d digests known.", strmap_size(fingerprint_list->fp_by_name), digestmap_size(fingerprint_list->status_by_digest)); /* Versions before Tor 0.2.2.35 have known security issues that * make them unsuitable for the current network. */ if (platform && !tor_version_as_new_as(platform,"0.2.2.35")) { if (msg) *msg = "Tor version is insecure or unsupported. Please upgrade!"; return FP_REJECT; } else if (platform && tor_version_as_new_as(platform,"0.2.3.0-alpha")) { /* Versions from 0.2.3-alpha...0.2.3.9-alpha have known security * issues that make them unusable for the current network */ if (!tor_version_as_new_as(platform, "0.2.3.10-alpha")) { if (msg) *msg = "Tor version is insecure or unsupported. Please upgrade!"; return FP_REJECT; } } result = dirserv_get_name_status(id_digest, nickname); if (result & FP_NAMED) { if (should_log) log_debug(LD_DIRSERV,"Good fingerprint for '%s'",nickname); } if (result & FP_UNNAMED) { if (should_log) { char *esc_contact = esc_for_log(contact); log_info(LD_DIRSERV, "Mismatched fingerprint for '%s'. " "ContactInfo '%s', platform '%s'.)", nickname, esc_contact, platform ? escaped(platform) : ""); tor_free(esc_contact); } if (msg) *msg = "Rejected: There is already a named server with this nickname " "and a different fingerprint."; } status_by_digest = digestmap_get(fingerprint_list->status_by_digest, id_digest); if (status_by_digest) result |= (status_by_digest->status & ~FP_NAMED); if (result & FP_REJECT) { if (msg) *msg = "Fingerprint is marked rejected"; return FP_REJECT; } else if (result & FP_INVALID) { if (msg) *msg = "Fingerprint is marked invalid"; } if (authdir_policy_baddir_address(addr, or_port)) { if (should_log) log_info(LD_DIRSERV, "Marking '%s' as bad directory because of address '%s'", nickname, address); result |= FP_BADDIR; } if (authdir_policy_badexit_address(addr, or_port)) { if (should_log) log_info(LD_DIRSERV, "Marking '%s' as bad exit because of address '%s'", nickname, address); result |= FP_BADEXIT; } if (!(result & FP_NAMED)) { if (!authdir_policy_permits_address(addr, or_port)) { if (should_log) log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'", nickname, address); if (msg) *msg = "Authdir is rejecting routers in this range."; return FP_REJECT; } if (!authdir_policy_valid_address(addr, or_port)) { if (should_log) log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'", nickname, address); result |= FP_INVALID; } if (reject_unlisted) { if (msg) *msg = "Authdir rejects unknown routers."; return FP_REJECT; } } return result; } /** If we are an authoritative dirserver, and the list of approved * servers contains one whose identity key digest is digest, * return that router's nickname. Otherwise return NULL. */ const char * dirserv_get_nickname_by_digest(const char *digest) { router_status_t *status; if (!fingerprint_list) return NULL; tor_assert(digest); status = digestmap_get(fingerprint_list->status_by_digest, digest); return status ? status->nickname : NULL; } /** Clear the current fingerprint list. */ void dirserv_free_fingerprint_list(void) { if (!fingerprint_list) return; strmap_free(fingerprint_list->fp_by_name, tor_free_); digestmap_free(fingerprint_list->status_by_digest, tor_free_); tor_free(fingerprint_list); } /* * Descriptor list */ /** Return -1 if ri has a private or otherwise bad address, * unless we're configured to not care. Return 0 if all ok. */ static int dirserv_router_has_valid_address(routerinfo_t *ri) { struct in_addr iaddr; if (get_options()->DirAllowPrivateAddresses) return 0; /* whatever it is, we're fine with it */ if (!tor_inet_aton(ri->address, &iaddr)) { log_info(LD_DIRSERV,"Router %s published non-IP address '%s'. Refusing.", router_describe(ri), ri->address); return -1; } if (is_internal_IP(ntohl(iaddr.s_addr), 0)) { log_info(LD_DIRSERV, "Router %s published internal IP address '%s'. Refusing.", router_describe(ri), ri->address); return -1; /* it's a private IP, we should reject it */ } return 0; } /** Check whether we, as a directory server, want to accept ri. If so, * set its is_valid,named,running fields and return 0. Otherwise, return -1. * * If the router is rejected, set *msg to an explanation of why. * * If complain then explain at log-level 'notice' why we refused * a descriptor; else explain at log-level 'info'. */ int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, int complain, int *valid_out) { /* Okay. Now check whether the fingerprint is recognized. */ uint32_t status = dirserv_router_get_status(ri, msg); time_t now; int severity = (complain && ri->contact_info) ? LOG_NOTICE : LOG_INFO; tor_assert(msg); if (status & FP_REJECT) return -1; /* msg is already set. */ /* Is there too much clock skew? */ now = time(NULL); if (ri->cache_info.published_on > now+ROUTER_ALLOW_SKEW) { log_fn(severity, LD_DIRSERV, "Publication time for %s is too " "far (%d minutes) in the future; possible clock skew. Not adding " "(%s)", router_describe(ri), (int)((ri->cache_info.published_on-now)/60), esc_router_info(ri)); *msg = "Rejected: Your clock is set too far in the future, or your " "timezone is not correct."; return -1; } if (ri->cache_info.published_on < now-ROUTER_MAX_AGE_TO_PUBLISH) { log_fn(severity, LD_DIRSERV, "Publication time for %s is too far " "(%d minutes) in the past. Not adding (%s)", router_describe(ri), (int)((now-ri->cache_info.published_on)/60), esc_router_info(ri)); *msg = "Rejected: Server is expired, or your clock is too far in the past," " or your timezone is not correct."; return -1; } if (dirserv_router_has_valid_address(ri) < 0) { log_fn(severity, LD_DIRSERV, "Router %s has invalid address '%s'. " "Not adding (%s).", router_describe(ri), ri->address, esc_router_info(ri)); *msg = "Rejected: Address is not an IP, or IP is a private address."; return -1; } *valid_out = ! (status & FP_INVALID); return 0; } /** Update the relevant flags of node based on our opinion as a * directory authority in authstatus, as returned by * dirserv_router_get_status or equivalent. */ void dirserv_set_node_flags_from_authoritative_status(node_t *node, uint32_t authstatus) { node->is_valid = (authstatus & FP_INVALID) ? 0 : 1; node->is_bad_directory = (authstatus & FP_BADDIR) ? 1 : 0; node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0; } /** True iff a is more severe than b. */ static int WRA_MORE_SEVERE(was_router_added_t a, was_router_added_t b) { return a < b; } /** As for dirserv_add_descriptor(), but accepts multiple documents, and * returns the most severe error that occurred for any one of them. */ was_router_added_t dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose, const char *source, const char **msg) { was_router_added_t r, r_tmp; const char *msg_out; smartlist_t *list; const char *s; int n_parsed = 0; time_t now = time(NULL); char annotation_buf[ROUTER_ANNOTATION_BUF_LEN]; char time_buf[ISO_TIME_LEN+1]; int general = purpose == ROUTER_PURPOSE_GENERAL; tor_assert(msg); r=ROUTER_ADDED_SUCCESSFULLY; /*Least severe return value. */ format_iso_time(time_buf, now); if (tor_snprintf(annotation_buf, sizeof(annotation_buf), "@uploaded-at %s\n" "@source %s\n" "%s%s%s", time_buf, escaped(source), !general ? "@purpose " : "", !general ? router_purpose_to_string(purpose) : "", !general ? "\n" : "")<0) { *msg = "Couldn't format annotations"; return -1; } s = desc; list = smartlist_new(); if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0, annotation_buf)) { SMARTLIST_FOREACH(list, routerinfo_t *, ri, { msg_out = NULL; tor_assert(ri->purpose == purpose); r_tmp = dirserv_add_descriptor(ri, &msg_out, source); if (WRA_MORE_SEVERE(r_tmp, r)) { r = r_tmp; *msg = msg_out; } }); } n_parsed += smartlist_len(list); smartlist_clear(list); s = desc; if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0, NULL)) { SMARTLIST_FOREACH(list, extrainfo_t *, ei, { msg_out = NULL; r_tmp = dirserv_add_extrainfo(ei, &msg_out); if (WRA_MORE_SEVERE(r_tmp, r)) { r = r_tmp; *msg = msg_out; } }); } n_parsed += smartlist_len(list); smartlist_free(list); if (! *msg) { if (!n_parsed) { *msg = "No descriptors found in your POST."; if (WRA_WAS_ADDED(r)) r = ROUTER_WAS_NOT_NEW; } else { *msg = "(no message)"; } } return r; } /** Examine the parsed server descriptor in ri and maybe insert it into * the list of server descriptors. Set *msg to a message that should be * passed back to the origin of this descriptor, or NULL if there is no such * message. Use source to produce better log messages. * * Return the status of the operation * * This function is only called when fresh descriptors are posted, not when * we re-load the cache. */ was_router_added_t dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source) { was_router_added_t r; routerinfo_t *ri_old; char *desc, *nickname; size_t desclen = 0; *msg = NULL; /* If it's too big, refuse it now. Otherwise we'll cache it all over the * network and it'll clog everything up. */ if (ri->cache_info.signed_descriptor_len > MAX_DESCRIPTOR_UPLOAD_SIZE) { log_notice(LD_DIR, "Somebody attempted to publish a router descriptor '%s'" " (source: %s) with size %d. Either this is an attack, or the " "MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.", ri->nickname, source, (int)ri->cache_info.signed_descriptor_len, MAX_DESCRIPTOR_UPLOAD_SIZE); *msg = "Router descriptor was too large."; control_event_or_authdir_new_descriptor("REJECTED", ri->cache_info.signed_descriptor_body, ri->cache_info.signed_descriptor_len, *msg); routerinfo_free(ri); return ROUTER_AUTHDIR_REJECTS; } /* Check whether this descriptor is semantically identical to the last one * from this server. (We do this here and not in router_add_to_routerlist * because we want to be able to accept the newest router descriptor that * another authority has, so we all converge on the same one.) */ ri_old = router_get_mutable_by_digest(ri->cache_info.identity_digest); if (ri_old && ri_old->cache_info.published_on < ri->cache_info.published_on && router_differences_are_cosmetic(ri_old, ri) && !router_is_me(ri)) { log_info(LD_DIRSERV, "Not replacing descriptor from %s (source: %s); " "differences are cosmetic.", router_describe(ri), source); *msg = "Not replacing router descriptor; no information has changed since " "the last one with this identity."; control_event_or_authdir_new_descriptor("DROPPED", ri->cache_info.signed_descriptor_body, ri->cache_info.signed_descriptor_len, *msg); routerinfo_free(ri); return ROUTER_WAS_NOT_NEW; } /* Make a copy of desc, since router_add_to_routerlist might free * ri and its associated signed_descriptor_t. */ desclen = ri->cache_info.signed_descriptor_len; desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen); nickname = tor_strdup(ri->nickname); /* Tell if we're about to need to launch a test if we add this. */ ri->needs_retest_if_added = dirserv_should_launch_reachability_test(ri, ri_old); r = router_add_to_routerlist(ri, msg, 0, 0); if (!WRA_WAS_ADDED(r)) { /* unless the routerinfo was fine, just out-of-date */ if (WRA_WAS_REJECTED(r)) control_event_or_authdir_new_descriptor("REJECTED", desc, desclen, *msg); log_info(LD_DIRSERV, "Did not add descriptor from '%s' (source: %s): %s.", nickname, source, *msg ? *msg : "(no message)"); } else { smartlist_t *changed; control_event_or_authdir_new_descriptor("ACCEPTED", desc, desclen, *msg); changed = smartlist_new(); smartlist_add(changed, ri); routerlist_descriptors_added(changed, 0); smartlist_free(changed); if (!*msg) { *msg = "Descriptor accepted"; } log_info(LD_DIRSERV, "Added descriptor from '%s' (source: %s): %s.", nickname, source, *msg); } tor_free(desc); tor_free(nickname); return r; } /** As dirserv_add_descriptor, but for an extrainfo_t ei. */ static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei, const char **msg) { const routerinfo_t *ri; int r; tor_assert(msg); *msg = NULL; ri = router_get_by_id_digest(ei->cache_info.identity_digest); if (!ri) { *msg = "No corresponding router descriptor for extra-info descriptor"; extrainfo_free(ei); return ROUTER_BAD_EI; } /* If it's too big, refuse it now. Otherwise we'll cache it all over the * network and it'll clog everything up. */ if (ei->cache_info.signed_descriptor_len > MAX_EXTRAINFO_UPLOAD_SIZE) { log_notice(LD_DIR, "Somebody attempted to publish an extrainfo " "with size %d. Either this is an attack, or the " "MAX_EXTRAINFO_UPLOAD_SIZE (%d) constant is too low.", (int)ei->cache_info.signed_descriptor_len, MAX_EXTRAINFO_UPLOAD_SIZE); *msg = "Extrainfo document was too large"; extrainfo_free(ei); return ROUTER_BAD_EI; } if ((r = routerinfo_incompatible_with_extrainfo(ri, ei, NULL, msg))) { extrainfo_free(ei); return r < 0 ? ROUTER_WAS_NOT_NEW : ROUTER_BAD_EI; } router_add_extrainfo_to_routerlist(ei, msg, 0, 0); return ROUTER_ADDED_SUCCESSFULLY; } /** Remove all descriptors whose nicknames or fingerprints no longer * are allowed by our fingerprint list. (Descriptors that used to be * good can become bad when we reload the fingerprint list.) */ static void directory_remove_invalid(void) { int changed = 0; routerlist_t *rl = router_get_routerlist(); smartlist_t *nodes = smartlist_new(); smartlist_add_all(nodes, nodelist_get_list()); SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) { const char *msg; routerinfo_t *ent = node->ri; char description[NODE_DESC_BUF_LEN]; uint32_t r; if (!ent) continue; r = dirserv_router_get_status(ent, &msg); router_get_description(description, ent); if (r & FP_REJECT) { log_info(LD_DIRSERV, "Router %s is now rejected: %s", description, msg?msg:""); routerlist_remove(rl, ent, 0, time(NULL)); changed = 1; continue; } #if 0 if (bool_neq((r & FP_NAMED), ent->auth_says_is_named)) { log_info(LD_DIRSERV, "Router %s is now %snamed.", description, (r&FP_NAMED)?"":"un"); ent->is_named = (r&FP_NAMED)?1:0; changed = 1; } if (bool_neq((r & FP_UNNAMED), ent->auth_says_is_unnamed)) { log_info(LD_DIRSERV, "Router '%s' is now %snamed. (FP_UNNAMED)", description, (r&FP_NAMED)?"":"un"); ent->is_named = (r&FP_NUNAMED)?0:1; changed = 1; } #endif if (bool_neq((r & FP_INVALID), !node->is_valid)) { log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description, (r&FP_INVALID) ? "in" : ""); node->is_valid = (r&FP_INVALID)?0:1; changed = 1; } if (bool_neq((r & FP_BADDIR), node->is_bad_directory)) { log_info(LD_DIRSERV, "Router '%s' is now a %s directory", description, (r & FP_BADDIR) ? "bad" : "good"); node->is_bad_directory = (r&FP_BADDIR) ? 1: 0; changed = 1; } if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) { log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description, (r & FP_BADEXIT) ? "bad" : "good"); node->is_bad_exit = (r&FP_BADEXIT) ? 1: 0; changed = 1; } } SMARTLIST_FOREACH_END(node); if (changed) directory_set_dirty(); routerlist_assert_ok(rl); smartlist_free(nodes); } /** Mark the directory as dirty -- when we're next asked for a * directory, we will rebuild it instead of reusing the most recently * generated one. */ void directory_set_dirty(void) { time_t now = time(NULL); int set_v1_dirty=0; /* Regenerate stubs only every 8 hours. * XXXX It would be nice to generate less often, but these are just * stubs: it doesn't matter. */ #define STUB_REGENERATE_INTERVAL (8*60*60) if (!the_directory || !the_runningrouters.dir) set_v1_dirty = 1; else if (the_directory->published < now - STUB_REGENERATE_INTERVAL || the_runningrouters.published < now - STUB_REGENERATE_INTERVAL) set_v1_dirty = 1; if (set_v1_dirty) { if (!the_directory_is_dirty) the_directory_is_dirty = now; if (!runningrouters_is_dirty) runningrouters_is_dirty = now; } if (!the_v2_networkstatus_is_dirty) the_v2_networkstatus_is_dirty = now; } /** * Allocate and return a description of the status of the server desc, * for use in a v1-style router-status line. The server is listed * as running iff is_live is true. */ static char * list_single_server_status(const routerinfo_t *desc, int is_live) { char buf[MAX_NICKNAME_LEN+HEX_DIGEST_LEN+4]; /* !nickname=$hexdigest\0 */ char *cp; const node_t *node; tor_assert(desc); cp = buf; if (!is_live) { *cp++ = '!'; } node = node_get_by_id(desc->cache_info.identity_digest); if (node && node->is_valid) { strlcpy(cp, desc->nickname, sizeof(buf)-(cp-buf)); cp += strlen(cp); *cp++ = '='; } *cp++ = '$'; base16_encode(cp, HEX_DIGEST_LEN+1, desc->cache_info.identity_digest, DIGEST_LEN); return tor_strdup(buf); } /* DOCDOC running_long_enough_to_decide_unreachable */ static INLINE int running_long_enough_to_decide_unreachable(void) { return time_of_process_start + get_options()->TestingAuthDirTimeToLearnReachability < approx_time(); } /** Each server needs to have passed a reachability test no more * than this number of seconds ago, or he is listed as down in * the directory. */ #define REACHABLE_TIMEOUT (45*60) /** If we tested a router and found it reachable _at least this long_ after it * declared itself hibernating, it is probably done hibernating and we just * missed a descriptor from it. */ #define HIBERNATION_PUBLICATION_SKEW (60*60) /** Treat a router as alive if * - It's me, and I'm not hibernating. * or - We've found it reachable recently. */ void dirserv_set_router_is_running(routerinfo_t *router, time_t now) { /*XXXX024 This function is a mess. Separate out the part that calculates whether it's reachable and the part that tells rephist that the router was unreachable. */ int answer; const or_options_t *options = get_options(); node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest); tor_assert(node); if (router_is_me(router)) { /* We always know if we are down ourselves. */ answer = ! we_are_hibernating(); } else if (router->is_hibernating && (router->cache_info.published_on + HIBERNATION_PUBLICATION_SKEW) > node->last_reachable) { /* A hibernating router is down unless we (somehow) had contact with it * since it declared itself to be hibernating. */ answer = 0; } else if (options->AssumeReachable) { /* If AssumeReachable, everybody is up unless they say they are down! */ answer = 1; } else { /* Otherwise, a router counts as up if we found all announced OR ports reachable in the last REACHABLE_TIMEOUT seconds. XXX prop186 For now there's always one IPv4 and at most one IPv6 OR port. If we're not on IPv6, don't consider reachability of potential IPv6 OR port since that'd kill all dual stack relays until a majority of the dir auths have IPv6 connectivity. */ answer = (now < node->last_reachable + REACHABLE_TIMEOUT && (options->AuthDirHasIPv6Connectivity != 1 || tor_addr_is_null(&router->ipv6_addr) || now < node->last_reachable6 + REACHABLE_TIMEOUT)); } if (!answer && running_long_enough_to_decide_unreachable()) { /* Not considered reachable. tell rephist about that. Because we launch a reachability test for each router every REACHABILITY_TEST_CYCLE_PERIOD seconds, then the router has probably been down since at least that time after we last successfully reached it. XXX ipv6 */ time_t when = now; if (node->last_reachable && node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now) when = node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD; rep_hist_note_router_unreachable(router->cache_info.identity_digest, when); } node->is_running = answer; } /** Based on the routerinfo_ts in routers, allocate the * contents of a v1-style router-status line, and store it in * *router_status_out. Return 0 on success, -1 on failure. * * If for_controller is true, include the routers with very old descriptors. */ int list_server_status_v1(smartlist_t *routers, char **router_status_out, int for_controller) { /* List of entries in a router-status style: An optional !, then an optional * equals-suffixed nickname, then a dollar-prefixed hexdigest. */ smartlist_t *rs_entries; time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; const or_options_t *options = get_options(); /* We include v2 dir auths here too, because they need to answer * controllers. Eventually we'll deprecate this whole function; * see also networkstatus_getinfo_by_purpose(). */ int authdir = authdir_mode_publishes_statuses(options); tor_assert(router_status_out); rs_entries = smartlist_new(); SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { const node_t *node = node_get_by_id(ri->cache_info.identity_digest); tor_assert(node); if (authdir) { /* Update router status in routerinfo_t. */ dirserv_set_router_is_running(ri, now); } if (for_controller) { char name_buf[MAX_VERBOSE_NICKNAME_LEN+2]; char *cp = name_buf; if (!node->is_running) *cp++ = '!'; router_get_verbose_nickname(cp, ri); smartlist_add(rs_entries, tor_strdup(name_buf)); } else if (ri->cache_info.published_on >= cutoff) { smartlist_add(rs_entries, list_single_server_status(ri, node->is_running)); } } SMARTLIST_FOREACH_END(ri); *router_status_out = smartlist_join_strings(rs_entries, " ", 0, NULL); SMARTLIST_FOREACH(rs_entries, char *, cp, tor_free(cp)); smartlist_free(rs_entries); return 0; } /** Given a (possibly empty) list of config_line_t, each line of which contains * a list of comma-separated version numbers surrounded by optional space, * allocate and return a new string containing the version numbers, in order, * separated by commas. Used to generate Recommended(Client|Server)?Versions */ static char * format_versions_list(config_line_t *ln) { smartlist_t *versions; char *result; versions = smartlist_new(); for ( ; ln; ln = ln->next) { smartlist_split_string(versions, ln->value, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); } sort_version_list(versions, 1); result = smartlist_join_strings(versions,",",0,NULL); SMARTLIST_FOREACH(versions,char *,s,tor_free(s)); smartlist_free(versions); return result; } /** Return 1 if ri's descriptor is "active" -- running, valid, * not hibernating, and not too old. Else return 0. */ static int router_is_active(const routerinfo_t *ri, const node_t *node, time_t now) { time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; if (ri->cache_info.published_on < cutoff) return 0; if (!node->is_running || !node->is_valid || ri->is_hibernating) return 0; return 1; } /** Generate a new v1 directory and write it into a newly allocated string. * Point *dir_out to the allocated string. Sign the * directory with private_key. Return 0 on success, -1 on * failure. If complete is set, give us all the descriptors; * otherwise leave out non-running and non-valid ones. */ int dirserv_dump_directory_to_string(char **dir_out, crypto_pk_t *private_key) { /* XXXX 024 Get rid of this function if we can confirm that nobody's * fetching these any longer */ char *cp; char *identity_pkey; /* Identity key, DER64-encoded. */ char *recommended_versions; char digest[DIGEST_LEN]; char published[ISO_TIME_LEN+1]; char *buf = NULL; size_t buf_len; size_t identity_pkey_len; time_t now = time(NULL); tor_assert(dir_out); *dir_out = NULL; if (crypto_pk_write_public_key_to_string(private_key,&identity_pkey, &identity_pkey_len)<0) { log_warn(LD_BUG,"write identity_pkey to string failed!"); return -1; } recommended_versions = format_versions_list(get_options()->RecommendedVersions); format_iso_time(published, now); buf_len = 2048+strlen(recommended_versions); buf = tor_malloc(buf_len); /* We'll be comparing against buf_len throughout the rest of the function, though strictly speaking we shouldn't be able to exceed it. This is C, after all, so we may as well check for buffer overruns.*/ tor_snprintf(buf, buf_len, "signed-directory\n" "published %s\n" "recommended-software %s\n" "router-status %s\n" "dir-signing-key\n%s\n", published, recommended_versions, "", identity_pkey); tor_free(recommended_versions); tor_free(identity_pkey); cp = buf + strlen(buf); *cp = '\0'; /* These multiple strlcat calls are inefficient, but dwarfed by the RSA signature. */ if (strlcat(buf, "directory-signature ", buf_len) >= buf_len) goto truncated; if (strlcat(buf, get_options()->Nickname, buf_len) >= buf_len) goto truncated; if (strlcat(buf, "\n", buf_len) >= buf_len) goto truncated; if (router_get_dir_hash(buf,digest)) { log_warn(LD_BUG,"couldn't compute digest"); tor_free(buf); return -1; } note_crypto_pk_op(SIGN_DIR); if (router_append_dirobj_signature(buf,buf_len,digest,DIGEST_LEN, private_key)<0) { tor_free(buf); return -1; } *dir_out = buf; return 0; truncated: log_warn(LD_BUG,"tried to exceed string length."); tor_free(buf); return -1; } /********************************************************************/ /* A set of functions to answer questions about how we'd like to behave * as a directory mirror/client. */ /** Return 1 if we fetch our directory material directly from the * authorities, rather than from a mirror. */ int directory_fetches_from_authorities(const or_options_t *options) { const routerinfo_t *me; uint32_t addr; int refuseunknown; if (options->FetchDirInfoEarly) return 1; if (options->BridgeRelay == 1) return 0; if (server_mode(options) && router_pick_published_address(options, &addr)<0) return 1; /* we don't know our IP address; ask an authority. */ refuseunknown = ! router_my_exit_policy_is_reject_star() && should_refuse_unknown_exits(options); if (!options->DirPort_set && !refuseunknown) return 0; if (!server_mode(options) || !advertised_server_mode()) return 0; me = router_get_my_routerinfo(); if (!me || (!me->dir_port && !refuseunknown)) return 0; /* if dirport not advertised, return 0 too */ return 1; } /** Return 1 if we should fetch new networkstatuses, descriptors, etc * on the "mirror" schedule rather than the "client" schedule. */ int directory_fetches_dir_info_early(const or_options_t *options) { return directory_fetches_from_authorities(options); } /** Return 1 if we should fetch new networkstatuses, descriptors, etc * on a very passive schedule -- waiting long enough for ordinary clients * to probably have the info we want. These would include bridge users, * and maybe others in the future e.g. if a Tor client uses another Tor * client as a directory guard. */ int directory_fetches_dir_info_later(const or_options_t *options) { return options->UseBridges != 0; } /** Return 1 if we want to cache v2 dir info (each status file). */ int directory_caches_v2_dir_info(const or_options_t *options) { return options->DirPort_set; } /** Return true iff we want to fetch and keep certificates for authorities * that we don't acknowledge as aurthorities ourself. */ int directory_caches_unknown_auth_certs(const or_options_t *options) { return options->DirPort_set || options->BridgeRelay; } /** Return 1 if we want to keep descriptors, networkstatuses, etc around * and we're willing to serve them to others. Else return 0. */ int directory_caches_dir_info(const or_options_t *options) { if (options->BridgeRelay || options->DirPort_set) return 1; if (!server_mode(options) || !advertised_server_mode()) return 0; /* We need an up-to-date view of network info if we're going to try to * block exit attempts from unknown relays. */ return ! router_my_exit_policy_is_reject_star() && should_refuse_unknown_exits(options); } /** Return 1 if we want to allow remote people to ask us directory * requests via the "begin_dir" interface, which doesn't require * having any separate port open. */ int directory_permits_begindir_requests(const or_options_t *options) { return options->BridgeRelay != 0 || options->DirPort_set; } /** Return 1 if we want to allow controllers to ask us directory * requests via the controller interface, which doesn't require * having any separate port open. */ int directory_permits_controller_requests(const or_options_t *options) { return options->DirPort_set; } /** Return 1 if we have no need to fetch new descriptors. This generally * happens when we're not a dir cache and we haven't built any circuits * lately. */ int directory_too_idle_to_fetch_descriptors(const or_options_t *options, time_t now) { return !directory_caches_dir_info(options) && !options->FetchUselessDescriptors && rep_hist_circbuilding_dormant(now); } /********************************************************************/ /* Used only by non-v1-auth dirservers: The v1 directory and * runningrouters we'll serve when requested. */ /** The v1 directory we'll serve (as a cache or as an authority) if * requested. */ static cached_dir_t *cached_directory = NULL; /** The v1 runningrouters document we'll serve (as a cache or as an authority) * if requested. */ static cached_dir_t cached_runningrouters; /** Used for other dirservers' v2 network statuses. Map from hexdigest to * cached_dir_t. */ static digestmap_t *cached_v2_networkstatus = NULL; /** Map from flavor name to the cached_dir_t for the v3 consensuses that we're * currently serving. */ static strmap_t *cached_consensuses = NULL; /** Possibly replace the contents of d with the value of * directory published on when, unless when is older than * the last value, or too far in the future. * * Does not copy directory; frees it if it isn't used. */ static void set_cached_dir(cached_dir_t *d, char *directory, time_t when) { time_t now = time(NULL); if (when<=d->published) { log_info(LD_DIRSERV, "Ignoring old directory; not caching."); tor_free(directory); } else if (when>=now+ROUTER_MAX_AGE_TO_PUBLISH) { log_info(LD_DIRSERV, "Ignoring future directory; not caching."); tor_free(directory); } else { /* if (when>d->published && whendir); d->dir = directory; d->dir_len = strlen(directory); tor_free(d->dir_z); if (tor_gzip_compress(&(d->dir_z), &(d->dir_z_len), d->dir, d->dir_len, ZLIB_METHOD)) { log_warn(LD_BUG,"Error compressing cached directory"); } d->published = when; } } /** Decrement the reference count on d, and free it if it no longer has * any references. */ void cached_dir_decref(cached_dir_t *d) { if (!d || --d->refcnt > 0) return; clear_cached_dir(d); tor_free(d); } /** Allocate and return a new cached_dir_t containing the string s, * published at published. */ cached_dir_t * new_cached_dir(char *s, time_t published) { cached_dir_t *d = tor_malloc_zero(sizeof(cached_dir_t)); d->refcnt = 1; d->dir = s; d->dir_len = strlen(s); d->published = published; if (tor_gzip_compress(&(d->dir_z), &(d->dir_z_len), d->dir, d->dir_len, ZLIB_METHOD)) { log_warn(LD_BUG, "Error compressing directory"); } return d; } /** Remove all storage held in d, but do not free d itself. */ static void clear_cached_dir(cached_dir_t *d) { tor_free(d->dir); tor_free(d->dir_z); memset(d, 0, sizeof(cached_dir_t)); } /** Free all storage held by the cached_dir_t in d. */ static void free_cached_dir_(void *_d) { cached_dir_t *d; if (!_d) return; d = (cached_dir_t *)_d; cached_dir_decref(d); } /** If we have no cached v1 directory, or it is older than published, * then replace it with directory, published at published. * * If published is too old, do nothing. * * If is_running_routers, this is really a v1 running_routers * document rather than a v1 directory. */ static void dirserv_set_cached_directory(const char *directory, time_t published) { cached_dir_decref(cached_directory); cached_directory = new_cached_dir(tor_strdup(directory), published); } /** If networkstatus is non-NULL, we've just received a v2 * network-status for an authoritative directory with identity digest * identity published at published -- store it so we can * serve it to others. * * If networkstatus is NULL, remove the entry with the given * identity fingerprint from the v2 cache. */ void dirserv_set_cached_networkstatus_v2(const char *networkstatus, const char *identity, time_t published) { cached_dir_t *d, *old_d; if (!cached_v2_networkstatus) cached_v2_networkstatus = digestmap_new(); old_d = digestmap_get(cached_v2_networkstatus, identity); if (!old_d && !networkstatus) return; if (networkstatus) { if (!old_d || published > old_d->published) { d = new_cached_dir(tor_strdup(networkstatus), published); digestmap_set(cached_v2_networkstatus, identity, d); if (old_d) cached_dir_decref(old_d); } } else { if (old_d) { digestmap_remove(cached_v2_networkstatus, identity); cached_dir_decref(old_d); } } /* Now purge old entries. */ if (digestmap_size(cached_v2_networkstatus) > get_n_authorities(V2_DIRINFO) + MAX_UNTRUSTED_NETWORKSTATUSES) { /* We need to remove the oldest untrusted networkstatus. */ const char *oldest = NULL; time_t oldest_published = TIME_MAX; digestmap_iter_t *iter; for (iter = digestmap_iter_init(cached_v2_networkstatus); !digestmap_iter_done(iter); iter = digestmap_iter_next(cached_v2_networkstatus, iter)) { const char *ident; void *val; digestmap_iter_get(iter, &ident, &val); d = val; if (d->published < oldest_published && !router_digest_is_trusted_dir(ident)) { oldest = ident; oldest_published = d->published; } } tor_assert(oldest); d = digestmap_remove(cached_v2_networkstatus, oldest); if (d) cached_dir_decref(d); } } /** Replace the v3 consensus networkstatus of type flavor_name that * we're serving with networkstatus, published at published. No * validation is performed. */ void dirserv_set_cached_consensus_networkstatus(const char *networkstatus, const char *flavor_name, const digests_t *digests, time_t published) { cached_dir_t *new_networkstatus; cached_dir_t *old_networkstatus; if (!cached_consensuses) cached_consensuses = strmap_new(); new_networkstatus = new_cached_dir(tor_strdup(networkstatus), published); memcpy(&new_networkstatus->digests, digests, sizeof(digests_t)); old_networkstatus = strmap_set(cached_consensuses, flavor_name, new_networkstatus); if (old_networkstatus) cached_dir_decref(old_networkstatus); } /** Remove any v2 networkstatus from the directory cache that was published * before cutoff. */ void dirserv_clear_old_networkstatuses(time_t cutoff) { if (!cached_v2_networkstatus) return; DIGESTMAP_FOREACH_MODIFY(cached_v2_networkstatus, id, cached_dir_t *, dir) { if (dir->published < cutoff) { char *fname; fname = networkstatus_get_cache_filename(id); if (file_status(fname) == FN_FILE) { log_info(LD_DIR, "Removing too-old untrusted networkstatus in %s", fname); unlink(fname); } tor_free(fname); cached_dir_decref(dir); MAP_DEL_CURRENT(id); } } DIGESTMAP_FOREACH_END } /** Remove any v1 info from the directory cache that was published * too long ago. */ void dirserv_clear_old_v1_info(time_t now) { if (cached_directory && cached_directory->published < (now - MAX_V1_DIRECTORY_AGE)) { cached_dir_decref(cached_directory); cached_directory = NULL; } if (cached_runningrouters.published < (now - MAX_V1_RR_AGE)) { clear_cached_dir(&cached_runningrouters); } } /** Helper: If we're an authority for the right directory version (v1 or v2) * (based on auth_type), try to regenerate * auth_src as appropriate and return it, falling back to cache_src on * failure. If we're a cache, simply return cache_src. */ static cached_dir_t * dirserv_pick_cached_dir_obj(cached_dir_t *cache_src, cached_dir_t *auth_src, time_t dirty, cached_dir_t *(*regenerate)(void), const char *name, dirinfo_type_t auth_type) { const or_options_t *options = get_options(); int authority = (auth_type == V1_DIRINFO && authdir_mode_v1(options)) || (auth_type == V2_DIRINFO && authdir_mode_v2(options)); if (!authority || authdir_mode_bridge(options)) { return cache_src; } else { /* We're authoritative. */ if (regenerate != NULL) { if (dirty && dirty + DIR_REGEN_SLACK_TIME < time(NULL)) { if (!(auth_src = regenerate())) { log_err(LD_BUG, "Couldn't generate %s?", name); exit(1); } } else { log_info(LD_DIRSERV, "The %s is still clean; reusing.", name); } } return auth_src ? auth_src : cache_src; } } /** Return the most recently generated encoded signed v1 directory, * generating a new one as necessary. If not a v1 authoritative directory * may return NULL if no directory is yet cached. */ cached_dir_t * dirserv_get_directory(void) { return dirserv_pick_cached_dir_obj(cached_directory, the_directory, the_directory_is_dirty, dirserv_regenerate_directory, "v1 server directory", V1_DIRINFO); } /** Only called by v1 auth dirservers. * Generate a fresh v1 directory; set the_directory and return a pointer * to the new value. */ static cached_dir_t * dirserv_regenerate_directory(void) { /* XXXX 024 Get rid of this function if we can confirm that nobody's * fetching these any longer */ char *new_directory=NULL; if (dirserv_dump_directory_to_string(&new_directory, get_server_identity_key())) { log_warn(LD_BUG, "Error creating directory."); tor_free(new_directory); return NULL; } cached_dir_decref(the_directory); the_directory = new_cached_dir(new_directory, time(NULL)); log_info(LD_DIRSERV,"New directory (size %d) has been built.", (int)the_directory->dir_len); log_debug(LD_DIRSERV,"New directory (size %d):\n%s", (int)the_directory->dir_len, the_directory->dir); the_directory_is_dirty = 0; /* Save the directory to disk so we re-load it quickly on startup. */ dirserv_set_cached_directory(the_directory->dir, time(NULL)); return the_directory; } /** Only called by v1 auth dirservers. * Replace the current running-routers list with a newly generated one. */ static cached_dir_t * generate_runningrouters(void) { char *s=NULL; char digest[DIGEST_LEN]; char published[ISO_TIME_LEN+1]; size_t len; crypto_pk_t *private_key = get_server_identity_key(); char *identity_pkey; /* Identity key, DER64-encoded. */ size_t identity_pkey_len; if (crypto_pk_write_public_key_to_string(private_key,&identity_pkey, &identity_pkey_len)<0) { log_warn(LD_BUG,"write identity_pkey to string failed!"); goto err; } format_iso_time(published, time(NULL)); len = 2048; s = tor_malloc_zero(len); tor_snprintf(s, len, "network-status\n" "published %s\n" "router-status %s\n" "dir-signing-key\n%s" "directory-signature %s\n", published, "", identity_pkey, get_options()->Nickname); tor_free(identity_pkey); if (router_get_runningrouters_hash(s,digest)) { log_warn(LD_BUG,"couldn't compute digest"); goto err; } note_crypto_pk_op(SIGN_DIR); if (router_append_dirobj_signature(s, len, digest, DIGEST_LEN, private_key)<0) goto err; set_cached_dir(&the_runningrouters, s, time(NULL)); runningrouters_is_dirty = 0; return &the_runningrouters; err: tor_free(s); return NULL; } /** Set *rr to the most recently generated encoded signed * running-routers list, generating a new one as necessary. Return the * size of the directory on success, and 0 on failure. */ cached_dir_t * dirserv_get_runningrouters(void) { return dirserv_pick_cached_dir_obj( &cached_runningrouters, &the_runningrouters, runningrouters_is_dirty, generate_runningrouters, "v1 network status list", V1_DIRINFO); } /** Return the latest downloaded consensus networkstatus in encoded, signed, * optionally compressed format, suitable for sending to clients. */ cached_dir_t * dirserv_get_consensus(const char *flavor_name) { if (!cached_consensuses) return NULL; return strmap_get(cached_consensuses, flavor_name); } /** For authoritative directories: the current (v2) network status. */ static cached_dir_t *the_v2_networkstatus = NULL; /** Return true iff our opinion of the routers has been stale for long * enough that we should generate a new v2 network status doc. */ static int should_generate_v2_networkstatus(void) { return authdir_mode_v2(get_options()) && the_v2_networkstatus_is_dirty && the_v2_networkstatus_is_dirty + DIR_REGEN_SLACK_TIME < time(NULL); } /** If a router's uptime is at least this value, then it is always * considered stable, regardless of the rest of the network. This * way we resist attacks where an attacker doubles the size of the * network using allegedly high-uptime nodes, displacing all the * current guards. */ #define UPTIME_TO_GUARANTEE_STABLE (3600*24*30) /** If a router's MTBF is at least this value, then it is always stable. * See above. (Corresponds to about 7 days for current decay rates.) */ #define MTBF_TO_GUARANTEE_STABLE (60*60*24*5) /** Similarly, every node with at least this much weighted time known can be * considered familiar enough to be a guard. Corresponds to about 20 days for * current decay rates. */ #define TIME_KNOWN_TO_GUARANTEE_FAMILIAR (8*24*60*60) /** Similarly, every node with sufficient WFU is around enough to be a guard. */ #define WFU_TO_GUARANTEE_GUARD (0.98) /* Thresholds for server performance: set by * dirserv_compute_performance_thresholds, and used by * generate_v2_networkstatus */ /** Any router with an uptime of at least this value is stable. */ static uint32_t stable_uptime = 0; /* start at a safe value */ /** Any router with an mtbf of at least this value is stable. */ static double stable_mtbf = 0.0; /** If true, we have measured enough mtbf info to look at stable_mtbf rather * than stable_uptime. */ static int enough_mtbf_info = 0; /** Any router with a weighted fractional uptime of at least this much might * be good as a guard. */ static double guard_wfu = 0.0; /** Don't call a router a guard unless we've known about it for at least this * many seconds. */ static long guard_tk = 0; /** Any router with a bandwidth at least this high is "Fast" */ static uint32_t fast_bandwidth_kb = 0; /** If exits can be guards, then all guards must have a bandwidth this * high. */ static uint32_t guard_bandwidth_including_exits_kb = 0; /** If exits can't be guards, then all guards must have a bandwidth this * high. */ static uint32_t guard_bandwidth_excluding_exits_kb = 0; /** Helper: estimate the uptime of a router given its stated uptime and the * amount of time since it last stated its stated uptime. */ static INLINE long real_uptime(const routerinfo_t *router, time_t now) { if (now < router->cache_info.published_on) return router->uptime; else return router->uptime + (now - router->cache_info.published_on); } /** Return 1 if router is not suitable for these parameters, else 0. * If need_uptime is non-zero, we require a minimum uptime. * If need_capacity is non-zero, we require a minimum advertised * bandwidth. */ static int dirserv_thinks_router_is_unreliable(time_t now, routerinfo_t *router, int need_uptime, int need_capacity) { if (need_uptime) { if (!enough_mtbf_info) { /* XXX024 Once most authorities are on v3, we should change the rule from * "use uptime if we don't have mtbf data" to "don't advertise Stable on * v3 if we don't have enough mtbf data." Or maybe not, since if we ever * hit a point where we need to reset a lot of authorities at once, * none of them would be in a position to declare Stable. */ long uptime = real_uptime(router, now); if ((unsigned)uptime < stable_uptime && (unsigned)uptime < UPTIME_TO_GUARANTEE_STABLE) return 1; } else { double mtbf = rep_hist_get_stability(router->cache_info.identity_digest, now); if (mtbf < stable_mtbf && mtbf < MTBF_TO_GUARANTEE_STABLE) return 1; } } if (need_capacity) { uint32_t bw_kb = dirserv_get_credible_bandwidth_kb(router); if (bw_kb < fast_bandwidth_kb) return 1; } return 0; } /** Return true iff router should be assigned the "HSDir" flag. * Right now this means it advertises support for it, it has a high * uptime, it has a DirPort open, and it's currently considered Running. * * This function needs to be called after router-\>is_running has * been set. */ static int dirserv_thinks_router_is_hs_dir(const routerinfo_t *router, const node_t *node, time_t now) { long uptime; /* If we haven't been running for at least * get_options()->MinUptimeHidServDirectoryV2 seconds, we can't * have accurate data telling us a relay has been up for at least * that long. We also want to allow a bit of slack: Reachability * tests aren't instant. If we haven't been running long enough, * trust the relay. */ if (stats_n_seconds_working > get_options()->MinUptimeHidServDirectoryV2 * 1.1) uptime = MIN(rep_hist_get_uptime(router->cache_info.identity_digest, now), real_uptime(router, now)); else uptime = real_uptime(router, now); /* XXX We shouldn't need to check dir_port, but we do because of * bug 1693. In the future, once relays set wants_to_be_hs_dir * correctly, we can revert to only checking dir_port if router's * version is too old. */ /* XXX Unfortunately, we need to keep checking dir_port until all * *clients* suffering from bug 2722 are obsolete. The first version * to fix the bug was 0.2.2.25-alpha. */ return (router->wants_to_be_hs_dir && router->dir_port && uptime >= get_options()->MinUptimeHidServDirectoryV2 && node->is_running); } /** Don't consider routers with less bandwidth than this when computing * thresholds. */ #define ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB 4 /** Helper for dirserv_compute_performance_thresholds(): Decide whether to * include a router in our calculations, and return true iff we should; the * require_mbw parameter is passed in by * dirserv_compute_performance_thresholds() and controls whether we ever * count routers with only advertised bandwidths */ static int router_counts_toward_thresholds(const node_t *node, time_t now, const digestmap_t *omit_as_sybil, int require_mbw) { /* Have measured bw? */ int have_mbw = dirserv_has_measured_bw(node->identity); uint64_t min_bw_kb = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB; const or_options_t *options = get_options(); if (options->TestingTorNetwork) { min_bw_kb = (int64_t)options->TestingMinExitFlagThreshold / 1000; } return node->ri && router_is_active(node->ri, node, now) && !digestmap_get(omit_as_sybil, node->identity) && (dirserv_get_credible_bandwidth_kb(node->ri) >= min_bw_kb) && (have_mbw || !require_mbw); } /** Look through the routerlist, the Mean Time Between Failure history, and * the Weighted Fractional Uptime history, and use them to set thresholds for * the Stable, Fast, and Guard flags. Update the fields stable_uptime, * stable_mtbf, enough_mtbf_info, guard_wfu, guard_tk, fast_bandwidth, * guard_bandwidh_including_exits, guard_bandwidth_excluding_exits, * * Also, set the is_exit flag of each router appropriately. */ static void dirserv_compute_performance_thresholds(routerlist_t *rl, digestmap_t *omit_as_sybil) { int n_active, n_active_nonexit, n_familiar; uint32_t *uptimes, *bandwidths_kb, *bandwidths_excluding_exits_kb; long *tks; double *mtbfs, *wfus; time_t now = time(NULL); const or_options_t *options = get_options(); /* Require mbw? */ int require_mbw = (routers_with_measured_bw > options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0; /* initialize these all here, in case there are no routers */ stable_uptime = 0; stable_mtbf = 0; fast_bandwidth_kb = 0; guard_bandwidth_including_exits_kb = 0; guard_bandwidth_excluding_exits_kb = 0; guard_tk = 0; guard_wfu = 0; /* Initialize arrays that will hold values for each router. We'll * sort them and use that to compute thresholds. */ n_active = n_active_nonexit = 0; /* Uptime for every active router. */ uptimes = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); /* Bandwidth for every active router. */ bandwidths_kb = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); /* Bandwidth for every active non-exit router. */ bandwidths_excluding_exits_kb = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); /* Weighted mean time between failure for each active router. */ mtbfs = tor_malloc(sizeof(double)*smartlist_len(rl->routers)); /* Time-known for each active router. */ tks = tor_malloc(sizeof(long)*smartlist_len(rl->routers)); /* Weighted fractional uptime for each active router. */ wfus = tor_malloc(sizeof(double)*smartlist_len(rl->routers)); nodelist_assert_ok(); /* Now, fill in the arrays. */ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { if (router_counts_toward_thresholds(node, now, omit_as_sybil, require_mbw)) { routerinfo_t *ri = node->ri; const char *id = node->identity; uint32_t bw_kb; node->is_exit = (!router_exit_policy_rejects_all(ri) && exit_policy_is_general_exit(ri->exit_policy)); uptimes[n_active] = (uint32_t)real_uptime(ri, now); mtbfs[n_active] = rep_hist_get_stability(id, now); tks [n_active] = rep_hist_get_weighted_time_known(id, now); bandwidths_kb[n_active] = bw_kb = dirserv_get_credible_bandwidth_kb(ri); if (!node->is_exit || node->is_bad_exit) { bandwidths_excluding_exits_kb[n_active_nonexit] = bw_kb; ++n_active_nonexit; } ++n_active; } } SMARTLIST_FOREACH_END(node); /* Now, compute thresholds. */ if (n_active) { /* The median uptime is stable. */ stable_uptime = median_uint32(uptimes, n_active); /* The median mtbf is stable, if we have enough mtbf info */ stable_mtbf = median_double(mtbfs, n_active); /* The 12.5th percentile bandwidth is fast. */ fast_bandwidth_kb = find_nth_uint32(bandwidths_kb, n_active, n_active/8); /* (Now bandwidths is sorted.) */ if (fast_bandwidth_kb < ROUTER_REQUIRED_MIN_BANDWIDTH/(2 * 1000)) fast_bandwidth_kb = bandwidths_kb[n_active/4]; guard_bandwidth_including_exits_kb = bandwidths_kb[(n_active-1)/2]; guard_tk = find_nth_long(tks, n_active, n_active/8); } if (guard_tk > TIME_KNOWN_TO_GUARANTEE_FAMILIAR) guard_tk = TIME_KNOWN_TO_GUARANTEE_FAMILIAR; { /* We can vote on a parameter for the minimum and maximum. */ #define ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG 4 int32_t min_fast_kb, max_fast_kb, min_fast, max_fast; min_fast = networkstatus_get_param(NULL, "FastFlagMinThreshold", ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, INT32_MAX); if (options->TestingTorNetwork) { min_fast = (int32_t)options->TestingMinFastFlagThreshold; } max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold", INT32_MAX, min_fast, INT32_MAX); min_fast_kb = min_fast / 1000; max_fast_kb = max_fast / 1000; if (fast_bandwidth_kb < (uint32_t)min_fast_kb) fast_bandwidth_kb = min_fast_kb; if (fast_bandwidth_kb > (uint32_t)max_fast_kb) fast_bandwidth_kb = max_fast_kb; } /* Protect sufficiently fast nodes from being pushed out of the set * of Fast nodes. */ if (options->AuthDirFastGuarantee && fast_bandwidth_kb > options->AuthDirFastGuarantee/1000) fast_bandwidth_kb = (uint32_t)options->AuthDirFastGuarantee/1000; /* Now that we have a time-known that 7/8 routers are known longer than, * fill wfus with the wfu of every such "familiar" router. */ n_familiar = 0; SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { if (router_counts_toward_thresholds(node, now, omit_as_sybil, require_mbw)) { routerinfo_t *ri = node->ri; const char *id = ri->cache_info.identity_digest; long tk = rep_hist_get_weighted_time_known(id, now); if (tk < guard_tk) continue; wfus[n_familiar++] = rep_hist_get_weighted_fractional_uptime(id, now); } } SMARTLIST_FOREACH_END(node); if (n_familiar) guard_wfu = median_double(wfus, n_familiar); if (guard_wfu > WFU_TO_GUARANTEE_GUARD) guard_wfu = WFU_TO_GUARANTEE_GUARD; enough_mtbf_info = rep_hist_have_measured_enough_stability(); if (n_active_nonexit) { guard_bandwidth_excluding_exits_kb = median_uint32(bandwidths_excluding_exits_kb, n_active_nonexit); } log_info(LD_DIRSERV, "Cutoffs: For Stable, %lu sec uptime, %lu sec MTBF. " "For Fast: %lu kilobytes/sec. " "For Guard: WFU %.03f%%, time-known %lu sec, " "and bandwidth %lu or %lu kilobytes/sec. " "We%s have enough stability data.", (unsigned long)stable_uptime, (unsigned long)stable_mtbf, (unsigned long)fast_bandwidth_kb, guard_wfu*100, (unsigned long)guard_tk, (unsigned long)guard_bandwidth_including_exits_kb, (unsigned long)guard_bandwidth_excluding_exits_kb, enough_mtbf_info ? "" : " don't "); tor_free(uptimes); tor_free(mtbfs); tor_free(bandwidths_kb); tor_free(bandwidths_excluding_exits_kb); tor_free(tks); tor_free(wfus); } /** Measured bandwidth cache entry */ typedef struct mbw_cache_entry_s { long mbw_kb; time_t as_of; } mbw_cache_entry_t; /** Measured bandwidth cache - keys are identity_digests, values are * mbw_cache_entry_t *. */ static digestmap_t *mbw_cache = NULL; /** Store a measured bandwidth cache entry when reading the measured * bandwidths file. */ void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, time_t as_of) { mbw_cache_entry_t *e = NULL; tor_assert(parsed_line); /* Allocate a cache if we need */ if (!mbw_cache) mbw_cache = digestmap_new(); /* Check if we have an existing entry */ e = digestmap_get(mbw_cache, parsed_line->node_id); /* If we do, we can re-use it */ if (e) { /* Check that we really are newer, and update */ if (as_of > e->as_of) { e->mbw_kb = parsed_line->bw_kb; e->as_of = as_of; } } else { /* We'll have to insert a new entry */ e = tor_malloc(sizeof(*e)); e->mbw_kb = parsed_line->bw_kb; e->as_of = as_of; digestmap_set(mbw_cache, parsed_line->node_id, e); } } /** Clear and free the measured bandwidth cache */ void dirserv_clear_measured_bw_cache(void) { if (mbw_cache) { /* Free the map and all entries */ digestmap_free(mbw_cache, tor_free_); mbw_cache = NULL; } } /** Scan the measured bandwidth cache and remove expired entries */ void dirserv_expire_measured_bw_cache(time_t now) { if (mbw_cache) { /* Iterate through the cache and check each entry */ DIGESTMAP_FOREACH_MODIFY(mbw_cache, k, mbw_cache_entry_t *, e) { if (now > e->as_of + MAX_MEASUREMENT_AGE) { tor_free(e); MAP_DEL_CURRENT(k); } } DIGESTMAP_FOREACH_END; /* Check if we cleared the whole thing and free if so */ if (digestmap_size(mbw_cache) == 0) { digestmap_free(mbw_cache, tor_free_); mbw_cache = 0; } } } /** Get the current size of the measured bandwidth cache */ int dirserv_get_measured_bw_cache_size(void) { if (mbw_cache) return digestmap_size(mbw_cache); else return 0; } /** Query the cache by identity digest, return value indicates whether * we found it. The bw_out and as_of_out pointers receive the cached * bandwidth value and the time it was cached if not NULL. */ int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out, time_t *as_of_out) { mbw_cache_entry_t *v = NULL; int rv = 0; if (mbw_cache && node_id) { v = digestmap_get(mbw_cache, node_id); if (v) { /* Found something */ rv = 1; if (bw_kb_out) *bw_kb_out = v->mbw_kb; if (as_of_out) *as_of_out = v->as_of; } } return rv; } /** Predicate wrapper for dirserv_query_measured_bw_cache() */ int dirserv_has_measured_bw(const char *node_id) { return dirserv_query_measured_bw_cache_kb(node_id, NULL, NULL); } /** Get the best estimate of a router's bandwidth for dirauth purposes, * preferring measured to advertised values if available. */ static uint32_t dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri) { uint32_t bw_kb = 0; /* * Yeah, measured bandwidths in measured_bw_line_t are (implicitly * signed) longs and the ones router_get_advertised_bandwidth() returns * are uint32_t. */ long mbw_kb = 0; if (ri) { /* * * First try to see if we have a measured bandwidth; don't bother with * as_of_out here, on the theory that a stale measured bandwidth is still * better to trust than an advertised one. */ if (dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest, &mbw_kb, NULL)) { /* Got one! */ bw_kb = (uint32_t)mbw_kb; } else { /* If not, fall back to advertised */ bw_kb = router_get_advertised_bandwidth(ri) / 1000; } } return bw_kb; } /** Look through the routerlist, and using the measured bandwidth cache count * how many measured bandwidths we know. This is used to decide whether we * ever trust advertised bandwidths for purposes of assigning flags. */ static void dirserv_count_measured_bws(routerlist_t *rl) { /* Initialize this first */ routers_with_measured_bw = 0; tor_assert(rl); tor_assert(rl->routers); /* Iterate over the routerlist and count measured bandwidths */ SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { /* Check if we know a measured bandwidth for this one */ if (dirserv_has_measured_bw(ri->cache_info.identity_digest)) { ++routers_with_measured_bw; } } SMARTLIST_FOREACH_END(ri); } /** Return the bandwidth we believe for assigning flags; prefer measured * over advertised, and if we have above a threshold quantity of measured * bandwidths, we don't want to ever give flags to unmeasured routers, so * return 0. */ static uint32_t dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri) { int threshold; uint32_t bw_kb = 0; long mbw_kb; tor_assert(ri); /* Check if we have a measured bandwidth, and check the threshold if not */ if (!(dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest, &mbw_kb, NULL))) { threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; if (routers_with_measured_bw > threshold) { /* Return zero for unmeasured bandwidth if we are above threshold */ bw_kb = 0; } else { /* Return an advertised bandwidth otherwise */ bw_kb = router_get_advertised_bandwidth_capped(ri) / 1000; } } else { /* We have the measured bandwidth in mbw */ bw_kb = (uint32_t)mbw_kb; } return bw_kb; } /** Give a statement of our current performance thresholds for inclusion * in a vote document. */ char * dirserv_get_flag_thresholds_line(void) { char *result=NULL; const int measured_threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; const int enough_measured_bw = routers_with_measured_bw > measured_threshold; tor_asprintf(&result, "stable-uptime=%lu stable-mtbf=%lu " "fast-speed=%lu " "guard-wfu=%.03f%% guard-tk=%lu " "guard-bw-inc-exits=%lu guard-bw-exc-exits=%lu " "enough-mtbf=%d ignoring-advertised-bws=%d", (unsigned long)stable_uptime, (unsigned long)stable_mtbf, (unsigned long)fast_bandwidth_kb*1000, guard_wfu*100, (unsigned long)guard_tk, (unsigned long)guard_bandwidth_including_exits_kb*1000, (unsigned long)guard_bandwidth_excluding_exits_kb*1000, enough_mtbf_info ? 1 : 0, enough_measured_bw ? 1 : 0); return result; } /** Given a platform string as in a routerinfo_t (possibly null), return a * newly allocated version string for a networkstatus document, or NULL if the * platform doesn't give a Tor version. */ static char * version_from_platform(const char *platform) { if (platform && !strcmpstart(platform, "Tor ")) { const char *eos = find_whitespace(platform+4); if (eos && !strcmpstart(eos, " (r")) { /* XXXX Unify this logic with the other version extraction * logic in routerparse.c. */ eos = find_whitespace(eos+1); } if (eos) { return tor_strndup(platform, eos-platform); } } return NULL; } /** Helper: write the router-status information in rs into a newly * allocated character buffer. Use the same format as in network-status * documents. If version is non-NULL, add a "v" line for the platform. * Return 0 on success, -1 on failure. * * The format argument has one of the following values: * NS_V2 - Output an entry suitable for a V2 NS opinion document * NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry * NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc * consensus entry. * NS_V3_VOTE - Output a complete V3 NS vote. If vrs is present, * it contains additional information for the vote. * NS_CONTROL_PORT - Output a NS document for the control port */ char * routerstatus_format_entry(const routerstatus_t *rs, const char *version, routerstatus_format_type_t format, const vote_routerstatus_t *vrs) { char *summary; char *result = NULL; char published[ISO_TIME_LEN+1]; char identity64[BASE64_DIGEST_LEN+1]; char digest64[BASE64_DIGEST_LEN+1]; smartlist_t *chunks = NULL; format_iso_time(published, rs->published_on); digest_to_base64(identity64, rs->identity_digest); digest_to_base64(digest64, rs->descriptor_digest); chunks = smartlist_new(); smartlist_add_asprintf(chunks, "r %s %s %s%s%s %s %d %d\n", rs->nickname, identity64, (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64, (format==NS_V3_CONSENSUS_MICRODESC)?"":" ", published, fmt_addr32(rs->addr), (int)rs->or_port, (int)rs->dir_port); /* TODO: Maybe we want to pass in what we need to build the rest of * this here, instead of in the caller. Then we could use the * networkstatus_type_t values, with an additional control port value * added -MP */ /* V3 microdesc consensuses don't have "a" lines. */ if (format == NS_V3_CONSENSUS_MICRODESC) goto done; /* Possible "a" line. At most one for now. */ if (!tor_addr_is_null(&rs->ipv6_addr)) { smartlist_add_asprintf(chunks, "a %s\n", fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport)); } if (format == NS_V3_CONSENSUS) goto done; smartlist_add_asprintf(chunks, "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", /* These must stay in alphabetical order. */ rs->is_authority?" Authority":"", rs->is_bad_directory?" BadDirectory":"", rs->is_bad_exit?" BadExit":"", rs->is_exit?" Exit":"", rs->is_fast?" Fast":"", rs->is_possible_guard?" Guard":"", rs->is_hs_dir?" HSDir":"", rs->is_named?" Named":"", rs->is_flagged_running?" Running":"", rs->is_stable?" Stable":"", rs->is_unnamed?" Unnamed":"", rs->is_v2_dir?" V2Dir":"", rs->is_valid?" Valid":""); /* length of "opt v \n" */ #define V_LINE_OVERHEAD 7 if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) { smartlist_add_asprintf(chunks, "v %s\n", version); } if (format != NS_V2) { const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest); uint32_t bw_kb; if (format != NS_CONTROL_PORT) { /* Blow up more or less nicely if we didn't get anything or not the * thing we expected. */ if (!desc) { char id[HEX_DIGEST_LEN+1]; char dd[HEX_DIGEST_LEN+1]; base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN); base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN); log_warn(LD_BUG, "Cannot get any descriptor for %s " "(wanted descriptor %s).", id, dd); goto err; } /* This assert could fire for the control port, because * it can request NS documents before all descriptors * have been fetched. Therefore, we only do this test when * format != NS_CONTROL_PORT. */ if (tor_memneq(desc->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)) { char rl_d[HEX_DIGEST_LEN+1]; char rs_d[HEX_DIGEST_LEN+1]; char id[HEX_DIGEST_LEN+1]; base16_encode(rl_d, sizeof(rl_d), desc->cache_info.signed_descriptor_digest, DIGEST_LEN); base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN); base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN); log_err(LD_BUG, "descriptor digest in routerlist does not match " "the one in routerstatus: %s vs %s " "(router %s)\n", rl_d, rs_d, id); tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)); } } if (format == NS_CONTROL_PORT && rs->has_bandwidth) { bw_kb = rs->bandwidth_kb; } else { tor_assert(desc); bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000; } smartlist_add_asprintf(chunks, "w Bandwidth=%d", bw_kb); if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) { smartlist_add_asprintf(chunks, " Measured=%d", vrs->measured_bw_kb); } smartlist_add(chunks, tor_strdup("\n")); if (desc) { summary = policy_summarize(desc->exit_policy, AF_INET); smartlist_add_asprintf(chunks, "p %s\n", summary); tor_free(summary); } } done: result = smartlist_join_strings(chunks, "", 0, NULL); err: if (chunks) { SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); smartlist_free(chunks); } return result; } /** Helper for sorting: compares two routerinfos first by address, and then by * descending order of "usefulness". (An authority is more useful than a * non-authority; a running router is more useful than a non-running router; * and a router with more bandwidth is more useful than one with less.) **/ static int compare_routerinfo_by_ip_and_bw_(const void **a, const void **b) { routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b; int first_is_auth, second_is_auth; uint32_t bw_kb_first, bw_kb_second; const node_t *node_first, *node_second; int first_is_running, second_is_running; /* we return -1 if first should appear before second... that is, * if first is a better router. */ if (first->addr < second->addr) return -1; else if (first->addr > second->addr) return 1; /* Potentially, this next bit could cause k n lg n memeq calls. But in * reality, we will almost never get here, since addresses will usually be * different. */ first_is_auth = router_digest_is_trusted_dir(first->cache_info.identity_digest); second_is_auth = router_digest_is_trusted_dir(second->cache_info.identity_digest); if (first_is_auth && !second_is_auth) return -1; else if (!first_is_auth && second_is_auth) return 1; node_first = node_get_by_id(first->cache_info.identity_digest); node_second = node_get_by_id(second->cache_info.identity_digest); first_is_running = node_first && node_first->is_running; second_is_running = node_second && node_second->is_running; if (first_is_running && !second_is_running) return -1; else if (!first_is_running && second_is_running) return 1; bw_kb_first = dirserv_get_bandwidth_for_router_kb(first); bw_kb_second = dirserv_get_bandwidth_for_router_kb(second); if (bw_kb_first > bw_kb_second) return -1; else if (bw_kb_first < bw_kb_second) return 1; /* They're equal! Compare by identity digest, so there's a * deterministic order and we avoid flapping. */ return fast_memcmp(first->cache_info.identity_digest, second->cache_info.identity_digest, DIGEST_LEN); } /** Given a list of routerinfo_t in routers, return a new digestmap_t * whose keys are the identity digests of those routers that we're going to * exclude for Sybil-like appearance. */ static digestmap_t * get_possible_sybil_list(const smartlist_t *routers) { const or_options_t *options = get_options(); digestmap_t *omit_as_sybil; smartlist_t *routers_by_ip = smartlist_new(); uint32_t last_addr; int addr_count; /* Allow at most this number of Tor servers on a single IP address, ... */ int max_with_same_addr = options->AuthDirMaxServersPerAddr; /* ... unless it's a directory authority, in which case allow more. */ int max_with_same_addr_on_authority = options->AuthDirMaxServersPerAuthAddr; if (max_with_same_addr <= 0) max_with_same_addr = INT_MAX; if (max_with_same_addr_on_authority <= 0) max_with_same_addr_on_authority = INT_MAX; smartlist_add_all(routers_by_ip, routers); smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_); omit_as_sybil = digestmap_new(); last_addr = 0; addr_count = 0; SMARTLIST_FOREACH_BEGIN(routers_by_ip, routerinfo_t *, ri) { if (last_addr != ri->addr) { last_addr = ri->addr; addr_count = 1; } else if (++addr_count > max_with_same_addr) { if (!router_addr_is_trusted_dir(ri->addr) || addr_count > max_with_same_addr_on_authority) digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri); } } SMARTLIST_FOREACH_END(ri); smartlist_free(routers_by_ip); return omit_as_sybil; } /** Return non-zero iff a relay running the Tor version specified in * platform is suitable for use as a potential entry guard. */ static int is_router_version_good_for_possible_guard(const char *platform) { static int parsed_versions_initialized = 0; static tor_version_t first_good_0_2_1_guard_version; static tor_version_t first_good_0_2_2_guard_version; static tor_version_t first_good_later_guard_version; tor_version_t router_version; /* XXX024 This block should be extracted into its own function. */ /* XXXX Begin code copied from tor_version_as_new_as (in routerparse.c) */ { char *s, *s2, *start; char tmp[128]; tor_assert(platform); /* nonstandard Tor; be safe and say yes */ if (strcmpstart(platform,"Tor ")) return 1; start = (char *)eat_whitespace(platform+3); if (!*start) return 0; s = (char *)find_whitespace(start); /* also finds '\0', which is fine */ s2 = (char*)eat_whitespace(s); if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-")) s = (char*)find_whitespace(s2); if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */ return 0; strlcpy(tmp, start, s-start+1); if (tor_version_parse(tmp, &router_version)<0) { log_info(LD_DIR,"Router version '%s' unparseable.",tmp); return 1; /* be safe and say yes */ } } /* XXXX End code copied from tor_version_as_new_as (in routerparse.c) */ if (!parsed_versions_initialized) { /* CVE-2011-2769 was fixed on the relay side in Tor versions * 0.2.1.31, 0.2.2.34, and 0.2.3.6-alpha. */ tor_assert(tor_version_parse("0.2.1.31", &first_good_0_2_1_guard_version)>=0); tor_assert(tor_version_parse("0.2.2.34", &first_good_0_2_2_guard_version)>=0); tor_assert(tor_version_parse("0.2.3.6-alpha", &first_good_later_guard_version)>=0); /* Don't parse these constant version strings once for every relay * for every vote. */ parsed_versions_initialized = 1; } return ((tor_version_same_series(&first_good_0_2_1_guard_version, &router_version) && tor_version_compare(&first_good_0_2_1_guard_version, &router_version) <= 0) || (tor_version_same_series(&first_good_0_2_2_guard_version, &router_version) && tor_version_compare(&first_good_0_2_2_guard_version, &router_version) <= 0) || (tor_version_compare(&first_good_later_guard_version, &router_version) <= 0)); } /** Extract status information from ri and from other authority * functions and store it in rs>. If naming, consider setting * the named flag in rs. * * We assume that ri-\>is_running has already been set, e.g. by * dirserv_set_router_is_running(ri, now); */ void set_routerstatus_from_routerinfo(routerstatus_t *rs, node_t *node, routerinfo_t *ri, time_t now, int naming, int listbadexits, int listbaddirs, int vote_on_hsdirs) { const or_options_t *options = get_options(); uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri); memset(rs, 0, sizeof(routerstatus_t)); rs->is_authority = router_digest_is_trusted_dir(ri->cache_info.identity_digest); /* Already set by compute_performance_thresholds. */ rs->is_exit = node->is_exit; rs->is_stable = node->is_stable = router_is_active(ri, node, now) && !dirserv_thinks_router_is_unreliable(now, ri, 1, 0); rs->is_fast = node->is_fast = router_is_active(ri, node, now) && !dirserv_thinks_router_is_unreliable(now, ri, 0, 1); rs->is_flagged_running = node->is_running; /* computed above */ if (naming) { uint32_t name_status = dirserv_get_name_status( node->identity, ri->nickname); rs->is_named = (naming && (name_status & FP_NAMED)) ? 1 : 0; rs->is_unnamed = (naming && (name_status & FP_UNNAMED)) ? 1 : 0; } rs->is_valid = node->is_valid; if (node->is_fast && ((options->AuthDirGuardBWGuarantee && routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) || routerbw_kb >= MIN(guard_bandwidth_including_exits_kb, guard_bandwidth_excluding_exits_kb)) && is_router_version_good_for_possible_guard(ri->platform)) { long tk = rep_hist_get_weighted_time_known( node->identity, now); double wfu = rep_hist_get_weighted_fractional_uptime( node->identity, now); rs->is_possible_guard = (wfu >= guard_wfu && tk >= guard_tk) ? 1 : 0; } else { rs->is_possible_guard = 0; } rs->is_bad_directory = listbaddirs && node->is_bad_directory; rs->is_bad_exit = listbadexits && node->is_bad_exit; node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now); rs->is_hs_dir = vote_on_hsdirs && node->is_hs_dir; rs->is_v2_dir = ri->dir_port != 0; if (!strcasecmp(ri->nickname, UNNAMED_ROUTER_NICKNAME)) rs->is_named = rs->is_unnamed = 0; rs->published_on = ri->cache_info.published_on; memcpy(rs->identity_digest, node->identity, DIGEST_LEN); memcpy(rs->descriptor_digest, ri->cache_info.signed_descriptor_digest, DIGEST_LEN); rs->addr = ri->addr; strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname)); rs->or_port = ri->or_port; rs->dir_port = ri->dir_port; if (options->AuthDirHasIPv6Connectivity == 1 && !tor_addr_is_null(&ri->ipv6_addr) && node->last_reachable6 >= now - REACHABLE_TIMEOUT) { /* We're configured as having IPv6 connectivity. There's an IPv6 OR port and it's reachable so copy it to the routerstatus. */ tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); rs->ipv6_orport = ri->ipv6_orport; } } /** Routerstatus rs is part of a group of routers that are on * too narrow an IP-space. Clear out its flags: we don't want people * using it. */ static void clear_status_flags_on_sybil(routerstatus_t *rs) { rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running = rs->is_named = rs->is_valid = rs->is_v2_dir = rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit = rs->is_bad_directory = 0; /* FFFF we might want some mechanism to check later on if we * missed zeroing any flags: it's easy to add a new flag but * forget to add it to this clause. */ } /** * Helper function to parse out a line in the measured bandwidth file * into a measured_bw_line_t output structure. Returns -1 on failure * or 0 on success. */ int measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line) { char *line = tor_strdup(orig_line); char *cp = line; int got_bw = 0; int got_node_id = 0; char *strtok_state; /* lame sauce d'jour */ cp = tor_strtok_r(cp, " \t", &strtok_state); if (!cp) { log_warn(LD_DIRSERV, "Invalid line in bandwidth file: %s", escaped(orig_line)); tor_free(line); return -1; } if (orig_line[strlen(orig_line)-1] != '\n') { log_warn(LD_DIRSERV, "Incomplete line in bandwidth file: %s", escaped(orig_line)); tor_free(line); return -1; } do { if (strcmpstart(cp, "bw=") == 0) { int parse_ok = 0; char *endptr; if (got_bw) { log_warn(LD_DIRSERV, "Double bw= in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } cp+=strlen("bw="); out->bw_kb = tor_parse_long(cp, 0, 0, LONG_MAX, &parse_ok, &endptr); if (!parse_ok || (*endptr && !TOR_ISSPACE(*endptr))) { log_warn(LD_DIRSERV, "Invalid bandwidth in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } got_bw=1; } else if (strcmpstart(cp, "node_id=$") == 0) { if (got_node_id) { log_warn(LD_DIRSERV, "Double node_id= in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } cp+=strlen("node_id=$"); if (strlen(cp) != HEX_DIGEST_LEN || base16_decode(out->node_id, DIGEST_LEN, cp, HEX_DIGEST_LEN)) { log_warn(LD_DIRSERV, "Invalid node_id in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } strlcpy(out->node_hex, cp, sizeof(out->node_hex)); got_node_id=1; } } while ((cp = tor_strtok_r(NULL, " \t", &strtok_state))); if (got_bw && got_node_id) { tor_free(line); return 0; } else { log_warn(LD_DIRSERV, "Incomplete line in bandwidth file: %s", escaped(orig_line)); tor_free(line); return -1; } } /** * Helper function to apply a parsed measurement line to a list * of bandwidth statuses. Returns true if a line is found, * false otherwise. */ int measured_bw_line_apply(measured_bw_line_t *parsed_line, smartlist_t *routerstatuses) { vote_routerstatus_t *rs = NULL; if (!routerstatuses) return 0; rs = smartlist_bsearch(routerstatuses, parsed_line->node_id, compare_digest_to_vote_routerstatus_entry); if (rs) { rs->has_measured_bw = 1; rs->measured_bw_kb = (uint32_t)parsed_line->bw_kb; } else { log_info(LD_DIRSERV, "Node ID %s not found in routerstatus list", parsed_line->node_hex); } return rs != NULL; } /** * Read the measured bandwidth file and apply it to the list of * vote_routerstatus_t. Returns -1 on error, 0 otherwise. */ int dirserv_read_measured_bandwidths(const char *from_file, smartlist_t *routerstatuses) { char line[256]; FILE *fp = tor_fopen_cloexec(from_file, "r"); int applied_lines = 0; time_t file_time, now; int ok; if (fp == NULL) { log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s", from_file); return -1; } if (!fgets(line, sizeof(line), fp) || !strlen(line) || line[strlen(line)-1] != '\n') { log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s", escaped(line)); fclose(fp); return -1; } line[strlen(line)-1] = '\0'; file_time = tor_parse_ulong(line, 10, 0, ULONG_MAX, &ok, NULL); if (!ok) { log_warn(LD_DIRSERV, "Non-integer time in bandwidth file: %s", escaped(line)); fclose(fp); return -1; } now = time(NULL); if ((now - file_time) > MAX_MEASUREMENT_AGE) { log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u", (unsigned)(time(NULL) - file_time)); fclose(fp); return -1; } if (routerstatuses) smartlist_sort(routerstatuses, compare_vote_routerstatus_entries); while (!feof(fp)) { measured_bw_line_t parsed_line; if (fgets(line, sizeof(line), fp) && strlen(line)) { if (measured_bw_line_parse(&parsed_line, line) != -1) { /* Also cache the line for dirserv_get_bandwidth_for_router() */ dirserv_cache_measured_bw(&parsed_line, file_time); if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0) applied_lines++; } } } /* Now would be a nice time to clean the cache, too */ dirserv_expire_measured_bw_cache(now); fclose(fp); log_info(LD_DIRSERV, "Bandwidth measurement file successfully read. " "Applied %d measurements.", applied_lines); return 0; } /** Return a new networkstatus_t* containing our current opinion. (For v3 * authorities) */ networkstatus_t * dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, authority_cert_t *cert) { const or_options_t *options = get_options(); networkstatus_t *v3_out = NULL; uint32_t addr; char *hostname = NULL, *client_versions = NULL, *server_versions = NULL; const char *contact; smartlist_t *routers, *routerstatuses; char identity_digest[DIGEST_LEN]; char signing_key_digest[DIGEST_LEN]; int naming = options->NamingAuthoritativeDir; int listbadexits = options->AuthDirListBadExits; int listbaddirs = options->AuthDirListBadDirs; int vote_on_hsdirs = options->VoteOnHidServDirectoriesV2; routerlist_t *rl = router_get_routerlist(); time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; networkstatus_voter_info_t *voter = NULL; vote_timing_t timing; digestmap_t *omit_as_sybil = NULL; const int vote_on_reachability = running_long_enough_to_decide_unreachable(); smartlist_t *microdescriptors = NULL; tor_assert(private_key); tor_assert(cert); if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) { log_warn(LD_NET, "Couldn't resolve my hostname"); return NULL; } if (!hostname || !strchr(hostname, '.')) { tor_free(hostname); hostname = tor_dup_ip(addr); } if (crypto_pk_get_digest(private_key, signing_key_digest)<0) { log_err(LD_BUG, "Error computing signing key digest"); return NULL; } if (crypto_pk_get_digest(cert->identity_key, identity_digest)<0) { log_err(LD_BUG, "Error computing identity key digest"); return NULL; } if (options->VersioningAuthoritativeDir) { client_versions = format_versions_list(options->RecommendedClientVersions); server_versions = format_versions_list(options->RecommendedServerVersions); } contact = get_options()->ContactInfo; if (!contact) contact = "(none)"; /* * Do this so dirserv_compute_performance_thresholds() and * set_routerstatus_from_routerinfo() see up-to-date bandwidth info. */ if (options->V3BandwidthsFile) { dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL); } else { /* * No bandwidths file; clear the measured bandwidth cache in case we had * one last time around. */ if (dirserv_get_measured_bw_cache_size() > 0) { dirserv_clear_measured_bw_cache(); } } /* precompute this part, since we need it to decide what "stable" * means. */ SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, { dirserv_set_router_is_running(ri, now); }); routers = smartlist_new(); smartlist_add_all(routers, rl->routers); routers_sort_by_identity(routers); omit_as_sybil = get_possible_sybil_list(routers); DIGESTMAP_FOREACH(omit_as_sybil, sybil_id, void *, ignore) { (void) ignore; rep_hist_make_router_pessimal(sybil_id, now); } DIGESTMAP_FOREACH_END; /* Count how many have measured bandwidths so we know how to assign flags; * this must come before dirserv_compute_performance_thresholds() */ dirserv_count_measured_bws(rl); dirserv_compute_performance_thresholds(rl, omit_as_sybil); routerstatuses = smartlist_new(); microdescriptors = smartlist_new(); SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { if (ri->cache_info.published_on >= cutoff) { routerstatus_t *rs; vote_routerstatus_t *vrs; node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); if (!node) continue; vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; set_routerstatus_from_routerinfo(rs, node, ri, now, naming, listbadexits, listbaddirs, vote_on_hsdirs); if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) clear_status_flags_on_sybil(rs); if (!vote_on_reachability) rs->is_flagged_running = 0; vrs->version = version_from_platform(ri->platform); vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now, microdescriptors); smartlist_add(routerstatuses, vrs); } } SMARTLIST_FOREACH_END(ri); { smartlist_t *added = microdescs_add_list_to_cache(get_microdesc_cache(), microdescriptors, SAVED_NOWHERE, 0); smartlist_free(added); smartlist_free(microdescriptors); } smartlist_free(routers); digestmap_free(omit_as_sybil, NULL); /* This pass through applies the measured bw lines to the routerstatuses */ if (options->V3BandwidthsFile) { dirserv_read_measured_bandwidths(options->V3BandwidthsFile, routerstatuses); } else { /* * No bandwidths file; clear the measured bandwidth cache in case we had * one last time around. */ if (dirserv_get_measured_bw_cache_size() > 0) { dirserv_clear_measured_bw_cache(); } } v3_out = tor_malloc_zero(sizeof(networkstatus_t)); v3_out->type = NS_TYPE_VOTE; dirvote_get_preferred_voting_intervals(&timing); v3_out->published = now; { char tbuf[ISO_TIME_LEN+1]; networkstatus_t *current_consensus = networkstatus_get_live_consensus(now); long last_consensus_interval; /* only used to pick a valid_after */ if (current_consensus) last_consensus_interval = current_consensus->fresh_until - current_consensus->valid_after; else last_consensus_interval = options->TestingV3AuthInitialVotingInterval; v3_out->valid_after = dirvote_get_start_of_next_interval(now, (int)last_consensus_interval); format_iso_time(tbuf, v3_out->valid_after); log_notice(LD_DIR,"Choosing valid-after time in vote as %s: " "consensus_set=%d, last_interval=%d", tbuf, current_consensus?1:0, (int)last_consensus_interval); } v3_out->fresh_until = v3_out->valid_after + timing.vote_interval; v3_out->valid_until = v3_out->valid_after + (timing.vote_interval * timing.n_intervals_valid); v3_out->vote_seconds = timing.vote_delay; v3_out->dist_seconds = timing.dist_delay; tor_assert(v3_out->vote_seconds > 0); tor_assert(v3_out->dist_seconds > 0); tor_assert(timing.n_intervals_valid > 0); v3_out->client_versions = client_versions; v3_out->server_versions = server_versions; v3_out->known_flags = smartlist_new(); smartlist_split_string(v3_out->known_flags, "Authority Exit Fast Guard Stable V2Dir Valid", 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (vote_on_reachability) smartlist_add(v3_out->known_flags, tor_strdup("Running")); if (listbaddirs) smartlist_add(v3_out->known_flags, tor_strdup("BadDirectory")); if (listbadexits) smartlist_add(v3_out->known_flags, tor_strdup("BadExit")); if (naming) { smartlist_add(v3_out->known_flags, tor_strdup("Named")); smartlist_add(v3_out->known_flags, tor_strdup("Unnamed")); } if (vote_on_hsdirs) smartlist_add(v3_out->known_flags, tor_strdup("HSDir")); smartlist_sort_strings(v3_out->known_flags); if (options->ConsensusParams) { v3_out->net_params = smartlist_new(); smartlist_split_string(v3_out->net_params, options->ConsensusParams, NULL, 0, 0); smartlist_sort_strings(v3_out->net_params); } voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); voter->nickname = tor_strdup(options->Nickname); memcpy(voter->identity_digest, identity_digest, DIGEST_LEN); voter->sigs = smartlist_new(); voter->address = hostname; voter->addr = addr; voter->dir_port = router_get_advertised_dir_port(options, 0); voter->or_port = router_get_advertised_or_port(options); voter->contact = tor_strdup(contact); if (options->V3AuthUseLegacyKey) { authority_cert_t *c = get_my_v3_legacy_cert(); if (c) { if (crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest)) { log_warn(LD_BUG, "Unable to compute digest of legacy v3 identity key"); memset(voter->legacy_id_digest, 0, DIGEST_LEN); } } } v3_out->voters = smartlist_new(); smartlist_add(v3_out->voters, voter); v3_out->cert = authority_cert_dup(cert); v3_out->routerstatus_list = routerstatuses; /* Note: networkstatus_digest is unset; it won't get set until we actually * format the vote. */ return v3_out; } /** For v2 authoritative directories only: Replace the contents of * the_v2_networkstatus with a newly generated network status * object. */ cached_dir_t * generate_v2_networkstatus_opinion(void) { cached_dir_t *r = NULL; size_t identity_pkey_len; char *status = NULL, *client_versions = NULL, *server_versions = NULL, *identity_pkey = NULL, *hostname = NULL; const or_options_t *options = get_options(); char fingerprint[FINGERPRINT_LEN+1]; char published[ISO_TIME_LEN+1]; char digest[DIGEST_LEN]; uint32_t addr; crypto_pk_t *private_key; routerlist_t *rl = router_get_routerlist(); time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; int naming = options->NamingAuthoritativeDir; int versioning = options->VersioningAuthoritativeDir; int listbaddirs = options->AuthDirListBadDirs; int listbadexits = options->AuthDirListBadExits; int vote_on_hsdirs = options->VoteOnHidServDirectoriesV2; const char *contact; char *version_lines = NULL; smartlist_t *routers = NULL; digestmap_t *omit_as_sybil = NULL; smartlist_t *chunks = NULL; private_key = get_server_identity_key(); if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) { log_warn(LD_NET, "Couldn't resolve my hostname"); goto done; } if (!hostname) hostname = tor_dup_ip(addr); format_iso_time(published, now); client_versions = format_versions_list(options->RecommendedClientVersions); server_versions = format_versions_list(options->RecommendedServerVersions); if (crypto_pk_write_public_key_to_string(private_key, &identity_pkey, &identity_pkey_len)<0) { log_warn(LD_BUG,"Writing public key to string failed."); goto done; } if (crypto_pk_get_fingerprint(private_key, fingerprint, 0)<0) { log_err(LD_BUG, "Error computing fingerprint"); goto done; } contact = options->ContactInfo; if (!contact) contact = "(none)"; if (versioning) { tor_asprintf(&version_lines, "client-versions %s\nserver-versions %s\n", client_versions, server_versions); } else { version_lines = tor_strdup(""); } chunks = smartlist_new(); smartlist_add_asprintf(chunks, "network-status-version 2\n" "dir-source %s %s %d\n" "fingerprint %s\n" "contact %s\n" "published %s\n" "dir-options%s%s%s%s\n" "%s" /* client version line, server version line. */ "dir-signing-key\n%s", hostname, fmt_addr32(addr), (int)router_get_advertised_dir_port(options, 0), fingerprint, contact, published, naming ? " Names" : "", listbaddirs ? " BadDirectories" : "", listbadexits ? " BadExits" : "", versioning ? " Versions" : "", version_lines, identity_pkey); /* precompute this part, since we need it to decide what "stable" * means. */ SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, { dirserv_set_router_is_running(ri, now); }); routers = smartlist_new(); smartlist_add_all(routers, rl->routers); routers_sort_by_identity(routers); omit_as_sybil = get_possible_sybil_list(routers); dirserv_compute_performance_thresholds(rl, omit_as_sybil); SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { if (ri->cache_info.published_on >= cutoff) { routerstatus_t rs; char *version = version_from_platform(ri->platform); node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); if (!node) { tor_free(version); continue; } set_routerstatus_from_routerinfo(&rs, node, ri, now, naming, listbadexits, listbaddirs, vote_on_hsdirs); if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) clear_status_flags_on_sybil(&rs); { char *rsf = routerstatus_format_entry(&rs, version, NS_V2, NULL); if (rsf) smartlist_add(chunks, rsf); } tor_free(version); } } SMARTLIST_FOREACH_END(ri); smartlist_add_asprintf(chunks, "directory-signature %s\n", options->Nickname); crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1); note_crypto_pk_op(SIGN_DIR); { char *sig; if (!(sig = router_get_dirobj_signature(digest,DIGEST_LEN, private_key))) { log_warn(LD_BUG, "Unable to sign router status."); goto done; } smartlist_add(chunks, sig); } status = smartlist_join_strings(chunks, "", 0, NULL); { networkstatus_v2_t *ns; if (!(ns = networkstatus_v2_parse_from_string(status))) { log_err(LD_BUG,"Generated a networkstatus we couldn't parse."); goto done; } networkstatus_v2_free(ns); } { cached_dir_t **ns_ptr = &the_v2_networkstatus; if (*ns_ptr) cached_dir_decref(*ns_ptr); *ns_ptr = new_cached_dir(status, now); status = NULL; /* So it doesn't get double-freed. */ the_v2_networkstatus_is_dirty = 0; router_set_networkstatus_v2((*ns_ptr)->dir, now, NS_GENERATED, NULL); r = *ns_ptr; } done: if (chunks) { SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); smartlist_free(chunks); } tor_free(client_versions); tor_free(server_versions); tor_free(version_lines); tor_free(status); tor_free(hostname); tor_free(identity_pkey); smartlist_free(routers); digestmap_free(omit_as_sybil, NULL); return r; } /** Given the portion of a networkstatus request URL after "tor/status/" in * key, append to result the digests of the identity keys of the * networkstatus objects that the client has requested. */ void dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result, const char *key) { tor_assert(result); if (!cached_v2_networkstatus) cached_v2_networkstatus = digestmap_new(); if (should_generate_v2_networkstatus()) generate_v2_networkstatus_opinion(); if (!strcmp(key,"authority")) { if (authdir_mode_v2(get_options())) { const routerinfo_t *me = router_get_my_routerinfo(); if (me) smartlist_add(result, tor_memdup(me->cache_info.identity_digest, DIGEST_LEN)); } } else if (!strcmp(key, "all")) { if (digestmap_size(cached_v2_networkstatus)) { digestmap_iter_t *iter; iter = digestmap_iter_init(cached_v2_networkstatus); while (!digestmap_iter_done(iter)) { const char *ident; void *val; digestmap_iter_get(iter, &ident, &val); smartlist_add(result, tor_memdup(ident, DIGEST_LEN)); iter = digestmap_iter_next(cached_v2_networkstatus, iter); } } else { SMARTLIST_FOREACH(router_get_trusted_dir_servers(), dir_server_t *, ds, if (ds->type & V2_DIRINFO) smartlist_add(result, tor_memdup(ds->digest, DIGEST_LEN))); } smartlist_sort_digests(result); if (smartlist_len(result) == 0) log_info(LD_DIRSERV, "Client requested 'all' network status objects; we have none."); } else if (!strcmpstart(key, "fp/")) { dir_split_resource_into_fingerprints(key+3, result, NULL, DSR_HEX|DSR_SORT_UNIQ); } } /** Look for a network status object as specified by key, which should * be either "authority" (to find a network status generated by us), a hex * identity digest (to find a network status generated by given directory), or * "all" (to return all the v2 network status objects we have). */ void dirserv_get_networkstatus_v2(smartlist_t *result, const char *key) { cached_dir_t *cached; smartlist_t *fingerprints = smartlist_new(); tor_assert(result); if (!cached_v2_networkstatus) cached_v2_networkstatus = digestmap_new(); dirserv_get_networkstatus_v2_fingerprints(fingerprints, key); SMARTLIST_FOREACH_BEGIN(fingerprints, const char *, fp) { if (router_digest_is_me(fp) && should_generate_v2_networkstatus()) generate_v2_networkstatus_opinion(); cached = digestmap_get(cached_v2_networkstatus, fp); if (cached) { smartlist_add(result, cached); } else { char hexbuf[HEX_DIGEST_LEN+1]; base16_encode(hexbuf, sizeof(hexbuf), fp, DIGEST_LEN); log_info(LD_DIRSERV, "Don't know about any network status with " "fingerprint '%s'", hexbuf); } } SMARTLIST_FOREACH_END(fp); SMARTLIST_FOREACH(fingerprints, char *, cp, tor_free(cp)); smartlist_free(fingerprints); } /** As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t * pointers, adds copies of digests to fps_out, and doesn't use the * /tor/server/ prefix. For a /d/ request, adds descriptor digests; for other * requests, adds identity digests. */ int dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key, const char **msg, int for_unencrypted_conn, int is_extrainfo) { int by_id = 1; *msg = NULL; if (!strcmp(key, "all")) { routerlist_t *rl = router_get_routerlist(); SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, smartlist_add(fps_out, tor_memdup(r->cache_info.identity_digest, DIGEST_LEN))); /* Treat "all" requests as if they were unencrypted */ for_unencrypted_conn = 1; } else if (!strcmp(key, "authority")) { const routerinfo_t *ri = router_get_my_routerinfo(); if (ri) smartlist_add(fps_out, tor_memdup(ri->cache_info.identity_digest, DIGEST_LEN)); } else if (!strcmpstart(key, "d/")) { by_id = 0; key += strlen("d/"); dir_split_resource_into_fingerprints(key, fps_out, NULL, DSR_HEX|DSR_SORT_UNIQ); } else if (!strcmpstart(key, "fp/")) { key += strlen("fp/"); dir_split_resource_into_fingerprints(key, fps_out, NULL, DSR_HEX|DSR_SORT_UNIQ); } else { *msg = "Key not recognized"; return -1; } if (for_unencrypted_conn) { /* Remove anything that insists it not be sent unencrypted. */ SMARTLIST_FOREACH_BEGIN(fps_out, char *, cp) { const signed_descriptor_t *sd; if (by_id) sd = get_signed_descriptor_by_fp(cp,is_extrainfo,0); else if (is_extrainfo) sd = extrainfo_get_by_descriptor_digest(cp); else sd = router_get_by_descriptor_digest(cp); if (sd && !sd->send_unencrypted) { tor_free(cp); SMARTLIST_DEL_CURRENT(fps_out, cp); } } SMARTLIST_FOREACH_END(cp); } if (!smartlist_len(fps_out)) { *msg = "Servers unavailable"; return -1; } return 0; } /** Add a signed_descriptor_t to descs_out for each router matching * key. The key should be either * - "/tor/server/authority" for our own routerinfo; * - "/tor/server/all" for all the routerinfos we have, concatenated; * - "/tor/server/fp/FP" where FP is a plus-separated sequence of * hex identity digests; or * - "/tor/server/d/D" where D is a plus-separated sequence * of server descriptor digests, in hex. * * Return 0 if we found some matching descriptors, or -1 if we do not * have any descriptors, no matching descriptors, or if we did not * recognize the key (URL). * If -1 is returned *msg will be set to an appropriate error * message. * * XXXX rename this function. It's only called from the controller. * XXXX in fact, refactor this function, merging as much as possible. */ int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key, const char **msg) { *msg = NULL; if (!strcmp(key, "/tor/server/all")) { routerlist_t *rl = router_get_routerlist(); SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, smartlist_add(descs_out, &(r->cache_info))); } else if (!strcmp(key, "/tor/server/authority")) { const routerinfo_t *ri = router_get_my_routerinfo(); if (ri) smartlist_add(descs_out, (void*) &(ri->cache_info)); } else if (!strcmpstart(key, "/tor/server/d/")) { smartlist_t *digests = smartlist_new(); key += strlen("/tor/server/d/"); dir_split_resource_into_fingerprints(key, digests, NULL, DSR_HEX|DSR_SORT_UNIQ); SMARTLIST_FOREACH(digests, const char *, d, { signed_descriptor_t *sd = router_get_by_descriptor_digest(d); if (sd) smartlist_add(descs_out,sd); }); SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); smartlist_free(digests); } else if (!strcmpstart(key, "/tor/server/fp/")) { smartlist_t *digests = smartlist_new(); time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH; key += strlen("/tor/server/fp/"); dir_split_resource_into_fingerprints(key, digests, NULL, DSR_HEX|DSR_SORT_UNIQ); SMARTLIST_FOREACH_BEGIN(digests, const char *, d) { if (router_digest_is_me(d)) { /* make sure desc_routerinfo exists */ const routerinfo_t *ri = router_get_my_routerinfo(); if (ri) smartlist_add(descs_out, (void*) &(ri->cache_info)); } else { const routerinfo_t *ri = router_get_by_id_digest(d); /* Don't actually serve a descriptor that everyone will think is * expired. This is an (ugly) workaround to keep buggy 0.1.1.10 * Tors from downloading descriptors that they will throw away. */ if (ri && ri->cache_info.published_on > cutoff) smartlist_add(descs_out, (void*) &(ri->cache_info)); } } SMARTLIST_FOREACH_END(d); SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); smartlist_free(digests); } else { *msg = "Key not recognized"; return -1; } if (!smartlist_len(descs_out)) { *msg = "Servers unavailable"; return -1; } return 0; } /** Called when a TLS handshake has completed successfully with a * router listening at address:or_port, and has yielded * a certificate with digest digest_rcvd. * * Inform the reachability checker that we could get to this guy. */ void dirserv_orconn_tls_done(const tor_addr_t *addr, uint16_t or_port, const char *digest_rcvd) { node_t *node = NULL; tor_addr_port_t orport; routerinfo_t *ri = NULL; time_t now = time(NULL); tor_assert(addr); tor_assert(digest_rcvd); node = node_get_mutable_by_id(digest_rcvd); if (node == NULL || node->ri == NULL) return; ri = node->ri; tor_addr_copy(&orport.addr, addr); orport.port = or_port; if (router_has_orport(ri, &orport)) { /* Found the right router. */ if (!authdir_mode_bridge(get_options()) || ri->purpose == ROUTER_PURPOSE_BRIDGE) { char addrstr[TOR_ADDR_BUF_LEN]; /* This is a bridge or we're not a bridge authorititative -- mark it as reachable. */ log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.", router_describe(ri), tor_addr_to_str(addrstr, addr, sizeof(addrstr), 1), ri->or_port); if (tor_addr_family(addr) == AF_INET) { rep_hist_note_router_reachable(digest_rcvd, addr, or_port, now); node->last_reachable = now; } else if (tor_addr_family(addr) == AF_INET6) { /* No rephist for IPv6. */ node->last_reachable6 = now; } } } } /** Called when we, as an authority, receive a new router descriptor either as * an upload or a download. Used to decide whether to relaunch reachability * testing for the server. */ int dirserv_should_launch_reachability_test(const routerinfo_t *ri, const routerinfo_t *ri_old) { if (!authdir_mode_handles_descs(get_options(), ri->purpose)) return 0; if (!ri_old) { /* New router: Launch an immediate reachability test, so we will have an * opinion soon in case we're generating a consensus soon */ return 1; } if (ri_old->is_hibernating && !ri->is_hibernating) { /* It just came out of hibernation; launch a reachability test */ return 1; } if (! routers_have_same_or_addrs(ri, ri_old)) { /* Address or port changed; launch a reachability test */ return 1; } return 0; } /** Helper function for dirserv_test_reachability(). Start a TLS * connection to router, and annotate it with when we started * the test. */ void dirserv_single_reachability_test(time_t now, routerinfo_t *router) { channel_t *chan = NULL; node_t *node = NULL; tor_addr_t router_addr; (void) now; tor_assert(router); node = node_get_mutable_by_id(router->cache_info.identity_digest); tor_assert(node); /* IPv4. */ log_debug(LD_OR,"Testing reachability of %s at %s:%u.", router->nickname, router->address, router->or_port); tor_addr_from_ipv4h(&router_addr, router->addr); chan = channel_tls_connect(&router_addr, router->or_port, router->cache_info.identity_digest); if (chan) command_setup_channel(chan); /* Possible IPv6. */ if (get_options()->AuthDirHasIPv6Connectivity == 1 && !tor_addr_is_null(&router->ipv6_addr)) { char addrstr[TOR_ADDR_BUF_LEN]; log_debug(LD_OR, "Testing reachability of %s at %s:%u.", router->nickname, tor_addr_to_str(addrstr, &router->ipv6_addr, sizeof(addrstr), 1), router->ipv6_orport); chan = channel_tls_connect(&router->ipv6_addr, router->ipv6_orport, router->cache_info.identity_digest); if (chan) command_setup_channel(chan); } } /** Auth dir server only: load balance such that we only * try a few connections per call. * * The load balancing is such that if we get called once every ten * seconds, we will cycle through all the tests in * REACHABILITY_TEST_CYCLE_PERIOD seconds (a bit over 20 minutes). */ void dirserv_test_reachability(time_t now) { /* XXX decide what to do here; see or-talk thread "purging old router * information, revocation." -NM * We can't afford to mess with this in 0.1.2.x. The reason is that * if we stop doing reachability tests on some of routerlist, then * we'll for-sure think they're down, which may have unexpected * effects in other parts of the code. It doesn't hurt much to do * the testing, and directory authorities are easy to upgrade. Let's * wait til 0.2.0. -RD */ // time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; routerlist_t *rl = router_get_routerlist(); static char ctr = 0; int bridge_auth = authdir_mode_bridge(get_options()); SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, router) { const char *id_digest = router->cache_info.identity_digest; if (router_is_me(router)) continue; if (bridge_auth && router->purpose != ROUTER_PURPOSE_BRIDGE) continue; /* bridge authorities only test reachability on bridges */ // if (router->cache_info.published_on > cutoff) // continue; if ((((uint8_t)id_digest[0]) % REACHABILITY_MODULO_PER_TEST) == ctr) { dirserv_single_reachability_test(now, router); } } SMARTLIST_FOREACH_END(router); ctr = (ctr + 1) % REACHABILITY_MODULO_PER_TEST; /* increment ctr */ } /** Given a fingerprint fp which is either set if we're looking for a * v2 status, or zeroes if we're looking for a v3 status, or a NUL-padded * flavor name if we want a flavored v3 status, return a pointer to the * appropriate cached dir object, or NULL if there isn't one available. */ static cached_dir_t * lookup_cached_dir_by_fp(const char *fp) { cached_dir_t *d = NULL; if (tor_digest_is_zero(fp) && cached_consensuses) d = strmap_get(cached_consensuses, "ns"); else if (memchr(fp, '\0', DIGEST_LEN) && cached_consensuses && (d = strmap_get(cached_consensuses, fp))) { /* this here interface is a nasty hack XXXX024 */; } else if (router_digest_is_me(fp) && the_v2_networkstatus) d = the_v2_networkstatus; else if (cached_v2_networkstatus) d = digestmap_get(cached_v2_networkstatus, fp); return d; } /** Remove from fps every networkstatus key where both * a) we have a networkstatus document and * b) it is not newer than cutoff. * * Return 1 if any items were present at all; else return 0. */ int dirserv_remove_old_statuses(smartlist_t *fps, time_t cutoff) { int found_any = 0; SMARTLIST_FOREACH_BEGIN(fps, char *, digest) { cached_dir_t *d = lookup_cached_dir_by_fp(digest); if (!d) continue; found_any = 1; if (d->published <= cutoff) { tor_free(digest); SMARTLIST_DEL_CURRENT(fps, digest); } } SMARTLIST_FOREACH_END(digest); return found_any; } /** Return the cache-info for identity fingerprint fp, or * its extra-info document if extrainfo is true. Return * NULL if not found or if the descriptor is older than * publish_cutoff. */ static const signed_descriptor_t * get_signed_descriptor_by_fp(const char *fp, int extrainfo, time_t publish_cutoff) { if (router_digest_is_me(fp)) { if (extrainfo) return &(router_get_my_extrainfo()->cache_info); else return &(router_get_my_routerinfo()->cache_info); } else { const routerinfo_t *ri = router_get_by_id_digest(fp); if (ri && ri->cache_info.published_on > publish_cutoff) { if (extrainfo) return extrainfo_get_by_descriptor_digest( ri->cache_info.extra_info_digest); else return &ri->cache_info; } } return NULL; } /** Return true iff we have any of the documents (extrainfo or routerdesc) * specified by the fingerprints in fps and spool_src. Used to * decide whether to send a 404. */ int dirserv_have_any_serverdesc(smartlist_t *fps, int spool_src) { time_t publish_cutoff = time(NULL)-ROUTER_MAX_AGE_TO_PUBLISH; SMARTLIST_FOREACH_BEGIN(fps, const char *, fp) { switch (spool_src) { case DIR_SPOOL_EXTRA_BY_DIGEST: if (extrainfo_get_by_descriptor_digest(fp)) return 1; break; case DIR_SPOOL_SERVER_BY_DIGEST: if (router_get_by_descriptor_digest(fp)) return 1; break; case DIR_SPOOL_EXTRA_BY_FP: case DIR_SPOOL_SERVER_BY_FP: if (get_signed_descriptor_by_fp(fp, spool_src == DIR_SPOOL_EXTRA_BY_FP, publish_cutoff)) return 1; break; } } SMARTLIST_FOREACH_END(fp); return 0; } /** Return true iff any of the 256-bit elements in fps is the digest of * a microdescriptor we have. */ int dirserv_have_any_microdesc(const smartlist_t *fps) { microdesc_cache_t *cache = get_microdesc_cache(); SMARTLIST_FOREACH(fps, const char *, fp, if (microdesc_cache_lookup_by_digest256(cache, fp)) return 1); return 0; } /** Return an approximate estimate of the number of bytes that will * be needed to transmit the server descriptors (if is_serverdescs -- * they can be either d/ or fp/ queries) or networkstatus objects (if * !is_serverdescs) listed in fps. If compressed is set, * we guess how large the data will be after compression. * * The return value is an estimate; it might be larger or smaller. **/ size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs, int compressed) { size_t result; tor_assert(fps); if (is_serverdescs) { int n = smartlist_len(fps); const routerinfo_t *me = router_get_my_routerinfo(); result = (me?me->cache_info.signed_descriptor_len:2048) * n; if (compressed) result /= 2; /* observed compressibility is between 35 and 55%. */ } else { result = 0; SMARTLIST_FOREACH(fps, const char *, digest, { cached_dir_t *dir = lookup_cached_dir_by_fp(digest); if (dir) result += compressed ? dir->dir_z_len : dir->dir_len; }); } return result; } /** Given a list of microdescriptor hashes, guess how many bytes will be * needed to transmit them, and return the guess. */ size_t dirserv_estimate_microdesc_size(const smartlist_t *fps, int compressed) { size_t result = smartlist_len(fps) * microdesc_average_size(NULL); if (compressed) result /= 2; return result; } /** When we're spooling data onto our outbuf, add more whenever we dip * below this threshold. */ #define DIRSERV_BUFFER_MIN 16384 /** Spooling helper: called when we have no more data to spool to conn. * Flushes any remaining data to be (un)compressed, and changes the spool * source to NONE. Returns 0 on success, negative on failure. */ static int connection_dirserv_finish_spooling(dir_connection_t *conn) { if (conn->zlib_state) { connection_write_to_buf_zlib("", 0, conn, 1); tor_zlib_free(conn->zlib_state); conn->zlib_state = NULL; } conn->dir_spool_src = DIR_SPOOL_NONE; return 0; } /** Spooling helper: called when we're sending a bunch of server descriptors, * and the outbuf has become too empty. Pulls some entries from * fingerprint_stack, and writes the corresponding servers onto outbuf. If we * run out of entries, flushes the zlib state and sets the spool source to * NONE. Returns 0 on success, negative on failure. */ static int connection_dirserv_add_servers_to_outbuf(dir_connection_t *conn) { int by_fp = (conn->dir_spool_src == DIR_SPOOL_SERVER_BY_FP || conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_FP); int extra = (conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_FP || conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_DIGEST); time_t publish_cutoff = time(NULL)-ROUTER_MAX_AGE_TO_PUBLISH; const or_options_t *options = get_options(); while (smartlist_len(conn->fingerprint_stack) && connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) { const char *body; char *fp = smartlist_pop_last(conn->fingerprint_stack); const signed_descriptor_t *sd = NULL; if (by_fp) { sd = get_signed_descriptor_by_fp(fp, extra, publish_cutoff); } else { sd = extra ? extrainfo_get_by_descriptor_digest(fp) : router_get_by_descriptor_digest(fp); } tor_free(fp); if (!sd) continue; if (!connection_dir_is_encrypted(conn) && !sd->send_unencrypted) { /* we did this check once before (so we could have an accurate size * estimate and maybe send a 404 if somebody asked for only bridges on a * connection), but we need to do it again in case a previously * unknown bridge descriptor has shown up between then and now. */ continue; } /** If we are the bridge authority and the descriptor is a bridge * descriptor, remember that we served this descriptor for desc stats. */ if (options->BridgeAuthoritativeDir && by_fp) { const routerinfo_t *router = router_get_by_id_digest(sd->identity_digest); /* router can be NULL here when the bridge auth is asked for its own * descriptor. */ if (router && router->purpose == ROUTER_PURPOSE_BRIDGE) rep_hist_note_desc_served(sd->identity_digest); } body = signed_descriptor_get_body(sd); if (conn->zlib_state) { /* XXXX024 This 'last' business should actually happen on the last * routerinfo, not on the last fingerprint. */ int last = ! smartlist_len(conn->fingerprint_stack); connection_write_to_buf_zlib(body, sd->signed_descriptor_len, conn, last); if (last) { tor_zlib_free(conn->zlib_state); conn->zlib_state = NULL; } } else { connection_write_to_buf(body, sd->signed_descriptor_len, TO_CONN(conn)); } } if (!smartlist_len(conn->fingerprint_stack)) { /* We just wrote the last one; finish up. */ conn->dir_spool_src = DIR_SPOOL_NONE; smartlist_free(conn->fingerprint_stack); conn->fingerprint_stack = NULL; } return 0; } /** Spooling helper: called when we're sending a bunch of microdescriptors, * and the outbuf has become too empty. Pulls some entries from * fingerprint_stack, and writes the corresponding microdescs onto outbuf. If * we run out of entries, flushes the zlib state and sets the spool source to * NONE. Returns 0 on success, negative on failure. */ static int connection_dirserv_add_microdescs_to_outbuf(dir_connection_t *conn) { microdesc_cache_t *cache = get_microdesc_cache(); while (smartlist_len(conn->fingerprint_stack) && connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) { char *fp256 = smartlist_pop_last(conn->fingerprint_stack); microdesc_t *md = microdesc_cache_lookup_by_digest256(cache, fp256); tor_free(fp256); if (!md || !md->body) continue; if (conn->zlib_state) { /* XXXX024 This 'last' business should actually happen on the last * routerinfo, not on the last fingerprint. */ int last = !smartlist_len(conn->fingerprint_stack); connection_write_to_buf_zlib(md->body, md->bodylen, conn, last); if (last) { tor_zlib_free(conn->zlib_state); conn->zlib_state = NULL; } } else { connection_write_to_buf(md->body, md->bodylen, TO_CONN(conn)); } } if (!smartlist_len(conn->fingerprint_stack)) { conn->dir_spool_src = DIR_SPOOL_NONE; smartlist_free(conn->fingerprint_stack); conn->fingerprint_stack = NULL; } return 0; } /** Spooling helper: Called when we're sending a directory or networkstatus, * and the outbuf has become too empty. Pulls some bytes from * conn-\>cached_dir-\>dir_z, uncompresses them if appropriate, and * puts them on the outbuf. If we run out of entries, flushes the zlib state * and sets the spool source to NONE. Returns 0 on success, negative on * failure. */ static int connection_dirserv_add_dir_bytes_to_outbuf(dir_connection_t *conn) { ssize_t bytes; int64_t remaining; bytes = DIRSERV_BUFFER_MIN - connection_get_outbuf_len(TO_CONN(conn)); tor_assert(bytes > 0); tor_assert(conn->cached_dir); if (bytes < 8192) bytes = 8192; remaining = conn->cached_dir->dir_z_len - conn->cached_dir_offset; if (bytes > remaining) bytes = (ssize_t) remaining; if (conn->zlib_state) { connection_write_to_buf_zlib( conn->cached_dir->dir_z + conn->cached_dir_offset, bytes, conn, bytes == remaining); } else { connection_write_to_buf(conn->cached_dir->dir_z + conn->cached_dir_offset, bytes, TO_CONN(conn)); } conn->cached_dir_offset += bytes; if (conn->cached_dir_offset == (int)conn->cached_dir->dir_z_len) { /* We just wrote the last one; finish up. */ connection_dirserv_finish_spooling(conn); cached_dir_decref(conn->cached_dir); conn->cached_dir = NULL; } return 0; } /** Spooling helper: Called when we're spooling networkstatus objects on * conn, and the outbuf has become too empty. If the current * networkstatus object (in conn-\>cached_dir) has more data, pull data * from there. Otherwise, pop the next fingerprint from fingerprint_stack, * and start spooling the next networkstatus. (A digest of all 0 bytes is * treated as a request for the current consensus.) If we run out of entries, * flushes the zlib state and sets the spool source to NONE. Returns 0 on * success, negative on failure. */ static int connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn) { while (connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) { if (conn->cached_dir) { int uncompressing = (conn->zlib_state != NULL); int r = connection_dirserv_add_dir_bytes_to_outbuf(conn); if (conn->dir_spool_src == DIR_SPOOL_NONE) { /* add_dir_bytes thinks we're done with the cached_dir. But we * may have more cached_dirs! */ conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS; /* This bit is tricky. If we were uncompressing the last * networkstatus, we may need to make a new zlib object to * uncompress the next one. */ if (uncompressing && ! conn->zlib_state && conn->fingerprint_stack && smartlist_len(conn->fingerprint_stack)) { conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD); } } if (r) return r; } else if (conn->fingerprint_stack && smartlist_len(conn->fingerprint_stack)) { /* Add another networkstatus; start serving it. */ char *fp = smartlist_pop_last(conn->fingerprint_stack); cached_dir_t *d = lookup_cached_dir_by_fp(fp); tor_free(fp); if (d) { ++d->refcnt; conn->cached_dir = d; conn->cached_dir_offset = 0; } } else { connection_dirserv_finish_spooling(conn); smartlist_free(conn->fingerprint_stack); conn->fingerprint_stack = NULL; return 0; } } return 0; } /** Called whenever we have flushed some directory data in state * SERVER_WRITING. */ int connection_dirserv_flushed_some(dir_connection_t *conn) { tor_assert(conn->base_.state == DIR_CONN_STATE_SERVER_WRITING); if (connection_get_outbuf_len(TO_CONN(conn)) >= DIRSERV_BUFFER_MIN) return 0; switch (conn->dir_spool_src) { case DIR_SPOOL_EXTRA_BY_DIGEST: case DIR_SPOOL_EXTRA_BY_FP: case DIR_SPOOL_SERVER_BY_DIGEST: case DIR_SPOOL_SERVER_BY_FP: return connection_dirserv_add_servers_to_outbuf(conn); case DIR_SPOOL_MICRODESC: return connection_dirserv_add_microdescs_to_outbuf(conn); case DIR_SPOOL_CACHED_DIR: return connection_dirserv_add_dir_bytes_to_outbuf(conn); case DIR_SPOOL_NETWORKSTATUS: return connection_dirserv_add_networkstatus_bytes_to_outbuf(conn); case DIR_SPOOL_NONE: default: return 0; } } /** Release all storage used by the directory server. */ void dirserv_free_all(void) { dirserv_free_fingerprint_list(); cached_dir_decref(the_directory); clear_cached_dir(&the_runningrouters); cached_dir_decref(the_v2_networkstatus); cached_dir_decref(cached_directory); clear_cached_dir(&cached_runningrouters); digestmap_free(cached_v2_networkstatus, free_cached_dir_); cached_v2_networkstatus = NULL; strmap_free(cached_consensuses, free_cached_dir_); cached_consensuses = NULL; dirserv_clear_measured_bw_cache(); } tor-0.2.4.20/src/or/rendclient.c0000644000175000017500000014447412255745673013222 00000000000000/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file rendclient.c * \brief Client code to access location-hidden services. **/ #include "or.h" #include "circuitbuild.h" #include "circuitlist.h" #include "circuituse.h" #include "config.h" #include "connection.h" #include "connection_edge.h" #include "directory.h" #include "main.h" #include "networkstatus.h" #include "nodelist.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "routerset.h" static extend_info_t *rend_client_get_random_intro_impl( const rend_cache_entry_t *rend_query, const int strict, const int warnings); /** Purge all potentially remotely-detectable state held in the hidden * service client code. Called on SIGNAL NEWNYM. */ void rend_client_purge_state(void) { rend_cache_purge(); rend_client_cancel_descriptor_fetches(); rend_client_purge_last_hid_serv_requests(); } /** Called when we've established a circuit to an introduction point: * send the introduction request. */ void rend_client_introcirc_has_opened(origin_circuit_t *circ) { tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); tor_assert(circ->cpath); log_info(LD_REND,"introcirc is open"); connection_ap_attach_pending(); } /** Send the establish-rendezvous cell along a rendezvous circuit. if * it fails, mark the circ for close and return -1. else return 0. */ static int rend_client_send_establish_rendezvous(origin_circuit_t *circ) { tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); tor_assert(circ->rend_data); log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell"); if (crypto_rand(circ->rend_data->rend_cookie, REND_COOKIE_LEN) < 0) { log_warn(LD_BUG, "Internal error: Couldn't produce random cookie."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return -1; } /* Set timestamp_dirty, because circuit_expire_building expects it, * and the rend cookie also means we've used the circ. */ circ->base_.timestamp_dirty = time(NULL); /* We've attempted to use this circuit. Probe it if we fail */ pathbias_count_use_attempt(circ); if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), RELAY_COMMAND_ESTABLISH_RENDEZVOUS, circ->rend_data->rend_cookie, REND_COOKIE_LEN, circ->cpath->prev)<0) { /* circ is already marked for close */ log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell"); return -1; } return 0; } /** Extend the introduction circuit circ to another valid * introduction point for the hidden service it is trying to connect * to, or mark it and launch a new circuit if we can't extend it. * Return 0 on success or possible success. Return -1 and mark the * introduction circuit for close on permanent failure. * * On failure, the caller is responsible for marking the associated * rendezvous circuit for close. */ static int rend_client_reextend_intro_circuit(origin_circuit_t *circ) { extend_info_t *extend_info; int result; extend_info = rend_client_get_random_intro(circ->rend_data); if (!extend_info) { log_warn(LD_REND, "No usable introduction points left for %s. Closing.", safe_str_client(circ->rend_data->onion_address)); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return -1; } // XXX: should we not re-extend if hs_circ_has_timed_out? if (circ->remaining_relay_early_cells) { log_info(LD_REND, "Re-extending circ %u, this time to %s.", (unsigned)circ->base_.n_circ_id, safe_str_client(extend_info_describe(extend_info))); result = circuit_extend_to_new_exit(circ, extend_info); } else { log_info(LD_REND, "Closing intro circ %u (out of RELAY_EARLY cells).", (unsigned)circ->base_.n_circ_id); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); /* connection_ap_handshake_attach_circuit will launch a new intro circ. */ result = 0; } extend_info_free(extend_info); return result; } /** Return true iff we should send timestamps in our INTRODUCE1 cells */ static int rend_client_should_send_timestamp(void) { if (get_options()->Support022HiddenServices >= 0) return get_options()->Support022HiddenServices; return networkstatus_get_param(NULL, "Support022HiddenServices", 1, 0, 1); } /** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell * down introcirc if possible. */ int rend_client_send_introduction(origin_circuit_t *introcirc, origin_circuit_t *rendcirc) { size_t payload_len; int r, v3_shift = 0; char payload[RELAY_PAYLOAD_SIZE]; char tmp[RELAY_PAYLOAD_SIZE]; rend_cache_entry_t *entry; crypt_path_t *cpath; off_t dh_offset; crypto_pk_t *intro_key = NULL; int status = 0; tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY); tor_assert(introcirc->rend_data); tor_assert(rendcirc->rend_data); tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address, rendcirc->rend_data->onion_address)); #ifndef NON_ANONYMOUS_MODE_ENABLED tor_assert(!(introcirc->build_state->onehop_tunnel)); tor_assert(!(rendcirc->build_state->onehop_tunnel)); #endif if (rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1, &entry) < 1) { log_info(LD_REND, "query %s didn't have valid rend desc in cache. " "Refetching descriptor.", safe_str_client(introcirc->rend_data->onion_address)); rend_client_refetch_v2_renddesc(introcirc->rend_data); { connection_t *conn; while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP, AP_CONN_STATE_CIRCUIT_WAIT, introcirc->rend_data->onion_address))) { conn->state = AP_CONN_STATE_RENDDESC_WAIT; } } status = -1; goto cleanup; } /* first 20 bytes of payload are the hash of Bob's pk */ intro_key = NULL; SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *, intro, { if (tor_memeq(introcirc->build_state->chosen_exit->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN)) { intro_key = intro->intro_key; break; } }); if (!intro_key) { log_info(LD_REND, "Could not find intro key for %s at %s; we " "have a v2 rend desc with %d intro points. " "Trying a different intro point...", safe_str_client(introcirc->rend_data->onion_address), safe_str_client(extend_info_describe( introcirc->build_state->chosen_exit)), smartlist_len(entry->parsed->intro_nodes)); if (rend_client_reextend_intro_circuit(introcirc)) { status = -2; goto perm_err; } else { status = -1; goto cleanup; } } if (crypto_pk_get_digest(intro_key, payload)<0) { log_warn(LD_BUG, "Internal error: couldn't hash public key."); status = -2; goto perm_err; } /* Initialize the pending_final_cpath and start the DH handshake. */ cpath = rendcirc->build_state->pending_final_cpath; if (!cpath) { cpath = rendcirc->build_state->pending_final_cpath = tor_malloc_zero(sizeof(crypt_path_t)); cpath->magic = CRYPT_PATH_MAGIC; if (!(cpath->rend_dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) { log_warn(LD_BUG, "Internal error: couldn't allocate DH."); status = -2; goto perm_err; } if (crypto_dh_generate_public(cpath->rend_dh_handshake_state)<0) { log_warn(LD_BUG, "Internal error: couldn't generate g^x."); status = -2; goto perm_err; } } /* If version is 3, write (optional) auth data and timestamp. */ if (entry->parsed->protocols & (1<<3)) { tmp[0] = 3; /* version 3 of the cell format */ tmp[1] = (uint8_t)introcirc->rend_data->auth_type; /* auth type, if any */ v3_shift = 1; if (introcirc->rend_data->auth_type != REND_NO_AUTH) { set_uint16(tmp+2, htons(REND_DESC_COOKIE_LEN)); memcpy(tmp+4, introcirc->rend_data->descriptor_cookie, REND_DESC_COOKIE_LEN); v3_shift += 2+REND_DESC_COOKIE_LEN; } if (rend_client_should_send_timestamp()) { uint32_t now = (uint32_t)time(NULL); now += 300; now -= now % 600; set_uint32(tmp+v3_shift+1, htonl(now)); } else { set_uint32(tmp+v3_shift+1, 0); } v3_shift += 4; } /* if version 2 only write version number */ else if (entry->parsed->protocols & (1<<2)) { tmp[0] = 2; /* version 2 of the cell format */ } /* write the remaining items into tmp */ if (entry->parsed->protocols & (1<<3) || entry->parsed->protocols & (1<<2)) { /* version 2 format */ extend_info_t *extend_info = rendcirc->build_state->chosen_exit; int klen; /* nul pads */ set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4h(&extend_info->addr)); set_uint16(tmp+v3_shift+5, htons(extend_info->port)); memcpy(tmp+v3_shift+7, extend_info->identity_digest, DIGEST_LEN); klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+v3_shift+7+DIGEST_LEN+2, sizeof(tmp)-(v3_shift+7+DIGEST_LEN+2)); set_uint16(tmp+v3_shift+7+DIGEST_LEN, htons(klen)); memcpy(tmp+v3_shift+7+DIGEST_LEN+2+klen, rendcirc->rend_data->rend_cookie, REND_COOKIE_LEN); dh_offset = v3_shift+7+DIGEST_LEN+2+klen+REND_COOKIE_LEN; } else { /* Version 0. */ strncpy(tmp, rendcirc->build_state->chosen_exit->nickname, (MAX_NICKNAME_LEN+1)); /* nul pads */ memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_data->rend_cookie, REND_COOKIE_LEN); dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN; } if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset, DH_KEY_LEN)<0) { log_warn(LD_BUG, "Internal error: couldn't extract g^x."); status = -2; goto perm_err; } note_crypto_pk_op(REND_CLIENT); /*XXX maybe give crypto_pk_public_hybrid_encrypt a max_len arg, * to avoid buffer overflows? */ r = crypto_pk_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN, sizeof(payload)-DIGEST_LEN, tmp, (int)(dh_offset+DH_KEY_LEN), PK_PKCS1_OAEP_PADDING, 0); if (r<0) { log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed."); status = -2; goto perm_err; } payload_len = DIGEST_LEN + r; tor_assert(payload_len <= RELAY_PAYLOAD_SIZE); /* we overran something */ /* Copy the rendezvous cookie from rendcirc to introcirc, so that * when introcirc gets an ack, we can change the state of the right * rendezvous circuit. */ memcpy(introcirc->rend_data->rend_cookie, rendcirc->rend_data->rend_cookie, REND_COOKIE_LEN); log_info(LD_REND, "Sending an INTRODUCE1 cell"); if (relay_send_command_from_edge(0, TO_CIRCUIT(introcirc), RELAY_COMMAND_INTRODUCE1, payload, payload_len, introcirc->cpath->prev)<0) { /* introcirc is already marked for close. leave rendcirc alone. */ log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell"); status = -2; goto cleanup; } /* Now, we wait for an ACK or NAK on this circuit. */ circuit_change_purpose(TO_CIRCUIT(introcirc), CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT); /* Set timestamp_dirty, because circuit_expire_building expects it * to specify when a circuit entered the _C_INTRODUCE_ACK_WAIT * state. */ introcirc->base_.timestamp_dirty = time(NULL); pathbias_count_use_attempt(introcirc); goto cleanup; perm_err: if (!introcirc->base_.marked_for_close) circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL); circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL); cleanup: memwipe(payload, 0, sizeof(payload)); memwipe(tmp, 0, sizeof(tmp)); return status; } /** Called when a rendezvous circuit is open; sends a establish * rendezvous circuit as appropriate. */ void rend_client_rendcirc_has_opened(origin_circuit_t *circ) { tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); log_info(LD_REND,"rendcirc is open"); /* generate a rendezvous cookie, store it in circ */ if (rend_client_send_establish_rendezvous(circ) < 0) { return; } } /** * Called to close other intro circuits we launched in parallel * due to timeout. */ static void rend_client_close_other_intros(const char *onion_address) { circuit_t *c; /* abort parallel intro circs, if any */ for (c = circuit_get_global_list_(); c; c = c->next) { if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING || c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) && !c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) { origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(c); if (oc->rend_data && !rend_cmp_service_ids(onion_address, oc->rend_data->onion_address)) { log_info(LD_REND|LD_CIRC, "Closing introduction circuit %d that we " "built in parallel (Purpose %d).", oc->global_identifier, c->purpose); circuit_mark_for_close(c, END_CIRC_REASON_TIMEOUT); } } } } /** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell. */ int rend_client_introduction_acked(origin_circuit_t *circ, const uint8_t *request, size_t request_len) { origin_circuit_t *rendcirc; (void) request; // XXXX Use this. if (circ->base_.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { log_warn(LD_PROTOCOL, "Received REND_INTRODUCE_ACK on unexpected circuit %u.", (unsigned)circ->base_.n_circ_id); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); return -1; } tor_assert(circ->build_state->chosen_exit); #ifndef NON_ANONYMOUS_MODE_ENABLED tor_assert(!(circ->build_state->onehop_tunnel)); #endif tor_assert(circ->rend_data); /* For path bias: This circuit was used successfully. Valid * nacks and acks count. */ pathbias_mark_use_success(circ); if (request_len == 0) { /* It's an ACK; the introduction point relayed our introduction request. */ /* Locate the rend circ which is waiting to hear about this ack, * and tell it. */ log_info(LD_REND,"Received ack. Telling rend circ..."); rendcirc = circuit_get_ready_rend_circ_by_rend_data(circ->rend_data); if (rendcirc) { /* remember the ack */ #ifndef NON_ANONYMOUS_MODE_ENABLED tor_assert(!(rendcirc->build_state->onehop_tunnel)); #endif circuit_change_purpose(TO_CIRCUIT(rendcirc), CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED); /* Set timestamp_dirty, because circuit_expire_building expects * it to specify when a circuit entered the * _C_REND_READY_INTRO_ACKED state. */ rendcirc->base_.timestamp_dirty = time(NULL); } else { log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); } /* close the circuit: we won't need it anymore. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCE_ACKED); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); /* close any other intros launched in parallel */ rend_client_close_other_intros(circ->rend_data->onion_address); } else { /* It's a NAK; the introduction point didn't relay our request. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING); /* Remove this intro point from the set of viable introduction * points. If any remain, extend to a new one and try again. * If none remain, refetch the service descriptor. */ log_info(LD_REND, "Got nack for %s from %s...", safe_str_client(circ->rend_data->onion_address), safe_str_client(extend_info_describe(circ->build_state->chosen_exit))); if (rend_client_report_intro_point_failure(circ->build_state->chosen_exit, circ->rend_data, INTRO_POINT_FAILURE_GENERIC)>0) { /* There are introduction points left. Re-extend the circuit to * another intro point and try again. */ int result = rend_client_reextend_intro_circuit(circ); /* XXXX If that call failed, should we close the rend circuit, * too? */ return result; } } return 0; } /** The period for which a hidden service directory cannot be queried for * the same descriptor ID again. */ #define REND_HID_SERV_DIR_REQUERY_PERIOD (15 * 60) /** Contains the last request times to hidden service directories for * certain queries; each key is a string consisting of the * concatenation of a base32-encoded HS directory identity digest, a * base32-encoded HS descriptor ID, and a hidden service address * (without the ".onion" part); each value is a pointer to a time_t * holding the time of the last request for that descriptor ID to that * HS directory. */ static strmap_t *last_hid_serv_requests_ = NULL; /** Returns last_hid_serv_requests_, initializing it to a new strmap if * necessary. */ static strmap_t * get_last_hid_serv_requests(void) { if (!last_hid_serv_requests_) last_hid_serv_requests_ = strmap_new(); return last_hid_serv_requests_; } #define LAST_HID_SERV_REQUEST_KEY_LEN (REND_DESC_ID_V2_LEN_BASE32 + \ REND_DESC_ID_V2_LEN_BASE32 + \ REND_SERVICE_ID_LEN_BASE32) /** Look up the last request time to hidden service directory hs_dir * for descriptor ID desc_id_base32 for the service specified in * rend_query. If set is non-zero, * assign the current time now and return that. Otherwise, return * the most recent request time, or 0 if no such request has been sent * before. */ static time_t lookup_last_hid_serv_request(routerstatus_t *hs_dir, const char *desc_id_base32, const rend_data_t *rend_query, time_t now, int set) { char hsdir_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; char hsdir_desc_comb_id[LAST_HID_SERV_REQUEST_KEY_LEN + 1]; time_t *last_request_ptr; strmap_t *last_hid_serv_requests = get_last_hid_serv_requests(); base32_encode(hsdir_id_base32, sizeof(hsdir_id_base32), hs_dir->identity_digest, DIGEST_LEN); tor_snprintf(hsdir_desc_comb_id, sizeof(hsdir_desc_comb_id), "%s%s%s", hsdir_id_base32, desc_id_base32, rend_query->onion_address); /* XXX023 tor_assert(strlen(hsdir_desc_comb_id) == LAST_HID_SERV_REQUEST_KEY_LEN); */ if (set) { time_t *oldptr; last_request_ptr = tor_malloc_zero(sizeof(time_t)); *last_request_ptr = now; oldptr = strmap_set(last_hid_serv_requests, hsdir_desc_comb_id, last_request_ptr); tor_free(oldptr); } else last_request_ptr = strmap_get_lc(last_hid_serv_requests, hsdir_desc_comb_id); return (last_request_ptr) ? *last_request_ptr : 0; } /** Clean the history of request times to hidden service directories, so that * it does not contain requests older than REND_HID_SERV_DIR_REQUERY_PERIOD * seconds any more. */ static void directory_clean_last_hid_serv_requests(time_t now) { strmap_iter_t *iter; time_t cutoff = now - REND_HID_SERV_DIR_REQUERY_PERIOD; strmap_t *last_hid_serv_requests = get_last_hid_serv_requests(); for (iter = strmap_iter_init(last_hid_serv_requests); !strmap_iter_done(iter); ) { const char *key; void *val; time_t *ent; strmap_iter_get(iter, &key, &val); ent = (time_t *) val; if (*ent < cutoff) { iter = strmap_iter_next_rmv(last_hid_serv_requests, iter); tor_free(ent); } else { iter = strmap_iter_next(last_hid_serv_requests, iter); } } } /** Remove all requests related to the hidden service named * onion_address from the history of times of requests to * hidden service directories. */ static void purge_hid_serv_from_last_hid_serv_requests(const char *onion_address) { strmap_iter_t *iter; strmap_t *last_hid_serv_requests = get_last_hid_serv_requests(); /* XXX023 tor_assert(strlen(onion_address) == REND_SERVICE_ID_LEN_BASE32); */ for (iter = strmap_iter_init(last_hid_serv_requests); !strmap_iter_done(iter); ) { const char *key; void *val; strmap_iter_get(iter, &key, &val); /* XXX023 tor_assert(strlen(key) == LAST_HID_SERV_REQUEST_KEY_LEN); */ if (tor_memeq(key + LAST_HID_SERV_REQUEST_KEY_LEN - REND_SERVICE_ID_LEN_BASE32, onion_address, REND_SERVICE_ID_LEN_BASE32)) { iter = strmap_iter_next_rmv(last_hid_serv_requests, iter); tor_free(val); } else { iter = strmap_iter_next(last_hid_serv_requests, iter); } } } /** Purge the history of request times to hidden service directories, * so that future lookups of an HS descriptor will not fail because we * accessed all of the HSDir relays responsible for the descriptor * recently. */ void rend_client_purge_last_hid_serv_requests(void) { /* Don't create the table if it doesn't exist yet (and it may very * well not exist if the user hasn't accessed any HSes)... */ strmap_t *old_last_hid_serv_requests = last_hid_serv_requests_; /* ... and let get_last_hid_serv_requests re-create it for us if * necessary. */ last_hid_serv_requests_ = NULL; if (old_last_hid_serv_requests != NULL) { log_info(LD_REND, "Purging client last-HS-desc-request-time table"); strmap_free(old_last_hid_serv_requests, tor_free_); } } /** Determine the responsible hidden service directories for desc_id * and fetch the descriptor with that ID from one of them. Only * send a request to a hidden service directory that we have not yet tried * during this attempt to connect to this hidden service; on success, return 1, * in the case that no hidden service directory is left to ask for the * descriptor, return 0, and in case of a failure -1. */ static int directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query) { smartlist_t *responsible_dirs = smartlist_new(); routerstatus_t *hs_dir; char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; time_t now = time(NULL); char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64]; int tor2web_mode = get_options()->Tor2webMode; tor_assert(desc_id); tor_assert(rend_query); /* Determine responsible dirs. Even if we can't get all we want, * work with the ones we have. If it's empty, we'll notice below. */ hid_serv_get_responsible_directories(responsible_dirs, desc_id); base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, DIGEST_LEN); /* Only select those hidden service directories to which we did not send * a request recently and for which we have a router descriptor here. */ /* Clean request history first. */ directory_clean_last_hid_serv_requests(now); SMARTLIST_FOREACH(responsible_dirs, routerstatus_t *, dir, { time_t last = lookup_last_hid_serv_request( dir, desc_id_base32, rend_query, 0, 0); const node_t *node = node_get_by_id(dir->identity_digest); if (last + REND_HID_SERV_DIR_REQUERY_PERIOD >= now || !node || !node_has_descriptor(node)) SMARTLIST_DEL_CURRENT(responsible_dirs, dir); }); hs_dir = smartlist_choose(responsible_dirs); smartlist_free(responsible_dirs); if (!hs_dir) { log_info(LD_REND, "Could not pick one of the responsible hidden " "service directories, because we requested them all " "recently without success."); return 0; } /* Remember that we are requesting a descriptor from this hidden service * directory now. */ lookup_last_hid_serv_request(hs_dir, desc_id_base32, rend_query, now, 1); /* Encode descriptor cookie for logging purposes. */ if (rend_query->auth_type != REND_NO_AUTH) { if (base64_encode(descriptor_cookie_base64, sizeof(descriptor_cookie_base64), rend_query->descriptor_cookie, REND_DESC_COOKIE_LEN)<0) { log_warn(LD_BUG, "Could not base64-encode descriptor cookie."); return 0; } /* Remove == signs and newline. */ descriptor_cookie_base64[strlen(descriptor_cookie_base64)-3] = '\0'; } else { strlcpy(descriptor_cookie_base64, "(none)", sizeof(descriptor_cookie_base64)); } /* Send fetch request. (Pass query and possibly descriptor cookie so that * they can be written to the directory connection and be referred to when * the response arrives. */ directory_initiate_command_routerstatus_rend(hs_dir, DIR_PURPOSE_FETCH_RENDDESC_V2, ROUTER_PURPOSE_GENERAL, tor2web_mode?DIRIND_ONEHOP:DIRIND_ANONYMOUS, desc_id_base32, NULL, 0, 0, rend_query); log_info(LD_REND, "Sending fetch request for v2 descriptor for " "service '%s' with descriptor ID '%s', auth type %d, " "and descriptor cookie '%s' to hidden service " "directory %s", rend_query->onion_address, desc_id_base32, rend_query->auth_type, (rend_query->auth_type == REND_NO_AUTH ? "[none]" : escaped_safe_str_client(descriptor_cookie_base64)), routerstatus_describe(hs_dir)); return 1; } /** Unless we already have a descriptor for rend_query with at least * one (possibly) working introduction point in it, start a connection to a * hidden service directory to fetch a v2 rendezvous service descriptor. */ void rend_client_refetch_v2_renddesc(const rend_data_t *rend_query) { char descriptor_id[DIGEST_LEN]; int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS]; int i, tries_left; rend_cache_entry_t *e = NULL; tor_assert(rend_query); /* Are we configured to fetch descriptors? */ if (!get_options()->FetchHidServDescriptors) { log_warn(LD_REND, "We received an onion address for a v2 rendezvous " "service descriptor, but are not fetching service descriptors."); return; } /* Before fetching, check if we already have a usable descriptor here. */ if (rend_cache_lookup_entry(rend_query->onion_address, -1, &e) > 0 && rend_client_any_intro_points_usable(e)) { log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we " "already have a usable descriptor here. Not fetching."); return; } log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s", safe_str_client(rend_query->onion_address)); /* Randomly iterate over the replicas until a descriptor can be fetched * from one of the consecutive nodes, or no options are left. */ tries_left = REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; for (i = 0; i < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; i++) replicas_left_to_try[i] = i; while (tries_left > 0) { int rand = crypto_rand_int(tries_left); int chosen_replica = replicas_left_to_try[rand]; replicas_left_to_try[rand] = replicas_left_to_try[--tries_left]; if (rend_compute_v2_desc_id(descriptor_id, rend_query->onion_address, rend_query->auth_type == REND_STEALTH_AUTH ? rend_query->descriptor_cookie : NULL, time(NULL), chosen_replica) < 0) { log_warn(LD_REND, "Internal error: Computing v2 rendezvous " "descriptor ID did not succeed."); /* * Hmm, can this write anything to descriptor_id and still fail? * Let's clear it just to be safe. * * From here on, any returns should goto done which clears * descriptor_id so we don't leave key-derived material on the stack. */ goto done; } if (directory_get_from_hs_dir(descriptor_id, rend_query) != 0) goto done; /* either success or failure, but we're done */ } /* If we come here, there are no hidden service directories left. */ log_info(LD_REND, "Could not pick one of the responsible hidden " "service directories to fetch descriptors, because " "we already tried them all unsuccessfully."); /* Close pending connections. */ rend_client_desc_trynow(rend_query->onion_address); done: memwipe(descriptor_id, 0, sizeof(descriptor_id)); return; } /** Cancel all rendezvous descriptor fetches currently in progress. */ void rend_client_cancel_descriptor_fetches(void) { smartlist_t *connection_array = get_connection_array(); SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) { if (conn->type == CONN_TYPE_DIR && (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC || conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2)) { /* It's a rendezvous descriptor fetch in progress -- cancel it * by marking the connection for close. * * Even if this connection has already reached EOF, this is * enough to make sure that if the descriptor hasn't been * processed yet, it won't be. See the end of * connection_handle_read; connection_reached_eof (indirectly) * processes whatever response the connection received. */ const rend_data_t *rd = (TO_DIR_CONN(conn))->rend_data; if (!rd) { log_warn(LD_BUG | LD_REND, "Marking for close dir conn fetching rendezvous " "descriptor for unknown service!"); } else { log_debug(LD_REND, "Marking for close dir conn fetching " "rendezvous descriptor for service %s", safe_str(rd->onion_address)); } connection_mark_for_close(conn); } } SMARTLIST_FOREACH_END(conn); } /** Mark failed_intro as a failed introduction point for the * hidden service specified by rend_query. If the HS now has no * usable intro points, or we do not have an HS descriptor for it, * then launch a new renddesc fetch. * * If failure_type is INTRO_POINT_FAILURE_GENERIC, remove the * intro point from (our parsed copy of) the HS descriptor. * * If failure_type is INTRO_POINT_FAILURE_TIMEOUT, mark the * intro point as 'timed out'; it will not be retried until the * current hidden service connection attempt has ended or it has * appeared in a newly fetched rendezvous descriptor. * * If failure_type is INTRO_POINT_FAILURE_UNREACHABLE, * increment the intro point's reachability-failure count; if it has * now failed MAX_INTRO_POINT_REACHABILITY_FAILURES or more times, * remove the intro point from (our parsed copy of) the HS descriptor. * * Return -1 if error, 0 if no usable intro points remain or service * unrecognized, 1 if recognized and some intro points remain. */ int rend_client_report_intro_point_failure(extend_info_t *failed_intro, const rend_data_t *rend_query, unsigned int failure_type) { int i, r; rend_cache_entry_t *ent; connection_t *conn; r = rend_cache_lookup_entry(rend_query->onion_address, -1, &ent); if (r<0) { log_warn(LD_BUG, "Malformed service ID %s.", escaped_safe_str_client(rend_query->onion_address)); return -1; } if (r==0) { log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.", escaped_safe_str_client(rend_query->onion_address)); rend_client_refetch_v2_renddesc(rend_query); return 0; } for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) { rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i); if (tor_memeq(failed_intro->identity_digest, intro->extend_info->identity_digest, DIGEST_LEN)) { switch (failure_type) { default: log_warn(LD_BUG, "Unknown failure type %u. Removing intro point.", failure_type); tor_fragile_assert(); /* fall through */ case INTRO_POINT_FAILURE_GENERIC: rend_intro_point_free(intro); smartlist_del(ent->parsed->intro_nodes, i); break; case INTRO_POINT_FAILURE_TIMEOUT: intro->timed_out = 1; break; case INTRO_POINT_FAILURE_UNREACHABLE: ++(intro->unreachable_count); { int zap_intro_point = intro->unreachable_count >= MAX_INTRO_POINT_REACHABILITY_FAILURES; log_info(LD_REND, "Failed to reach this intro point %u times.%s", intro->unreachable_count, zap_intro_point ? " Removing from descriptor.": ""); if (zap_intro_point) { rend_intro_point_free(intro); smartlist_del(ent->parsed->intro_nodes, i); } } break; } break; } } if (! rend_client_any_intro_points_usable(ent)) { log_info(LD_REND, "No more intro points remain for %s. Re-fetching descriptor.", escaped_safe_str_client(rend_query->onion_address)); rend_client_refetch_v2_renddesc(rend_query); /* move all pending streams back to renddesc_wait */ while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP, AP_CONN_STATE_CIRCUIT_WAIT, rend_query->onion_address))) { conn->state = AP_CONN_STATE_RENDDESC_WAIT; } return 0; } log_info(LD_REND,"%d options left for %s.", smartlist_len(ent->parsed->intro_nodes), escaped_safe_str_client(rend_query->onion_address)); return 1; } /** Called when we receive a RENDEZVOUS_ESTABLISHED cell; changes the state of * the circuit to C_REND_READY. */ int rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request, size_t request_len) { (void) request; (void) request_len; /* we just got an ack for our establish-rendezvous. switch purposes. */ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) { log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. " "Closing circ."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); return -1; } log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for " "rendezvous."); circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_READY); /* Set timestamp_dirty, because circuit_expire_building expects it * to specify when a circuit entered the _C_REND_READY state. */ circ->base_.timestamp_dirty = time(NULL); /* From a path bias point of view, this circuit is now successfully used. * Waiting any longer opens us up to attacks from Bob. He could induce * Alice to attempt to connect to his hidden service and never reply * to her rend requests */ pathbias_mark_use_success(circ); /* XXXX This is a pretty brute-force approach. It'd be better to * attach only the connections that are waiting on this circuit, rather * than trying to attach them all. See comments bug 743. */ /* If we already have the introduction circuit built, make sure we send * the INTRODUCE cell _now_ */ connection_ap_attach_pending(); return 0; } /** Bob sent us a rendezvous cell; join the circuits. */ int rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, size_t request_len) { crypt_path_t *hop; char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; if ((circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY && circ->base_.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) || !circ->build_state->pending_final_cpath) { log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not " "expecting it. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); return -1; } if (request_len != DH_KEY_LEN+DIGEST_LEN) { log_warn(LD_PROTOCOL,"Incorrect length (%d) on RENDEZVOUS2 cell.", (int)request_len); goto err; } log_info(LD_REND,"Got RENDEZVOUS2 cell from hidden service."); /* first DH_KEY_LEN bytes are g^y from bob. Finish the dh handshake...*/ tor_assert(circ->build_state); tor_assert(circ->build_state->pending_final_cpath); hop = circ->build_state->pending_final_cpath; tor_assert(hop->rend_dh_handshake_state); if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, hop->rend_dh_handshake_state, (char*)request, DH_KEY_LEN, keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) { log_warn(LD_GENERAL, "Couldn't complete DH handshake."); goto err; } /* ... and set up cpath. */ if (circuit_init_cpath_crypto(hop, keys+DIGEST_LEN, 0)<0) goto err; /* Check whether the digest is right... */ if (tor_memneq(keys, request+DH_KEY_LEN, DIGEST_LEN)) { log_warn(LD_PROTOCOL, "Incorrect digest of key material."); goto err; } crypto_dh_free(hop->rend_dh_handshake_state); hop->rend_dh_handshake_state = NULL; /* All is well. Extend the circuit. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_REND_JOINED); hop->state = CPATH_STATE_OPEN; /* set the windows to default. these are the windows * that alice thinks bob has. */ hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; /* Now that this circuit has finished connecting to its destination, * make sure circuit_get_open_circ_or_launch is willing to return it * so we can actually use it. */ circ->hs_circ_has_timed_out = 0; onion_append_to_cpath(&circ->cpath, hop); circ->build_state->pending_final_cpath = NULL; /* prevent double-free */ circuit_try_attaching_streams(circ); memwipe(keys, 0, sizeof(keys)); return 0; err: memwipe(keys, 0, sizeof(keys)); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); return -1; } /** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that are * waiting on query. If there's a working cache entry here with at * least one intro point, move them to the next state. */ void rend_client_desc_trynow(const char *query) { entry_connection_t *conn; rend_cache_entry_t *entry; const rend_data_t *rend_data; time_t now = time(NULL); smartlist_t *conns = get_connection_array(); SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { if (base_conn->type != CONN_TYPE_AP || base_conn->state != AP_CONN_STATE_RENDDESC_WAIT || base_conn->marked_for_close) continue; conn = TO_ENTRY_CONN(base_conn); rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data; if (!rend_data) continue; if (rend_cmp_service_ids(query, rend_data->onion_address)) continue; assert_connection_ok(base_conn, now); if (rend_cache_lookup_entry(rend_data->onion_address, -1, &entry) == 1 && rend_client_any_intro_points_usable(entry)) { /* either this fetch worked, or it failed but there was a * valid entry from before which we should reuse */ log_info(LD_REND,"Rend desc is usable. Launching circuits."); base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; /* restart their timeout values, so they get a fair shake at * connecting to the hidden service. */ base_conn->timestamp_created = now; base_conn->timestamp_lastread = now; base_conn->timestamp_lastwritten = now; if (connection_ap_handshake_attach_circuit(conn) < 0) { /* it will never work */ log_warn(LD_REND,"Rendezvous attempt failed. Closing."); if (!base_conn->marked_for_close) connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); } } else { /* 404, or fetch didn't get that far */ log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is " "unavailable (try again later).", safe_str_client(query)); connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED); rend_client_note_connection_attempt_ended(query); } } SMARTLIST_FOREACH_END(base_conn); } /** Clear temporary state used only during an attempt to connect to * the hidden service named onion_address. Called when a * connection attempt has ended; may be called occasionally at other * times, and should be reasonably harmless. */ void rend_client_note_connection_attempt_ended(const char *onion_address) { rend_cache_entry_t *cache_entry = NULL; rend_cache_lookup_entry(onion_address, -1, &cache_entry); log_info(LD_REND, "Connection attempt for %s has ended; " "cleaning up temporary state.", safe_str_client(onion_address)); /* Clear the timed_out flag on all remaining intro points for this HS. */ if (cache_entry != NULL) { SMARTLIST_FOREACH(cache_entry->parsed->intro_nodes, rend_intro_point_t *, ip, ip->timed_out = 0; ); } /* Remove the HS's entries in last_hid_serv_requests. */ purge_hid_serv_from_last_hid_serv_requests(onion_address); } /** Return a newly allocated extend_info_t* for a randomly chosen introduction * point for the named hidden service. Return NULL if all introduction points * have been tried and failed. */ extend_info_t * rend_client_get_random_intro(const rend_data_t *rend_query) { extend_info_t *result; rend_cache_entry_t *entry; if (rend_cache_lookup_entry(rend_query->onion_address, -1, &entry) < 1) { log_warn(LD_REND, "Query '%s' didn't have valid rend desc in cache. Failing.", safe_str_client(rend_query->onion_address)); return NULL; } /* See if we can get a node that complies with ExcludeNodes */ if ((result = rend_client_get_random_intro_impl(entry, 1, 1))) return result; /* If not, and StrictNodes is not set, see if we can return any old node */ if (!get_options()->StrictNodes) return rend_client_get_random_intro_impl(entry, 0, 1); return NULL; } /** As rend_client_get_random_intro, except assume that StrictNodes is set * iff strict is true. If warnings is false, don't complain * to the user when we're out of nodes, even if StrictNodes is true. */ static extend_info_t * rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, const int strict, const int warnings) { int i; rend_intro_point_t *intro; const or_options_t *options = get_options(); smartlist_t *usable_nodes; int n_excluded = 0; /* We'll keep a separate list of the usable nodes. If this becomes empty, * no nodes are usable. */ usable_nodes = smartlist_new(); smartlist_add_all(usable_nodes, entry->parsed->intro_nodes); /* Remove the intro points that have timed out during this HS * connection attempt from our list of usable nodes. */ SMARTLIST_FOREACH(usable_nodes, rend_intro_point_t *, ip, if (ip->timed_out) { SMARTLIST_DEL_CURRENT(usable_nodes, ip); }); again: if (smartlist_len(usable_nodes) == 0) { if (n_excluded && get_options()->StrictNodes && warnings) { /* We only want to warn if StrictNodes is really set. Otherwise * we're just about to retry anyways. */ log_warn(LD_REND, "All introduction points for hidden service are " "at excluded relays, and StrictNodes is set. Skipping."); } smartlist_free(usable_nodes); return NULL; } i = crypto_rand_int(smartlist_len(usable_nodes)); intro = smartlist_get(usable_nodes, i); /* Do we need to look up the router or is the extend info complete? */ if (!intro->extend_info->onion_key) { const node_t *node; extend_info_t *new_extend_info; if (tor_digest_is_zero(intro->extend_info->identity_digest)) node = node_get_by_hex_id(intro->extend_info->nickname); else node = node_get_by_id(intro->extend_info->identity_digest); if (!node) { log_info(LD_REND, "Unknown router with nickname '%s'; trying another.", intro->extend_info->nickname); smartlist_del(usable_nodes, i); goto again; } new_extend_info = extend_info_from_node(node, 0); if (!new_extend_info) { log_info(LD_REND, "We don't have a descriptor for the intro-point relay " "'%s'; trying another.", extend_info_describe(intro->extend_info)); smartlist_del(usable_nodes, i); goto again; } else { extend_info_free(intro->extend_info); intro->extend_info = new_extend_info; } tor_assert(intro->extend_info != NULL); } /* Check if we should refuse to talk to this router. */ if (strict && routerset_contains_extendinfo(options->ExcludeNodes, intro->extend_info)) { n_excluded++; smartlist_del(usable_nodes, i); goto again; } smartlist_free(usable_nodes); return extend_info_dup(intro->extend_info); } /** Return true iff any introduction points still listed in entry are * usable. */ int rend_client_any_intro_points_usable(const rend_cache_entry_t *entry) { extend_info_t *extend_info = rend_client_get_random_intro_impl(entry, get_options()->StrictNodes, 0); int rv = (extend_info != NULL); extend_info_free(extend_info); return rv; } /** Client-side authorizations for hidden services; map of onion address to * rend_service_authorization_t*. */ static strmap_t *auth_hid_servs = NULL; /** Look up the client-side authorization for the hidden service with * onion_address. Return NULL if no authorization is available for * that address. */ rend_service_authorization_t* rend_client_lookup_service_authorization(const char *onion_address) { tor_assert(onion_address); if (!auth_hid_servs) return NULL; return strmap_get(auth_hid_servs, onion_address); } /** Helper: Free storage held by rend_service_authorization_t. */ static void rend_service_authorization_free(rend_service_authorization_t *auth) { tor_free(auth); } /** Helper for strmap_free. */ static void rend_service_authorization_strmap_item_free(void *service_auth) { rend_service_authorization_free(service_auth); } /** Release all the storage held in auth_hid_servs. */ void rend_service_authorization_free_all(void) { if (!auth_hid_servs) { return; } strmap_free(auth_hid_servs, rend_service_authorization_strmap_item_free); auth_hid_servs = NULL; } /** Parse config_line as a client-side authorization for a hidden * service and add it to the local map of hidden service authorizations. * Return 0 for success and -1 for failure. */ int rend_parse_service_authorization(const or_options_t *options, int validate_only) { config_line_t *line; int res = -1; strmap_t *parsed = strmap_new(); smartlist_t *sl = smartlist_new(); rend_service_authorization_t *auth = NULL; char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2]; char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_BASE64+2+1]; for (line = options->HidServAuth; line; line = line->next) { char *onion_address, *descriptor_cookie; int auth_type_val = 0; auth = NULL; SMARTLIST_FOREACH(sl, char *, c, tor_free(c);); smartlist_clear(sl); smartlist_split_string(sl, line->value, " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3); if (smartlist_len(sl) < 2) { log_warn(LD_CONFIG, "Configuration line does not consist of " "\"onion-address authorization-cookie [service-name]\": " "'%s'", line->value); goto err; } auth = tor_malloc_zero(sizeof(rend_service_authorization_t)); /* Parse onion address. */ onion_address = smartlist_get(sl, 0); if (strlen(onion_address) != REND_SERVICE_ADDRESS_LEN || strcmpend(onion_address, ".onion")) { log_warn(LD_CONFIG, "Onion address has wrong format: '%s'", onion_address); goto err; } strlcpy(auth->onion_address, onion_address, REND_SERVICE_ID_LEN_BASE32+1); if (!rend_valid_service_id(auth->onion_address)) { log_warn(LD_CONFIG, "Onion address has wrong format: '%s'", onion_address); goto err; } /* Parse descriptor cookie. */ descriptor_cookie = smartlist_get(sl, 1); if (strlen(descriptor_cookie) != REND_DESC_COOKIE_LEN_BASE64) { log_warn(LD_CONFIG, "Authorization cookie has wrong length: '%s'", descriptor_cookie); goto err; } /* Add trailing zero bytes (AA) to make base64-decoding happy. */ tor_snprintf(descriptor_cookie_base64ext, REND_DESC_COOKIE_LEN_BASE64+2+1, "%sAA", descriptor_cookie); if (base64_decode(descriptor_cookie_tmp, sizeof(descriptor_cookie_tmp), descriptor_cookie_base64ext, strlen(descriptor_cookie_base64ext)) < 0) { log_warn(LD_CONFIG, "Decoding authorization cookie failed: '%s'", descriptor_cookie); goto err; } auth_type_val = (((uint8_t)descriptor_cookie_tmp[16]) >> 4) + 1; if (auth_type_val < 1 || auth_type_val > 2) { log_warn(LD_CONFIG, "Authorization cookie has unknown authorization " "type encoded."); goto err; } auth->auth_type = auth_type_val == 1 ? REND_BASIC_AUTH : REND_STEALTH_AUTH; memcpy(auth->descriptor_cookie, descriptor_cookie_tmp, REND_DESC_COOKIE_LEN); if (strmap_get(parsed, auth->onion_address)) { log_warn(LD_CONFIG, "Duplicate authorization for the same hidden " "service."); goto err; } strmap_set(parsed, auth->onion_address, auth); auth = NULL; } res = 0; goto done; err: res = -1; done: rend_service_authorization_free(auth); SMARTLIST_FOREACH(sl, char *, c, tor_free(c);); smartlist_free(sl); if (!validate_only && res == 0) { rend_service_authorization_free_all(); auth_hid_servs = parsed; } else { strmap_free(parsed, rend_service_authorization_strmap_item_free); } memwipe(descriptor_cookie_tmp, 0, sizeof(descriptor_cookie_tmp)); memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext)); return res; } tor-0.2.4.20/src/or/or.h0000644000175000017500000061540212255745673011512 00000000000000/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file or.h * \brief Master header file for Tor-specific functionality. **/ #ifndef TOR_OR_H #define TOR_OR_H #include "orconfig.h" #ifdef __COVERITY__ /* If we're building for a static analysis, turn on all the off-by-default * features. */ #ifndef INSTRUMENT_DOWNLOADS #define INSTRUMENT_DOWNLOADS 1 #endif #endif #ifdef _WIN32 #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 #endif #define WIN32_LEAN_AND_MEAN #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_SYS_PARAM_H #include /* FreeBSD needs this to know what version it is */ #endif #include "torint.h" #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_SYS_FCNTL_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_UN_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_ASSERT_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef _WIN32 #include #include #include #include #endif #ifdef USE_BUFFEREVENTS #include #include #include #endif #include "crypto.h" #include "tortls.h" #include "../common/torlog.h" #include "container.h" #include "torgzip.h" #include "address.h" #include "compat_libevent.h" #include "ht.h" #include "replaycache.h" #include "crypto_curve25519.h" /* These signals are defined to help handle_control_signal work. */ #ifndef SIGHUP #define SIGHUP 1 #endif #ifndef SIGINT #define SIGINT 2 #endif #ifndef SIGUSR1 #define SIGUSR1 10 #endif #ifndef SIGUSR2 #define SIGUSR2 12 #endif #ifndef SIGTERM #define SIGTERM 15 #endif /* Controller signals start at a high number so we don't * conflict with system-defined signals. */ #define SIGNEWNYM 129 #define SIGCLEARDNSCACHE 130 #if (SIZEOF_CELL_T != 0) /* On Irix, stdlib.h defines a cell_t type, so we need to make sure * that our stuff always calls cell_t something different. */ #define cell_t tor_cell_t #endif #ifdef ENABLE_TOR2WEB_MODE #define NON_ANONYMOUS_MODE_ENABLED 1 #endif /** Length of longest allowable configured nickname. */ #define MAX_NICKNAME_LEN 19 /** Length of a router identity encoded as a hexadecimal digest, plus * possible dollar sign. */ #define MAX_HEX_NICKNAME_LEN (HEX_DIGEST_LEN+1) /** Maximum length of verbose router identifier: dollar sign, hex ID digest, * equal sign or tilde, nickname. */ #define MAX_VERBOSE_NICKNAME_LEN (1+HEX_DIGEST_LEN+1+MAX_NICKNAME_LEN) /** Maximum size, in bytes, for resized buffers. */ #define MAX_BUF_SIZE ((1<<24)-1) /* 16MB-1 */ /** Maximum size, in bytes, for any directory object that we've downloaded. */ #define MAX_DIR_DL_SIZE MAX_BUF_SIZE /** For HTTP parsing: Maximum number of bytes we'll accept in the headers * of an HTTP request or response. */ #define MAX_HEADERS_SIZE 50000 /** Maximum size, in bytes, for any directory object that we're accepting * as an upload. */ #define MAX_DIR_UL_SIZE MAX_BUF_SIZE /** Maximum size, in bytes, of a single router descriptor uploaded to us * as a directory authority. Caches and clients fetch whatever descriptors * the authorities tell them to fetch, and don't care about size. */ #define MAX_DESCRIPTOR_UPLOAD_SIZE 20000 /** Maximum size of a single extrainfo document, as above. */ #define MAX_EXTRAINFO_UPLOAD_SIZE 50000 /** How long do we keep DNS cache entries before purging them (regardless of * their TTL)? */ #define MAX_DNS_ENTRY_AGE (30*60) /** How long do we cache/tell clients to cache DNS records when no TTL is * known? */ #define DEFAULT_DNS_TTL (30*60) /** How long can a TTL be before we stop believing it? */ #define MAX_DNS_TTL (3*60*60) /** How small can a TTL be before we stop believing it? Provides rudimentary * pinning. */ #define MIN_DNS_TTL 60 /** How often do we rotate onion keys? */ #define MIN_ONION_KEY_LIFETIME (7*24*60*60) /** How often do we rotate TLS contexts? */ #define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60) /** How old do we allow a router to get before removing it * from the router list? In seconds. */ #define ROUTER_MAX_AGE (60*60*48) /** How old can a router get before we (as a server) will no longer * consider it live? In seconds. */ #define ROUTER_MAX_AGE_TO_PUBLISH (60*60*24) /** How old do we let a saved descriptor get before force-removing it? */ #define OLD_ROUTER_DESC_MAX_AGE (60*60*24*5) /** Possible rules for generating circuit IDs on an OR connection. */ typedef enum { CIRC_ID_TYPE_LOWER=0, /**< Pick from 0..1<<15-1. */ CIRC_ID_TYPE_HIGHER=1, /**< Pick from 1<<15..1<<16-1. */ /** The other side of a connection is an OP: never create circuits to it, * and let it use any circuit ID it wants. */ CIRC_ID_TYPE_NEITHER=2 } circ_id_type_t; #define CONN_TYPE_MIN_ 3 /** Type for sockets listening for OR connections. */ #define CONN_TYPE_OR_LISTENER 3 /** A bidirectional TLS connection transmitting a sequence of cells. * May be from an OR to an OR, or from an OP to an OR. */ #define CONN_TYPE_OR 4 /** A TCP connection from an onion router to a stream's destination. */ #define CONN_TYPE_EXIT 5 /** Type for sockets listening for SOCKS connections. */ #define CONN_TYPE_AP_LISTENER 6 /** A SOCKS proxy connection from the user application to the onion * proxy. */ #define CONN_TYPE_AP 7 /** Type for sockets listening for HTTP connections to the directory server. */ #define CONN_TYPE_DIR_LISTENER 8 /** Type for HTTP connections to the directory server. */ #define CONN_TYPE_DIR 9 /** Connection from the main process to a CPU worker process. */ #define CONN_TYPE_CPUWORKER 10 /** Type for listening for connections from user interface process. */ #define CONN_TYPE_CONTROL_LISTENER 11 /** Type for connections from user interface process. */ #define CONN_TYPE_CONTROL 12 /** Type for sockets listening for transparent connections redirected by pf or * netfilter. */ #define CONN_TYPE_AP_TRANS_LISTENER 13 /** Type for sockets listening for transparent connections redirected by * natd. */ #define CONN_TYPE_AP_NATD_LISTENER 14 /** Type for sockets listening for DNS requests. */ #define CONN_TYPE_AP_DNS_LISTENER 15 #define CONN_TYPE_MAX_ 15 /* !!!! If CONN_TYPE_MAX_ is ever over 15, we must grow the type field in * connection_t. */ /* Proxy client types */ #define PROXY_NONE 0 #define PROXY_CONNECT 1 #define PROXY_SOCKS4 2 #define PROXY_SOCKS5 3 /* !!!! If there is ever a PROXY_* type over 2, we must grow the proxy_type * field in or_connection_t */ /* pluggable transports proxy type */ #define PROXY_PLUGGABLE 4 /* Proxy client handshake states */ /* We use a proxy but we haven't even connected to it yet. */ #define PROXY_INFANT 1 /* We use an HTTP proxy and we've sent the CONNECT command. */ #define PROXY_HTTPS_WANT_CONNECT_OK 2 /* We use a SOCKS4 proxy and we've sent the CONNECT command. */ #define PROXY_SOCKS4_WANT_CONNECT_OK 3 /* We use a SOCKS5 proxy and we try to negotiate without any authentication . */ #define PROXY_SOCKS5_WANT_AUTH_METHOD_NONE 4 /* We use a SOCKS5 proxy and we try to negotiate with Username/Password authentication . */ #define PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929 5 /* We use a SOCKS5 proxy and we just sent our credentials. */ #define PROXY_SOCKS5_WANT_AUTH_RFC1929_OK 6 /* We use a SOCKS5 proxy and we just sent our CONNECT command. */ #define PROXY_SOCKS5_WANT_CONNECT_OK 7 /* We use a proxy and we CONNECTed successfully!. */ #define PROXY_CONNECTED 8 /** True iff x is an edge connection. */ #define CONN_IS_EDGE(x) \ ((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP) /** State for any listener connection. */ #define LISTENER_STATE_READY 0 #define CPUWORKER_STATE_MIN_ 1 /** State for a connection to a cpuworker process that's idle. */ #define CPUWORKER_STATE_IDLE 1 /** State for a connection to a cpuworker process that's processing a * handshake. */ #define CPUWORKER_STATE_BUSY_ONION 2 #define CPUWORKER_STATE_MAX_ 2 #define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION #define CPUWORKER_TASK_SHUTDOWN 255 #define OR_CONN_STATE_MIN_ 1 /** State for a connection to an OR: waiting for connect() to finish. */ #define OR_CONN_STATE_CONNECTING 1 /** State for a connection to an OR: waiting for proxy handshake to complete */ #define OR_CONN_STATE_PROXY_HANDSHAKING 2 /** State for an OR connection client: SSL is handshaking, not done * yet. */ #define OR_CONN_STATE_TLS_HANDSHAKING 3 /** State for a connection to an OR: We're doing a second SSL handshake for * renegotiation purposes. (V2 handshake only.) */ #define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4 /** State for a connection at an OR: We're waiting for the client to * renegotiate (to indicate a v2 handshake) or send a versions cell (to * indicate a v3 handshake) */ #define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5 /** State for an OR connection: We're done with our SSL handshake, we've done * renegotiation, but we haven't yet negotiated link protocol versions and * sent a netinfo cell. */ #define OR_CONN_STATE_OR_HANDSHAKING_V2 6 /** State for an OR connection: We're done with our SSL handshake, but we * haven't yet negotiated link protocol versions, done a V3 handshake, and * sent a netinfo cell. */ #define OR_CONN_STATE_OR_HANDSHAKING_V3 7 /** State for an OR connection: Ready to send/receive cells. */ #define OR_CONN_STATE_OPEN 8 #define OR_CONN_STATE_MAX_ 8 #define EXIT_CONN_STATE_MIN_ 1 /** State for an exit connection: waiting for response from DNS farm. */ #define EXIT_CONN_STATE_RESOLVING 1 /** State for an exit connection: waiting for connect() to finish. */ #define EXIT_CONN_STATE_CONNECTING 2 /** State for an exit connection: open and ready to transmit data. */ #define EXIT_CONN_STATE_OPEN 3 /** State for an exit connection: waiting to be removed. */ #define EXIT_CONN_STATE_RESOLVEFAILED 4 #define EXIT_CONN_STATE_MAX_ 4 /* The AP state values must be disjoint from the EXIT state values. */ #define AP_CONN_STATE_MIN_ 5 /** State for a SOCKS connection: waiting for SOCKS request. */ #define AP_CONN_STATE_SOCKS_WAIT 5 /** State for a SOCKS connection: got a y.onion URL; waiting to receive * rendezvous descriptor. */ #define AP_CONN_STATE_RENDDESC_WAIT 6 /** The controller will attach this connection to a circuit; it isn't our * job to do so. */ #define AP_CONN_STATE_CONTROLLER_WAIT 7 /** State for a SOCKS connection: waiting for a completed circuit. */ #define AP_CONN_STATE_CIRCUIT_WAIT 8 /** State for a SOCKS connection: sent BEGIN, waiting for CONNECTED. */ #define AP_CONN_STATE_CONNECT_WAIT 9 /** State for a SOCKS connection: sent RESOLVE, waiting for RESOLVED. */ #define AP_CONN_STATE_RESOLVE_WAIT 10 /** State for a SOCKS connection: ready to send and receive. */ #define AP_CONN_STATE_OPEN 11 /** State for a transparent natd connection: waiting for original * destination. */ #define AP_CONN_STATE_NATD_WAIT 12 #define AP_CONN_STATE_MAX_ 12 /** True iff the AP_CONN_STATE_* value s means that the corresponding * edge connection is not attached to any circuit. */ #define AP_CONN_STATE_IS_UNATTACHED(s) \ ((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT) #define DIR_CONN_STATE_MIN_ 1 /** State for connection to directory server: waiting for connect(). */ #define DIR_CONN_STATE_CONNECTING 1 /** State for connection to directory server: sending HTTP request. */ #define DIR_CONN_STATE_CLIENT_SENDING 2 /** State for connection to directory server: reading HTTP response. */ #define DIR_CONN_STATE_CLIENT_READING 3 /** State for connection to directory server: happy and finished. */ #define DIR_CONN_STATE_CLIENT_FINISHED 4 /** State for connection at directory server: waiting for HTTP request. */ #define DIR_CONN_STATE_SERVER_COMMAND_WAIT 5 /** State for connection at directory server: sending HTTP response. */ #define DIR_CONN_STATE_SERVER_WRITING 6 #define DIR_CONN_STATE_MAX_ 6 /** True iff the purpose of conn means that it's a server-side * directory connection. */ #define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER) #define CONTROL_CONN_STATE_MIN_ 1 /** State for a control connection: Authenticated and accepting v1 commands. */ #define CONTROL_CONN_STATE_OPEN 1 /** State for a control connection: Waiting for authentication; speaking * protocol v1. */ #define CONTROL_CONN_STATE_NEEDAUTH 2 #define CONTROL_CONN_STATE_MAX_ 2 #define DIR_PURPOSE_MIN_ 3 /** A connection to a directory server: download a rendezvous * descriptor. */ #define DIR_PURPOSE_FETCH_RENDDESC 3 /** A connection to a directory server: set after a rendezvous * descriptor is downloaded. */ #define DIR_PURPOSE_HAS_FETCHED_RENDDESC 4 /** A connection to a directory server: download one or more v2 * network-status objects */ #define DIR_PURPOSE_FETCH_V2_NETWORKSTATUS 5 /** A connection to a directory server: download one or more server * descriptors. */ #define DIR_PURPOSE_FETCH_SERVERDESC 6 /** A connection to a directory server: download one or more extra-info * documents. */ #define DIR_PURPOSE_FETCH_EXTRAINFO 7 /** A connection to a directory server: upload a server descriptor. */ #define DIR_PURPOSE_UPLOAD_DIR 8 /** A connection to a directory server: upload a rendezvous * descriptor. */ #define DIR_PURPOSE_UPLOAD_RENDDESC 9 /** A connection to a directory server: upload a v3 networkstatus vote. */ #define DIR_PURPOSE_UPLOAD_VOTE 10 /** A connection to a directory server: upload a v3 consensus signature */ #define DIR_PURPOSE_UPLOAD_SIGNATURES 11 /** A connection to a directory server: download one or more v3 networkstatus * votes. */ #define DIR_PURPOSE_FETCH_STATUS_VOTE 12 /** A connection to a directory server: download a v3 detached signatures * object for a consensus. */ #define DIR_PURPOSE_FETCH_DETACHED_SIGNATURES 13 /** A connection to a directory server: download a v3 networkstatus * consensus. */ #define DIR_PURPOSE_FETCH_CONSENSUS 14 /** A connection to a directory server: download one or more directory * authority certificates. */ #define DIR_PURPOSE_FETCH_CERTIFICATE 15 /** Purpose for connection at a directory server. */ #define DIR_PURPOSE_SERVER 16 /** A connection to a hidden service directory server: upload a v2 rendezvous * descriptor. */ #define DIR_PURPOSE_UPLOAD_RENDDESC_V2 17 /** A connection to a hidden service directory server: download a v2 rendezvous * descriptor. */ #define DIR_PURPOSE_FETCH_RENDDESC_V2 18 /** A connection to a directory server: download a microdescriptor. */ #define DIR_PURPOSE_FETCH_MICRODESC 19 #define DIR_PURPOSE_MAX_ 19 /** True iff p is a purpose corresponding to uploading data to a * directory server. */ #define DIR_PURPOSE_IS_UPLOAD(p) \ ((p)==DIR_PURPOSE_UPLOAD_DIR || \ (p)==DIR_PURPOSE_UPLOAD_RENDDESC || \ (p)==DIR_PURPOSE_UPLOAD_VOTE || \ (p)==DIR_PURPOSE_UPLOAD_SIGNATURES) #define EXIT_PURPOSE_MIN_ 1 /** This exit stream wants to do an ordinary connect. */ #define EXIT_PURPOSE_CONNECT 1 /** This exit stream wants to do a resolve (either normal or reverse). */ #define EXIT_PURPOSE_RESOLVE 2 #define EXIT_PURPOSE_MAX_ 2 /* !!!! If any connection purpose is ever over 31, we must grow the type * field in connection_t. */ /** Circuit state: I'm the origin, still haven't done all my handshakes. */ #define CIRCUIT_STATE_BUILDING 0 /** Circuit state: Waiting to process the onionskin. */ #define CIRCUIT_STATE_ONIONSKIN_PENDING 1 /** Circuit state: I'd like to deliver a create, but my n_chan is still * connecting. */ #define CIRCUIT_STATE_CHAN_WAIT 2 /** Circuit state: onionskin(s) processed, ready to send/receive cells. */ #define CIRCUIT_STATE_OPEN 3 #define CIRCUIT_PURPOSE_MIN_ 1 /* these circuits were initiated elsewhere */ #define CIRCUIT_PURPOSE_OR_MIN_ 1 /** OR-side circuit purpose: normal circuit, at OR. */ #define CIRCUIT_PURPOSE_OR 1 /** OR-side circuit purpose: At OR, from Bob, waiting for intro from Alices. */ #define CIRCUIT_PURPOSE_INTRO_POINT 2 /** OR-side circuit purpose: At OR, from Alice, waiting for Bob. */ #define CIRCUIT_PURPOSE_REND_POINT_WAITING 3 /** OR-side circuit purpose: At OR, both circuits have this purpose. */ #define CIRCUIT_PURPOSE_REND_ESTABLISHED 4 #define CIRCUIT_PURPOSE_OR_MAX_ 4 /* these circuits originate at this node */ /* here's how circ client-side purposes work: * normal circuits are C_GENERAL. * circuits that are c_introducing are either on their way to * becoming open, or they are open and waiting for a * suitable rendcirc before they send the intro. * circuits that are c_introduce_ack_wait have sent the intro, * but haven't gotten a response yet. * circuits that are c_establish_rend are either on their way * to becoming open, or they are open and have sent the * establish_rendezvous cell but haven't received an ack. * circuits that are c_rend_ready are open and have received a * rend ack, but haven't heard from bob yet. if they have a * buildstate->pending_final_cpath then they're expecting a * cell from bob, else they're not. * circuits that are c_rend_ready_intro_acked are open, and * some intro circ has sent its intro and received an ack. * circuits that are c_rend_joined are open, have heard from * bob, and are talking to him. */ /** Client-side circuit purpose: Normal circuit, with cpath. */ #define CIRCUIT_PURPOSE_C_GENERAL 5 /** Client-side circuit purpose: at Alice, connecting to intro point. */ #define CIRCUIT_PURPOSE_C_INTRODUCING 6 /** Client-side circuit purpose: at Alice, sent INTRODUCE1 to intro point, * waiting for ACK/NAK. */ #define CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT 7 /** Client-side circuit purpose: at Alice, introduced and acked, closing. */ #define CIRCUIT_PURPOSE_C_INTRODUCE_ACKED 8 /** Client-side circuit purpose: at Alice, waiting for ack. */ #define CIRCUIT_PURPOSE_C_ESTABLISH_REND 9 /** Client-side circuit purpose: at Alice, waiting for Bob. */ #define CIRCUIT_PURPOSE_C_REND_READY 10 /** Client-side circuit purpose: at Alice, waiting for Bob, INTRODUCE * has been acknowledged. */ #define CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED 11 /** Client-side circuit purpose: at Alice, rendezvous established. */ #define CIRCUIT_PURPOSE_C_REND_JOINED 12 /** This circuit is used for build time measurement only */ #define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 13 #define CIRCUIT_PURPOSE_C_MAX_ 13 /** Hidden-service-side circuit purpose: at Bob, waiting for introductions. */ #define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 14 /** Hidden-service-side circuit purpose: at Bob, successfully established * intro. */ #define CIRCUIT_PURPOSE_S_INTRO 15 /** Hidden-service-side circuit purpose: at Bob, connecting to rend point. */ #define CIRCUIT_PURPOSE_S_CONNECT_REND 16 /** Hidden-service-side circuit purpose: at Bob, rendezvous established. */ #define CIRCUIT_PURPOSE_S_REND_JOINED 17 /** A testing circuit; not meant to be used for actual traffic. */ #define CIRCUIT_PURPOSE_TESTING 18 /** A controller made this circuit and Tor should not use it. */ #define CIRCUIT_PURPOSE_CONTROLLER 19 /** This circuit is used for path bias probing only */ #define CIRCUIT_PURPOSE_PATH_BIAS_TESTING 20 #define CIRCUIT_PURPOSE_MAX_ 20 /** A catch-all for unrecognized purposes. Currently we don't expect * to make or see any circuits with this purpose. */ #define CIRCUIT_PURPOSE_UNKNOWN 255 /** True iff the circuit purpose p is for a circuit that * originated at this node. */ #define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>CIRCUIT_PURPOSE_OR_MAX_) /** True iff the circuit purpose p is for a circuit that originated * here to serve as a client. (Hidden services don't count here.) */ #define CIRCUIT_PURPOSE_IS_CLIENT(p) \ ((p)> CIRCUIT_PURPOSE_OR_MAX_ && \ (p)<=CIRCUIT_PURPOSE_C_MAX_) /** True iff the circuit_t c is actually an origin_circuit_t. */ #define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose)) /** True iff the circuit purpose p is for an established rendezvous * circuit. */ #define CIRCUIT_PURPOSE_IS_ESTABLISHED_REND(p) \ ((p) == CIRCUIT_PURPOSE_C_REND_JOINED || \ (p) == CIRCUIT_PURPOSE_S_REND_JOINED) /** True iff the circuit_t c is actually an or_circuit_t */ #define CIRCUIT_IS_ORCIRC(c) (((circuit_t *)(c))->magic == OR_CIRCUIT_MAGIC) /** How many circuits do we want simultaneously in-progress to handle * a given stream? */ #define MIN_CIRCUITS_HANDLING_STREAM 2 /* These RELAY_COMMAND constants define values for relay cell commands, and * must match those defined in tor-spec.txt. */ #define RELAY_COMMAND_BEGIN 1 #define RELAY_COMMAND_DATA 2 #define RELAY_COMMAND_END 3 #define RELAY_COMMAND_CONNECTED 4 #define RELAY_COMMAND_SENDME 5 #define RELAY_COMMAND_EXTEND 6 #define RELAY_COMMAND_EXTENDED 7 #define RELAY_COMMAND_TRUNCATE 8 #define RELAY_COMMAND_TRUNCATED 9 #define RELAY_COMMAND_DROP 10 #define RELAY_COMMAND_RESOLVE 11 #define RELAY_COMMAND_RESOLVED 12 #define RELAY_COMMAND_BEGIN_DIR 13 #define RELAY_COMMAND_EXTEND2 14 #define RELAY_COMMAND_EXTENDED2 15 #define RELAY_COMMAND_ESTABLISH_INTRO 32 #define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33 #define RELAY_COMMAND_INTRODUCE1 34 #define RELAY_COMMAND_INTRODUCE2 35 #define RELAY_COMMAND_RENDEZVOUS1 36 #define RELAY_COMMAND_RENDEZVOUS2 37 #define RELAY_COMMAND_INTRO_ESTABLISHED 38 #define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39 #define RELAY_COMMAND_INTRODUCE_ACK 40 /* Reasons why an OR connection is closed. */ #define END_OR_CONN_REASON_DONE 1 #define END_OR_CONN_REASON_REFUSED 2 /* connection refused */ #define END_OR_CONN_REASON_OR_IDENTITY 3 #define END_OR_CONN_REASON_CONNRESET 4 /* connection reset by peer */ #define END_OR_CONN_REASON_TIMEOUT 5 #define END_OR_CONN_REASON_NO_ROUTE 6 /* no route to host/net */ #define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */ #define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */ #define END_OR_CONN_REASON_MISC 9 /* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for * documentation of these. The values must match. */ #define END_STREAM_REASON_MISC 1 #define END_STREAM_REASON_RESOLVEFAILED 2 #define END_STREAM_REASON_CONNECTREFUSED 3 #define END_STREAM_REASON_EXITPOLICY 4 #define END_STREAM_REASON_DESTROY 5 #define END_STREAM_REASON_DONE 6 #define END_STREAM_REASON_TIMEOUT 7 #define END_STREAM_REASON_NOROUTE 8 #define END_STREAM_REASON_HIBERNATING 9 #define END_STREAM_REASON_INTERNAL 10 #define END_STREAM_REASON_RESOURCELIMIT 11 #define END_STREAM_REASON_CONNRESET 12 #define END_STREAM_REASON_TORPROTOCOL 13 #define END_STREAM_REASON_NOTDIRECTORY 14 #define END_STREAM_REASON_ENTRYPOLICY 15 /* These high-numbered end reasons are not part of the official spec, * and are not intended to be put in relay end cells. They are here * to be more informative when sending back socks replies to the * application. */ /* XXXX 256 is no longer used; feel free to reuse it. */ /** We were unable to attach the connection to any circuit at all. */ /* XXXX the ways we use this one don't make a lot of sense. */ #define END_STREAM_REASON_CANT_ATTACH 257 /** We can't connect to any directories at all, so we killed our streams * before they can time out. */ #define END_STREAM_REASON_NET_UNREACHABLE 258 /** This is a SOCKS connection, and the client used (or misused) the SOCKS * protocol in a way we couldn't handle. */ #define END_STREAM_REASON_SOCKSPROTOCOL 259 /** This is a transparent proxy connection, but we can't extract the original * target address:port. */ #define END_STREAM_REASON_CANT_FETCH_ORIG_DEST 260 /** This is a connection on the NATD port, and the destination IP:Port was * either ill-formed or out-of-range. */ #define END_STREAM_REASON_INVALID_NATD_DEST 261 /** The target address is in a private network (like 127.0.0.1 or 10.0.0.1); * you don't want to do that over a randomly chosen exit */ #define END_STREAM_REASON_PRIVATE_ADDR 262 /** Bitwise-and this value with endreason to mask out all flags. */ #define END_STREAM_REASON_MASK 511 /** Bitwise-or this with the argument to control_event_stream_status * to indicate that the reason came from an END cell. */ #define END_STREAM_REASON_FLAG_REMOTE 512 /** Bitwise-or this with the argument to control_event_stream_status * to indicate that we already sent a CLOSED stream event. */ #define END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED 1024 /** Bitwise-or this with endreason to indicate that we already sent * a socks reply, and no further reply needs to be sent from * connection_mark_unattached_ap(). */ #define END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED 2048 /** Reason for remapping an AP connection's address: we have a cached * answer. */ #define REMAP_STREAM_SOURCE_CACHE 1 /** Reason for remapping an AP connection's address: the exit node told us an * answer. */ #define REMAP_STREAM_SOURCE_EXIT 2 /* 'type' values to use in RESOLVED cells. Specified in tor-spec.txt. */ #define RESOLVED_TYPE_HOSTNAME 0 #define RESOLVED_TYPE_IPV4 4 #define RESOLVED_TYPE_IPV6 6 #define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0 #define RESOLVED_TYPE_ERROR 0xF1 /* Negative reasons are internal: we never send them in a DESTROY or TRUNCATE * call; they only go to the controller for tracking */ /** Our post-timeout circuit time measurement period expired. * We must give up now */ #define END_CIRC_REASON_MEASUREMENT_EXPIRED -3 /** We couldn't build a path for this circuit. */ #define END_CIRC_REASON_NOPATH -2 /** Catch-all "other" reason for closing origin circuits. */ #define END_CIRC_AT_ORIGIN -1 /* Reasons why we (or a remote OR) might close a circuit. See tor-spec.txt for * documentation of these. */ #define END_CIRC_REASON_MIN_ 0 #define END_CIRC_REASON_NONE 0 #define END_CIRC_REASON_TORPROTOCOL 1 #define END_CIRC_REASON_INTERNAL 2 #define END_CIRC_REASON_REQUESTED 3 #define END_CIRC_REASON_HIBERNATING 4 #define END_CIRC_REASON_RESOURCELIMIT 5 #define END_CIRC_REASON_CONNECTFAILED 6 #define END_CIRC_REASON_OR_IDENTITY 7 #define END_CIRC_REASON_CHANNEL_CLOSED 8 #define END_CIRC_REASON_FINISHED 9 #define END_CIRC_REASON_TIMEOUT 10 #define END_CIRC_REASON_DESTROYED 11 #define END_CIRC_REASON_NOSUCHSERVICE 12 #define END_CIRC_REASON_MAX_ 12 /** Bitwise-OR this with the argument to circuit_mark_for_close() or * control_event_circuit_status() to indicate that the reason was * passed through from a destroy or truncate cell. */ #define END_CIRC_REASON_FLAG_REMOTE 512 /** Length of 'y' portion of 'y.onion' URL. */ #define REND_SERVICE_ID_LEN_BASE32 16 /** Length of 'y.onion' including '.onion' URL. */ #define REND_SERVICE_ADDRESS_LEN (16+1+5) /** Length of a binary-encoded rendezvous service ID. */ #define REND_SERVICE_ID_LEN 10 /** Time period for which a v2 descriptor will be valid. */ #define REND_TIME_PERIOD_V2_DESC_VALIDITY (24*60*60) /** Time period within which two sets of v2 descriptors will be uploaded in * parallel. */ #define REND_TIME_PERIOD_OVERLAPPING_V2_DESCS (60*60) /** Number of non-consecutive replicas (i.e. distributed somewhere * in the ring) for a descriptor. */ #define REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS 2 /** Number of consecutive replicas for a descriptor. */ #define REND_NUMBER_OF_CONSECUTIVE_REPLICAS 3 /** Length of v2 descriptor ID (32 base32 chars = 160 bits). */ #define REND_DESC_ID_V2_LEN_BASE32 32 /** Length of the base32-encoded secret ID part of versioned hidden service * descriptors. */ #define REND_SECRET_ID_PART_LEN_BASE32 32 /** Length of the base32-encoded hash of an introduction point's * identity key. */ #define REND_INTRO_POINT_ID_LEN_BASE32 32 /** Length of the descriptor cookie that is used for client authorization * to hidden services. */ #define REND_DESC_COOKIE_LEN 16 /** Length of the base64-encoded descriptor cookie that is used for * exchanging client authorization between hidden service and client. */ #define REND_DESC_COOKIE_LEN_BASE64 22 /** Length of client identifier in encrypted introduction points for hidden * service authorization type 'basic'. */ #define REND_BASIC_AUTH_CLIENT_ID_LEN 4 /** Multiple of the number of clients to which the real number of clients * is padded with fake clients for hidden service authorization type * 'basic'. */ #define REND_BASIC_AUTH_CLIENT_MULTIPLE 16 /** Length of client entry consisting of client identifier and encrypted * session key for hidden service authorization type 'basic'. */ #define REND_BASIC_AUTH_CLIENT_ENTRY_LEN (REND_BASIC_AUTH_CLIENT_ID_LEN \ + CIPHER_KEY_LEN) /** Maximum size of v2 hidden service descriptors. */ #define REND_DESC_MAX_SIZE (20 * 1024) /** Legal characters for use in authorized client names for a hidden * service. */ #define REND_LEGAL_CLIENTNAME_CHARACTERS \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-_" /** Maximum length of authorized client names for a hidden service. */ #define REND_CLIENTNAME_MAX_LEN 16 /** Length of the rendezvous cookie that is used to connect circuits at the * rendezvous point. */ #define REND_COOKIE_LEN DIGEST_LEN /** Client authorization type that a hidden service performs. */ typedef enum rend_auth_type_t { REND_NO_AUTH = 0, REND_BASIC_AUTH = 1, REND_STEALTH_AUTH = 2, } rend_auth_type_t; /** Client-side configuration of authorization for a hidden service. */ typedef struct rend_service_authorization_t { char descriptor_cookie[REND_DESC_COOKIE_LEN]; char onion_address[REND_SERVICE_ADDRESS_LEN+1]; rend_auth_type_t auth_type; } rend_service_authorization_t; /** Client- and server-side data that is used for hidden service connection * establishment. Not all fields contain data depending on where this struct * is used. */ typedef struct rend_data_t { /** Onion address (without the .onion part) that a client requests. */ char onion_address[REND_SERVICE_ID_LEN_BASE32+1]; /** (Optional) descriptor cookie that is used by a client. */ char descriptor_cookie[REND_DESC_COOKIE_LEN]; /** Authorization type for accessing a service used by a client. */ rend_auth_type_t auth_type; /** Hash of the hidden service's PK used by a service. */ char rend_pk_digest[DIGEST_LEN]; /** Rendezvous cookie used by both, client and service. */ char rend_cookie[REND_COOKIE_LEN]; } rend_data_t; /** Time interval for tracking replays of DH public keys received in * INTRODUCE2 cells. Used only to avoid launching multiple * simultaneous attempts to connect to the same rendezvous point. */ #define REND_REPLAY_TIME_INTERVAL (5 * 60) /** Used to indicate which way a cell is going on a circuit. */ typedef enum { CELL_DIRECTION_IN=1, /**< The cell is moving towards the origin. */ CELL_DIRECTION_OUT=2, /**< The cell is moving away from the origin. */ } cell_direction_t; /** Initial value for both sides of a circuit transmission window when the * circuit is initialized. Measured in cells. */ #define CIRCWINDOW_START 1000 #define CIRCWINDOW_START_MIN 100 #define CIRCWINDOW_START_MAX 1000 /** Amount to increment a circuit window when we get a circuit SENDME. */ #define CIRCWINDOW_INCREMENT 100 /** Initial value on both sides of a stream transmission window when the * stream is initialized. Measured in cells. */ #define STREAMWINDOW_START 500 /** Amount to increment a stream window when we get a stream SENDME. */ #define STREAMWINDOW_INCREMENT 50 /** Maximum number of queued cells on a circuit for which we are the * midpoint before we give up and kill it. This must be >= circwindow * to avoid killing innocent circuits, and >= circwindow*2 to give * leaky-pipe a chance for being useful someday. */ #define ORCIRC_MAX_MIDDLE_CELLS (21*(CIRCWINDOW_START_MAX)/10) /* Cell commands. These values are defined in tor-spec.txt. */ #define CELL_PADDING 0 #define CELL_CREATE 1 #define CELL_CREATED 2 #define CELL_RELAY 3 #define CELL_DESTROY 4 #define CELL_CREATE_FAST 5 #define CELL_CREATED_FAST 6 #define CELL_VERSIONS 7 #define CELL_NETINFO 8 #define CELL_RELAY_EARLY 9 #define CELL_CREATE2 10 #define CELL_CREATED2 11 #define CELL_VPADDING 128 #define CELL_CERTS 129 #define CELL_AUTH_CHALLENGE 130 #define CELL_AUTHENTICATE 131 #define CELL_AUTHORIZE 132 /** How long to test reachability before complaining to the user. */ #define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60) /** Legal characters in a nickname. */ #define LEGAL_NICKNAME_CHARACTERS \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" /** Name to use in client TLS certificates if no nickname is given. Once * Tor 0.1.2.x is obsolete, we can remove this. */ #define DEFAULT_CLIENT_NICKNAME "client" /** Name chosen by routers that don't configure nicknames */ #define UNNAMED_ROUTER_NICKNAME "Unnamed" /** Number of bytes in a SOCKS4 header. */ #define SOCKS4_NETWORK_LEN 8 /* * Relay payload: * Relay command [1 byte] * Recognized [2 bytes] * Stream ID [2 bytes] * Partial SHA-1 [4 bytes] * Length [2 bytes] * Relay payload [498 bytes] */ /** Number of bytes in a cell, minus cell header. */ #define CELL_PAYLOAD_SIZE 509 /** Number of bytes in a cell transmitted over the network, in the longest * form */ #define CELL_MAX_NETWORK_SIZE 514 /** Maximum length of a header on a variable-length cell. */ #define VAR_CELL_MAX_HEADER_SIZE 7 static int get_cell_network_size(int wide_circ_ids); static INLINE int get_cell_network_size(int wide_circ_ids) { return wide_circ_ids ? CELL_MAX_NETWORK_SIZE : CELL_MAX_NETWORK_SIZE - 2; } static int get_var_cell_header_size(int wide_circ_ids); static INLINE int get_var_cell_header_size(int wide_circ_ids) { return wide_circ_ids ? VAR_CELL_MAX_HEADER_SIZE : VAR_CELL_MAX_HEADER_SIZE - 2; } static int get_circ_id_size(int wide_circ_ids); static INLINE int get_circ_id_size(int wide_circ_ids) { return wide_circ_ids ? 4 : 2; } /** Number of bytes in a relay cell's header (not including general cell * header). */ #define RELAY_HEADER_SIZE (1+2+2+4+2) /** Largest number of bytes that can fit in a relay cell payload. */ #define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) /** Identifies a circuit on an or_connection */ typedef uint32_t circid_t; /** Identifies a stream on a circuit */ typedef uint16_t streamid_t; /* channel_t typedef; struct channel_s is in channel.h */ typedef struct channel_s channel_t; /* channel_listener_t typedef; struct channel_listener_s is in channel.h */ typedef struct channel_listener_s channel_listener_t; /* channel states for channel_t */ typedef enum { /* * Closed state - channel is inactive * * Permitted transitions from: * - CHANNEL_STATE_CLOSING * Permitted transitions to: * - CHANNEL_STATE_OPENING */ CHANNEL_STATE_CLOSED = 0, /* * Opening state - channel is trying to connect * * Permitted transitions from: * - CHANNEL_STATE_CLOSED * Permitted transitions to: * - CHANNEL_STATE_CLOSING * - CHANNEL_STATE_ERROR * - CHANNEL_STATE_OPEN */ CHANNEL_STATE_OPENING, /* * Open state - channel is active and ready for use * * Permitted transitions from: * - CHANNEL_STATE_MAINT * - CHANNEL_STATE_OPENING * Permitted transitions to: * - CHANNEL_STATE_CLOSING * - CHANNEL_STATE_ERROR * - CHANNEL_STATE_MAINT */ CHANNEL_STATE_OPEN, /* * Maintenance state - channel is temporarily offline for subclass specific * maintenance activities such as TLS renegotiation. * * Permitted transitions from: * - CHANNEL_STATE_OPEN * Permitted transitions to: * - CHANNEL_STATE_CLOSING * - CHANNEL_STATE_ERROR * - CHANNEL_STATE_OPEN */ CHANNEL_STATE_MAINT, /* * Closing state - channel is shutting down * * Permitted transitions from: * - CHANNEL_STATE_MAINT * - CHANNEL_STATE_OPEN * Permitted transitions to: * - CHANNEL_STATE_CLOSED, * - CHANNEL_STATE_ERROR */ CHANNEL_STATE_CLOSING, /* * Error state - channel has experienced a permanent error * * Permitted transitions from: * - CHANNEL_STATE_CLOSING * - CHANNEL_STATE_MAINT * - CHANNEL_STATE_OPENING * - CHANNEL_STATE_OPEN * Permitted transitions to: * - None */ CHANNEL_STATE_ERROR, /* * Placeholder for maximum state value */ CHANNEL_STATE_LAST } channel_state_t; /* channel listener states for channel_listener_t */ typedef enum { /* * Closed state - channel listener is inactive * * Permitted transitions from: * - CHANNEL_LISTENER_STATE_CLOSING * Permitted transitions to: * - CHANNEL_LISTENER_STATE_LISTENING */ CHANNEL_LISTENER_STATE_CLOSED = 0, /* * Listening state - channel listener is listening for incoming * connections * * Permitted transitions from: * - CHANNEL_LISTENER_STATE_CLOSED * Permitted transitions to: * - CHANNEL_LISTENER_STATE_CLOSING * - CHANNEL_LISTENER_STATE_ERROR */ CHANNEL_LISTENER_STATE_LISTENING, /* * Closing state - channel listener is shutting down * * Permitted transitions from: * - CHANNEL_LISTENER_STATE_LISTENING * Permitted transitions to: * - CHANNEL_LISTENER_STATE_CLOSED, * - CHANNEL_LISTENER_STATE_ERROR */ CHANNEL_LISTENER_STATE_CLOSING, /* * Error state - channel listener has experienced a permanent error * * Permitted transitions from: * - CHANNEL_STATE_CLOSING * - CHANNEL_STATE_LISTENING * Permitted transitions to: * - None */ CHANNEL_LISTENER_STATE_ERROR, /* * Placeholder for maximum state value */ CHANNEL_LISTENER_STATE_LAST } channel_listener_state_t; /* TLS channel stuff */ typedef struct channel_tls_s channel_tls_t; /* circuitmux_t typedef; struct circuitmux_s is in circuitmux.h */ typedef struct circuitmux_s circuitmux_t; /** Parsed onion routing cell. All communication between nodes * is via cells. */ typedef struct cell_t { circid_t circ_id; /**< Circuit which received the cell. */ uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE, * CELL_DESTROY, etc */ uint8_t payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */ } cell_t; /** Parsed variable-length onion routing cell. */ typedef struct var_cell_t { /** Type of the cell: CELL_VERSIONS, etc. */ uint8_t command; /** Circuit thich received the cell */ circid_t circ_id; /** Number of bytes actually stored in payload */ uint16_t payload_len; /** Payload of this cell */ uint8_t payload[FLEXIBLE_ARRAY_MEMBER]; } var_cell_t; /** A cell as packed for writing to the network. */ typedef struct packed_cell_t { struct packed_cell_t *next; /**< Next cell queued on this circuit. */ char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */ uint32_t inserted_time; /**< Time (in milliseconds since epoch, with high * bits truncated) when this cell was inserted. */ } packed_cell_t; /* XXXX This next structure may be obsoleted by inserted_time in * packed_cell_t */ /** Number of cells added to a circuit queue including their insertion * time on 10 millisecond detail; used for buffer statistics. */ typedef struct insertion_time_elem_t { struct insertion_time_elem_t *next; /**< Next element in queue. */ uint32_t insertion_time; /**< When were cells inserted (in 10 ms steps * starting at 0:00 of the current day)? */ unsigned counter; /**< How many cells were inserted? */ } insertion_time_elem_t; /** Queue of insertion times. */ typedef struct insertion_time_queue_t { struct insertion_time_elem_t *first; /**< First element in queue. */ struct insertion_time_elem_t *last; /**< Last element in queue. */ } insertion_time_queue_t; /** A queue of cells on a circuit, waiting to be added to the * or_connection_t's outbuf. */ typedef struct cell_queue_t { packed_cell_t *head; /**< The first cell, or NULL if the queue is empty. */ packed_cell_t *tail; /**< The last cell, or NULL if the queue is empty. */ int n; /**< The number of cells in the queue. */ insertion_time_queue_t *insertion_times; /**< Insertion times of cells. */ } cell_queue_t; /** Beginning of a RELAY cell payload. */ typedef struct { uint8_t command; /**< The end-to-end relay command. */ uint16_t recognized; /**< Used to tell whether cell is for us. */ streamid_t stream_id; /**< Which stream is this cell associated with? */ char integrity[4]; /**< Used to tell whether cell is corrupted. */ uint16_t length; /**< How long is the payload body? */ } relay_header_t; typedef struct buf_t buf_t; typedef struct socks_request_t socks_request_t; #ifdef USE_BUFFEREVENTS #define generic_buffer_t struct evbuffer #else #define generic_buffer_t buf_t #endif /* Values for connection_t.magic: used to make sure that downcasts (casts from * connection_t to foo_connection_t) are safe. */ #define BASE_CONNECTION_MAGIC 0x7C3C304Eu #define OR_CONNECTION_MAGIC 0x7D31FF03u #define EDGE_CONNECTION_MAGIC 0xF0374013u #define ENTRY_CONNECTION_MAGIC 0xbb4a5703 #define DIR_CONNECTION_MAGIC 0x9988ffeeu #define CONTROL_CONNECTION_MAGIC 0x8abc765du #define LISTENER_CONNECTION_MAGIC 0x1a1ac741u /** Description of a connection to another host or process, and associated * data. * * A connection is named based on what it's connected to -- an "OR * connection" has a Tor node on the other end, an "exit * connection" has a website or other server on the other end, and an * "AP connection" has an application proxy (and thus a user) on the * other end. * * Every connection has a type and a state. Connections never change * their type, but can go through many state changes in their lifetime. * * Every connection has two associated input and output buffers. * Listeners don't use them. For non-listener connections, incoming * data is appended to conn->inbuf, and outgoing data is taken from * conn->outbuf. Connections differ primarily in the functions called * to fill and drain these buffers. */ typedef struct connection_t { uint32_t magic; /**< For memory debugging: must equal one of * *_CONNECTION_MAGIC. */ uint8_t state; /**< Current state of this connection. */ unsigned int type:4; /**< What kind of connection is this? */ unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */ /* The next fields are all one-bit booleans. Some are only applicable to * connection subtypes, but we hold them here anyway, to save space. */ unsigned int read_blocked_on_bw:1; /**< Boolean: should we start reading * again once the bandwidth throttler allows it? */ unsigned int write_blocked_on_bw:1; /**< Boolean: should we start writing * again once the bandwidth throttler allows * writes? */ unsigned int hold_open_until_flushed:1; /**< Despite this connection's being * marked for close, do we flush it * before closing it? */ unsigned int inbuf_reached_eof:1; /**< Boolean: did read() return 0 on this * conn? */ /** Set to 1 when we're inside connection_flushed_some to keep us from * calling connection_handle_write() recursively. */ unsigned int in_flushed_some:1; /** True if connection_handle_write is currently running on this connection. */ unsigned int in_connection_handle_write:1; /* For linked connections: */ unsigned int linked:1; /**< True if there is, or has been, a linked_conn. */ /** True iff we'd like to be notified about read events from the * linked conn. */ unsigned int reading_from_linked_conn:1; /** True iff we're willing to write to the linked conn. */ unsigned int writing_to_linked_conn:1; /** True iff we're currently able to read on the linked conn, and our * read_event should be made active with libevent. */ unsigned int active_on_link:1; /** True iff we've called connection_close_immediate() on this linked * connection. */ unsigned int linked_conn_is_closed:1; /** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */ unsigned int proxy_state:4; /** Our socket; set to TOR_INVALID_SOCKET if this connection is closed, * or has no socket. */ tor_socket_t s; int conn_array_index; /**< Index into the global connection array. */ struct event *read_event; /**< Libevent event structure. */ struct event *write_event; /**< Libevent event structure. */ buf_t *inbuf; /**< Buffer holding data read over this connection. */ buf_t *outbuf; /**< Buffer holding data to write over this connection. */ size_t outbuf_flushlen; /**< How much data should we try to flush from the * outbuf? */ time_t timestamp_lastread; /**< When was the last time libevent said we could * read? */ time_t timestamp_lastwritten; /**< When was the last time libevent said we * could write? */ #ifdef USE_BUFFEREVENTS struct bufferevent *bufev; /**< A Libevent buffered IO structure. */ #endif time_t timestamp_created; /**< When was this connection_t created? */ /* XXXX_IP6 make this IPv6-capable */ int socket_family; /**< Address family of this connection's socket. Usually * AF_INET, but it can also be AF_UNIX, or in the future * AF_INET6 */ tor_addr_t addr; /**< IP of the other side of the connection; used to * identify routers, along with port. */ uint16_t port; /**< If non-zero, port on the other end * of the connection. */ uint16_t marked_for_close; /**< Should we close this conn on the next * iteration of the main loop? (If true, holds * the line number where this connection was * marked.) */ const char *marked_for_close_file; /**< For debugging: in which file were * we marked for close? */ char *address; /**< FQDN (or IP) of the guy on the other end. * strdup into this, because free_connection() frees it. */ /** Another connection that's connected to this one in lieu of a socket. */ struct connection_t *linked_conn; /** Unique identifier for this connection on this Tor instance. */ uint64_t global_identifier; } connection_t; /** Subtype of connection_t; used for a listener socket. */ typedef struct listener_connection_t { connection_t base_; /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points * to the evdns_server_port it uses to listen to and answer connections. */ struct evdns_server_port *dns_server_port; /** @name Isolation parameters * * For an AP listener, these fields describe how to isolate streams that * arrive on the listener. * * @{ */ /** The session group for this listener. */ int session_group; /** One or more ISO_ flags to describe how to isolate streams. */ uint8_t isolation_flags; /**@}*/ /** For SOCKS connections only: If this is set, we will choose "no * authentication" instead of "username/password" authentication if both * are offered. Used as input to parse_socks. */ unsigned int socks_prefer_no_auth : 1; /** For a SOCKS listeners, these fields describe whether we should * allow IPv4 and IPv6 addresses from our exit nodes, respectively. * * @{ */ unsigned int socks_ipv4_traffic : 1; unsigned int socks_ipv6_traffic : 1; /** @} */ /** For a socks listener: should we tell the exit that we prefer IPv6 * addresses? */ unsigned int socks_prefer_ipv6 : 1; /** For a socks listener: should we cache IPv4/IPv6 DNS information that * exit nodes tell us? * * @{ */ unsigned int cache_ipv4_answers : 1; unsigned int cache_ipv6_answers : 1; /** @} */ /** For a socks listeners: if we find an answer in our client-side DNS cache, * should we use it? * * @{ */ unsigned int use_cached_ipv4_answers : 1; unsigned int use_cached_ipv6_answers : 1; /** @} */ /** For socks listeners: When we can automap an address to IPv4 or IPv6, * do we prefer IPv6? */ unsigned int prefer_ipv6_virtaddr : 1; } listener_connection_t; /** Minimum length of the random part of an AUTH_CHALLENGE cell. */ #define OR_AUTH_CHALLENGE_LEN 32 /** * @name Certificate types for CERTS cells. * * These values are defined by the protocol, and affect how an X509 * certificate in a CERTS cell is interpreted and used. * * @{ */ /** A certificate that authenticates a TLS link key. The subject key * must match the key used in the TLS handshake; it must be signed by * the identity key. */ #define OR_CERT_TYPE_TLS_LINK 1 /** A self-signed identity certificate. The subject key must be a * 1024-bit RSA key. */ #define OR_CERT_TYPE_ID_1024 2 /** A certificate that authenticates a key used in an AUTHENTICATE cell * in the v3 handshake. The subject key must be a 1024-bit RSA key; it * must be signed by the identity key */ #define OR_CERT_TYPE_AUTH_1024 3 /**@}*/ /** The one currently supported type of AUTHENTICATE cell. It contains * a bunch of structures signed with an RSA1024 key. The signed * structures include a HMAC using negotiated TLS secrets, and a digest * of all cells sent or received before the AUTHENTICATE cell (including * the random server-generated AUTH_CHALLENGE cell). */ #define AUTHTYPE_RSA_SHA256_TLSSECRET 1 /** The length of the part of the AUTHENTICATE cell body that the client and * server can generate independently (when using RSA_SHA256_TLSSECRET). It * contains everything except the client's timestamp, the client's randomly * generated nonce, and the signature. */ #define V3_AUTH_FIXED_PART_LEN (8+(32*6)) /** The length of the part of the AUTHENTICATE cell body that the client * signs. */ #define V3_AUTH_BODY_LEN (V3_AUTH_FIXED_PART_LEN + 8 + 16) /** Stores flags and information related to the portion of a v2/v3 Tor OR * connection handshake that happens after the TLS handshake is finished. */ typedef struct or_handshake_state_t { /** When was the VERSIONS cell sent on this connection? Used to get * an estimate of the skew in the returning NETINFO reply. */ time_t sent_versions_at; /** True iff we originated this connection */ unsigned int started_here : 1; /** True iff we have received and processed a VERSIONS cell. */ unsigned int received_versions : 1; /** True iff we have received and processed an AUTH_CHALLENGE cell */ unsigned int received_auth_challenge : 1; /** True iff we have received and processed a CERTS cell. */ unsigned int received_certs_cell : 1; /** True iff we have received and processed an AUTHENTICATE cell */ unsigned int received_authenticate : 1; /* True iff we've received valid authentication to some identity. */ unsigned int authenticated : 1; /* True iff we have sent a netinfo cell */ unsigned int sent_netinfo : 1; /** True iff we should feed outgoing cells into digest_sent and * digest_received respectively. * * From the server's side of the v3 handshake, we want to capture everything * from the VERSIONS cell through and including the AUTH_CHALLENGE cell. * From the client's, we want to capture everything from the VERSIONS cell * through but *not* including the AUTHENTICATE cell. * * @{ */ unsigned int digest_sent_data : 1; unsigned int digest_received_data : 1; /**@}*/ /** Identity digest that we have received and authenticated for our peer * on this connection. */ uint8_t authenticated_peer_id[DIGEST_LEN]; /** Digests of the cells that we have sent or received as part of a V3 * handshake. Used for making and checking AUTHENTICATE cells. * * @{ */ crypto_digest_t *digest_sent; crypto_digest_t *digest_received; /** @} */ /** Certificates that a connection initiator sent us in a CERTS cell; we're * holding on to them until we get an AUTHENTICATE cell. * * @{ */ /** The cert for the key that's supposed to sign the AUTHENTICATE cell */ tor_cert_t *auth_cert; /** A self-signed identity certificate */ tor_cert_t *id_cert; /**@}*/ } or_handshake_state_t; /** Subtype of connection_t for an "OR connection" -- that is, one that speaks * cells over TLS. */ typedef struct or_connection_t { connection_t base_; /** Hash of the public RSA key for the other side's identity key, or zeroes * if the other side hasn't shown us a valid identity key. */ char identity_digest[DIGEST_LEN]; char *nickname; /**< Nickname of OR on other side (if any). */ tor_tls_t *tls; /**< TLS connection state. */ int tls_error; /**< Last tor_tls error code. */ /** When we last used this conn for any client traffic. If not * recent, we can rate limit it further. */ /* Channel using this connection */ channel_tls_t *chan; tor_addr_t real_addr; /**< The actual address that this connection came from * or went to. The addr field is prone to * getting overridden by the address from the router * descriptor matching identity_digest. */ /** Should this connection be used for extending circuits to the server * matching the identity_digest field? Set to true if we're pretty * sure we aren't getting MITMed, either because we're connected to an * address listed in a server descriptor, or because an authenticated * NETINFO cell listed the address we're connected to as recognized. */ unsigned int is_canonical:1; /** True iff we have decided that the other end of this connection * is a client. Connections with this flag set should never be used * to satisfy an EXTEND request. */ unsigned int is_connection_with_client:1; /** True iff this is an outgoing connection. */ unsigned int is_outgoing:1; unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */ unsigned int wide_circ_ids:1; uint16_t link_proto; /**< What protocol version are we using? 0 for * "none negotiated yet." */ or_handshake_state_t *handshake_state; /**< If we are setting this connection * up, state information to do so. */ time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/ time_t timestamp_last_added_nonpadding; /** When did we last add a * non-padding cell to the outbuf? */ /* bandwidth* and *_bucket only used by ORs in OPEN state: */ int bandwidthrate; /**< Bytes/s added to the bucket. (OPEN ORs only.) */ int bandwidthburst; /**< Max bucket size for this conn. (OPEN ORs only.) */ #ifndef USE_BUFFEREVENTS int read_bucket; /**< When this hits 0, stop receiving. Every second we * add 'bandwidthrate' to this, capping it at * bandwidthburst. (OPEN ORs only) */ int write_bucket; /**< When this hits 0, stop writing. Like read_bucket. */ #else /** A rate-limiting configuration object to determine how this connection * set its read- and write- limits. */ /* XXXX we could share this among all connections. */ struct ev_token_bucket_cfg *bucket_cfg; #endif struct or_connection_t *next_with_same_id; /**< Next connection with same * identity digest as this one. */ } or_connection_t; /** Subtype of connection_t for an "edge connection" -- that is, an entry (ap) * connection, or an exit. */ typedef struct edge_connection_t { connection_t base_; struct edge_connection_t *next_stream; /**< Points to the next stream at this * edge, if any */ int package_window; /**< How many more relay cells can I send into the * circuit? */ int deliver_window; /**< How many more relay cells can end at me? */ struct circuit_t *on_circuit; /**< The circuit (if any) that this edge * connection is using. */ /** A pointer to which node in the circ this conn exits at. Set for AP * connections and for hidden service exit connections. */ struct crypt_path_t *cpath_layer; /** What rendezvous service are we querying for (if an AP) or providing (if * an exit)? */ rend_data_t *rend_data; uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit * connection. Exit connections only. */ uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell * for this connection */ streamid_t stream_id; /**< The stream ID used for this edge connection on its * circuit */ /** The reason why this connection is closing; passed to the controller. */ uint16_t end_reason; /** Bytes read since last call to control_event_stream_bandwidth_used() */ uint32_t n_read; /** Bytes written since last call to control_event_stream_bandwidth_used() */ uint32_t n_written; /** True iff this connection is for a DNS request only. */ unsigned int is_dns_request:1; /** True iff this connection is for a PTR DNS request. (exit only) */ unsigned int is_reverse_dns_lookup:1; unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge * connections. Set once we've set the stream end, * and check in connection_about_to_close_connection(). */ /** True iff we've blocked reading until the circuit has fewer queued * cells. */ unsigned int edge_blocked_on_circ:1; /** Unique ID for directory requests; this used to be in connection_t, but * that's going away and being used on channels instead. We still tag * edge connections with dirreq_id from circuits, so it's copied here. */ uint64_t dirreq_id; } edge_connection_t; /** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS * connection, a DNS request, a TransPort connection or a NATD connection */ typedef struct entry_connection_t { edge_connection_t edge_; /** Nickname of planned exit node -- used with .exit support. */ char *chosen_exit_name; socks_request_t *socks_request; /**< SOCKS structure describing request (AP * only.) */ /* === Isolation related, AP only. === */ /** AP only: based on which factors do we isolate this stream? */ uint8_t isolation_flags; /** AP only: what session group is this stream in? */ int session_group; /** AP only: The newnym epoch in which we created this connection. */ unsigned nym_epoch; /** AP only: The original requested address before we rewrote it. */ char *original_dest_address; /* Other fields to isolate on already exist. The ClientAddr is addr. The ClientProtocol is a combination of type and socks_request-> socks_version. SocksAuth is socks_request->username/password. DestAddr is in socks_request->address. */ /** Number of times we've reassigned this application connection to * a new circuit. We keep track because the timeout is longer if we've * already retried several times. */ uint8_t num_socks_retries; /** For AP connections only: buffer for data that we have sent * optimistically, which we might need to re-send if we have to * retry this connection. */ generic_buffer_t *pending_optimistic_data; /* For AP connections only: buffer for data that we previously sent * optimistically which we are currently re-sending as we retry this * connection. */ generic_buffer_t *sending_optimistic_data; /** If this is a DNSPort connection, this field holds the pending DNS * request that we're going to try to answer. */ struct evdns_server_request *dns_server_request; #define NUM_CIRCUITS_LAUNCHED_THRESHOLD 10 /** Number of times we've launched a circuit to handle this stream. If * it gets too high, that could indicate an inconsistency between our * "launch a circuit to handle this stream" logic and our "attach our * stream to one of the available circuits" logic. */ unsigned int num_circuits_launched:4; /** True iff this stream must attach to a one-hop circuit (e.g. for * begin_dir). */ unsigned int want_onehop:1; /** True iff this stream should use a BEGIN_DIR relay command to establish * itself rather than BEGIN (either via onehop or via a whole circuit). */ unsigned int use_begindir:1; /** For AP connections only. If 1, and we fail to reach the chosen exit, * stop requiring it. */ unsigned int chosen_exit_optional:1; /** For AP connections only. If non-zero, this exit node was picked as * a result of the TrackHostExit, and the value decrements every time * we fail to complete a circuit to our chosen exit -- if it reaches * zero, abandon the associated mapaddress. */ unsigned int chosen_exit_retries:3; /** True iff this is an AP connection that came from a transparent or * NATd connection */ unsigned int is_transparent_ap:1; /** For AP connections only: Set if this connection's target exit node * allows optimistic data (that is, data sent on this stream before * the exit has sent a CONNECTED cell) and we have chosen to use it. */ unsigned int may_use_optimistic_data : 1; /** Should we permit IPv4 and IPv6 traffic to use this connection? * * @{ */ unsigned int ipv4_traffic_ok : 1; unsigned int ipv6_traffic_ok : 1; /** @} */ /** Should we say we prefer IPv6 traffic? */ unsigned int prefer_ipv6_traffic : 1; /** For a socks listener: should we cache IPv4/IPv6 DNS information that * exit nodes tell us? * * @{ */ unsigned int cache_ipv4_answers : 1; unsigned int cache_ipv6_answers : 1; /** @} */ /** For a socks listeners: if we find an answer in our client-side DNS cache, * should we use it? * * @{ */ unsigned int use_cached_ipv4_answers : 1; unsigned int use_cached_ipv6_answers : 1; /** @} */ /** For socks listeners: When we can automap an address to IPv4 or IPv6, * do we prefer IPv6? */ unsigned int prefer_ipv6_virtaddr : 1; } entry_connection_t; typedef enum { DIR_SPOOL_NONE=0, DIR_SPOOL_SERVER_BY_DIGEST, DIR_SPOOL_SERVER_BY_FP, DIR_SPOOL_EXTRA_BY_DIGEST, DIR_SPOOL_EXTRA_BY_FP, DIR_SPOOL_CACHED_DIR, DIR_SPOOL_NETWORKSTATUS, DIR_SPOOL_MICRODESC, /* NOTE: if we add another entry, add another bit. */ } dir_spool_source_t; /** Subtype of connection_t for an "directory connection" -- that is, an HTTP * connection to retrieve or serve directory material. */ typedef struct dir_connection_t { connection_t base_; /** Which 'resource' did we ask the directory for? This is typically the part * of the URL string that defines, relative to the directory conn purpose, * what thing we want. For example, in router descriptor downloads by * descriptor digest, it contains "d/", then one ore more +-separated * fingerprints. **/ char *requested_resource; unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */ /* Used only for server sides of some dir connections, to implement * "spooling" of directory material to the outbuf. Otherwise, we'd have * to append everything to the outbuf in one enormous chunk. */ /** What exactly are we spooling right now? */ ENUM_BF(dir_spool_source_t) dir_spool_src : 3; /** If we're fetching descriptors, what router purpose shall we assign * to them? */ uint8_t router_purpose; /** List of fingerprints for networkstatuses or descriptors to be spooled. */ smartlist_t *fingerprint_stack; /** A cached_dir_t object that we're currently spooling out */ struct cached_dir_t *cached_dir; /** The current offset into cached_dir. */ off_t cached_dir_offset; /** The zlib object doing on-the-fly compression for spooled data. */ tor_zlib_state_t *zlib_state; /** What rendezvous service are we querying for? */ rend_data_t *rend_data; char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for * the directory server's signing key. */ /** Unique ID for directory requests; this used to be in connection_t, but * that's going away and being used on channels instead. The dirserver still * needs this for the incoming side, so it's moved here. */ uint64_t dirreq_id; } dir_connection_t; /** Subtype of connection_t for an connection to a controller. */ typedef struct control_connection_t { connection_t base_; uint32_t event_mask; /**< Bitfield: which events does this controller * care about? */ /** True if we have sent a protocolinfo reply on this connection. */ unsigned int have_sent_protocolinfo:1; /** True if we have received a takeownership command on this * connection. */ unsigned int is_owning_control_connection:1; /** If we have sent an AUTHCHALLENGE reply on this connection and * have not received a successful AUTHENTICATE command, points to * the value which the client must send to authenticate itself; * otherwise, NULL. */ char *safecookie_client_hash; /** Amount of space allocated in incoming_cmd. */ uint32_t incoming_cmd_len; /** Number of bytes currently stored in incoming_cmd. */ uint32_t incoming_cmd_cur_len; /** A control command that we're reading from the inbuf, but which has not * yet arrived completely. */ char *incoming_cmd; } control_connection_t; /** Cast a connection_t subtype pointer to a connection_t **/ #define TO_CONN(c) (&(((c)->base_))) /** Helper macro: Given a pointer to to.base_, of type from*, return &to. */ #define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_)) /** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ #define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_)) /** Cast a entry_connection_t subtype pointer to a connection_t **/ #define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c))) /** Convert a connection_t* to an or_connection_t*; assert if the cast is * invalid. */ static or_connection_t *TO_OR_CONN(connection_t *); /** Convert a connection_t* to a dir_connection_t*; assert if the cast is * invalid. */ static dir_connection_t *TO_DIR_CONN(connection_t *); /** Convert a connection_t* to an edge_connection_t*; assert if the cast is * invalid. */ static edge_connection_t *TO_EDGE_CONN(connection_t *); /** Convert a connection_t* to an entry_connection_t*; assert if the cast is * invalid. */ static entry_connection_t *TO_ENTRY_CONN(connection_t *); /** Convert a edge_connection_t* to an entry_connection_t*; assert if the cast * is invalid. */ static entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *); /** Convert a connection_t* to an control_connection_t*; assert if the cast is * invalid. */ static control_connection_t *TO_CONTROL_CONN(connection_t *); /** Convert a connection_t* to an listener_connection_t*; assert if the cast is * invalid. */ static listener_connection_t *TO_LISTENER_CONN(connection_t *); static INLINE or_connection_t *TO_OR_CONN(connection_t *c) { tor_assert(c->magic == OR_CONNECTION_MAGIC); return DOWNCAST(or_connection_t, c); } static INLINE dir_connection_t *TO_DIR_CONN(connection_t *c) { tor_assert(c->magic == DIR_CONNECTION_MAGIC); return DOWNCAST(dir_connection_t, c); } static INLINE edge_connection_t *TO_EDGE_CONN(connection_t *c) { tor_assert(c->magic == EDGE_CONNECTION_MAGIC || c->magic == ENTRY_CONNECTION_MAGIC); return DOWNCAST(edge_connection_t, c); } static INLINE entry_connection_t *TO_ENTRY_CONN(connection_t *c) { tor_assert(c->magic == ENTRY_CONNECTION_MAGIC); return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); } static INLINE entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *c) { tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC); return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); } static INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c) { tor_assert(c->magic == CONTROL_CONNECTION_MAGIC); return DOWNCAST(control_connection_t, c); } static INLINE listener_connection_t *TO_LISTENER_CONN(connection_t *c) { tor_assert(c->magic == LISTENER_CONNECTION_MAGIC); return DOWNCAST(listener_connection_t, c); } /* Conditional macros to help write code that works whether bufferevents are disabled or not. We can't just write: if (conn->bufev) { do bufferevent stuff; } else { do other stuff; } because the bufferevent stuff won't even compile unless we have a fairly new version of Libevent. Instead, we say: IF_HAS_BUFFEREVENT(conn, { do_bufferevent_stuff } ); or: IF_HAS_BUFFEREVENT(conn, { do bufferevent stuff; }) ELSE_IF_NO_BUFFEREVENT { do non-bufferevent stuff; } If we're compiling with bufferevent support, then the macros expand more or less to: if (conn->bufev) { do_bufferevent_stuff; } else { do non-bufferevent stuff; } and if we aren't using bufferevents, they expand more or less to: { do non-bufferevent stuff; } */ #ifdef USE_BUFFEREVENTS #define HAS_BUFFEREVENT(c) (((c)->bufev) != NULL) #define IF_HAS_BUFFEREVENT(c, stmt) \ if ((c)->bufev) do { \ stmt ; \ } while (0) #define ELSE_IF_NO_BUFFEREVENT ; else #define IF_HAS_NO_BUFFEREVENT(c) \ if (NULL == (c)->bufev) #else #define HAS_BUFFEREVENT(c) (0) #define IF_HAS_BUFFEREVENT(c, stmt) (void)0 #define ELSE_IF_NO_BUFFEREVENT ; #define IF_HAS_NO_BUFFEREVENT(c) \ if (1) #endif /** What action type does an address policy indicate: accept or reject? */ typedef enum { ADDR_POLICY_ACCEPT=1, ADDR_POLICY_REJECT=2, } addr_policy_action_t; /** A reference-counted address policy rule. */ typedef struct addr_policy_t { int refcnt; /**< Reference count */ /** What to do when the policy matches.*/ ENUM_BF(addr_policy_action_t) policy_type:2; unsigned int is_private:1; /**< True iff this is the pseudo-address, * "private". */ unsigned int is_canonical:1; /**< True iff this policy is the canonical * copy (stored in a hash table to avoid * duplication of common policies) */ maskbits_t maskbits; /**< Accept/reject all addresses a such that the * first maskbits bits of a match * addr. */ /** Base address to accept or reject. * * Note that wildcards are treated * differntly depending on address family. An AF_UNSPEC address means * "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means * "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means * "All IPv6 addresses". **/ tor_addr_t addr; uint16_t prt_min; /**< Lowest port number to accept/reject. */ uint16_t prt_max; /**< Highest port number to accept/reject. */ } addr_policy_t; /** A cached_dir_t represents a cacheable directory object, along with its * compressed form. */ typedef struct cached_dir_t { char *dir; /**< Contents of this object, NUL-terminated. */ char *dir_z; /**< Compressed contents of this object. */ size_t dir_len; /**< Length of dir (not counting its NUL). */ size_t dir_z_len; /**< Length of dir_z. */ time_t published; /**< When was this object published. */ digests_t digests; /**< Digests of this object (networkstatus only) */ int refcnt; /**< Reference count for this cached_dir_t. */ } cached_dir_t; /** Enum used to remember where a signed_descriptor_t is stored and how to * manage the memory for signed_descriptor_body. */ typedef enum { /** The descriptor isn't stored on disk at all: the copy in memory is * canonical; the saved_offset field is meaningless. */ SAVED_NOWHERE=0, /** The descriptor is stored in the cached_routers file: the * signed_descriptor_body is meaningless; the signed_descriptor_len and * saved_offset are used to index into the mmaped cache file. */ SAVED_IN_CACHE, /** The descriptor is stored in the cached_routers.new file: the * signed_descriptor_body and saved_offset fields are both set. */ /* FFFF (We could also mmap the file and grow the mmap as needed, or * lazy-load the descriptor text by using seek and read. We don't, for * now.) */ SAVED_IN_JOURNAL } saved_location_t; /** Enumeration: what kind of download schedule are we using for a given * object? */ typedef enum { DL_SCHED_GENERIC = 0, DL_SCHED_CONSENSUS = 1, DL_SCHED_BRIDGE = 2, } download_schedule_t; /** Information about our plans for retrying downloads for a downloadable * object. */ typedef struct download_status_t { time_t next_attempt_at; /**< When should we try downloading this descriptor * again? */ uint8_t n_download_failures; /**< Number of failures trying to download the * most recent descriptor. */ ENUM_BF(download_schedule_t) schedule : 8; } download_status_t; /** If n_download_failures is this high, the download can never happen. */ #define IMPOSSIBLE_TO_DOWNLOAD 255 /** The max size we expect router descriptor annotations we create to * be. We'll accept larger ones if we see them on disk, but we won't * create any that are larger than this. */ #define ROUTER_ANNOTATION_BUF_LEN 256 /** Information need to cache an onion router's descriptor. */ typedef struct signed_descriptor_t { /** Pointer to the raw server descriptor, preceded by annotations. Not * necessarily NUL-terminated. If saved_location is SAVED_IN_CACHE, this * pointer is null. */ char *signed_descriptor_body; /** Length of the annotations preceding the server descriptor. */ size_t annotations_len; /** Length of the server descriptor. */ size_t signed_descriptor_len; /** Digest of the server descriptor, computed as specified in * dir-spec.txt. */ char signed_descriptor_digest[DIGEST_LEN]; /** Identity digest of the router. */ char identity_digest[DIGEST_LEN]; /** Declared publication time of the descriptor. */ time_t published_on; /** For routerdescs only: digest of the corresponding extrainfo. */ char extra_info_digest[DIGEST_LEN]; /** For routerdescs only: Status of downloading the corresponding * extrainfo. */ download_status_t ei_dl_status; /** Where is the descriptor saved? */ saved_location_t saved_location; /** If saved_location is SAVED_IN_CACHE or SAVED_IN_JOURNAL, the offset of * this descriptor in the corresponding file. */ off_t saved_offset; /** What position is this descriptor within routerlist->routers or * routerlist->old_routers? -1 for none. */ int routerlist_index; /** The valid-until time of the most recent consensus that listed this * descriptor, or a bit after the publication time of the most recent v2 * networkstatus that listed it. 0 for "never listed in a consensus or * status, so far as we know." */ time_t last_listed_as_valid_until; /* If true, we do not ever try to save this object in the cache. */ unsigned int do_not_cache : 1; /* If true, this item is meant to represent an extrainfo. */ unsigned int is_extrainfo : 1; /* If true, we got an extrainfo for this item, and the digest was right, * but it was incompatible. */ unsigned int extrainfo_is_bogus : 1; /* If true, we are willing to transmit this item unencrypted. */ unsigned int send_unencrypted : 1; } signed_descriptor_t; /** A signed integer representing a country code. */ typedef int16_t country_t; /** Information about another onion router in the network. */ typedef struct { signed_descriptor_t cache_info; char *address; /**< Location of OR: either a hostname or an IP address. */ char *nickname; /**< Human-readable OR name. */ uint32_t addr; /**< IPv4 address of OR, in host order. */ uint16_t or_port; /**< Port for TLS connections. */ uint16_t dir_port; /**< Port for HTTP directory connections. */ /** A router's IPv6 address, if it has one. */ /* XXXXX187 Actually these should probably be part of a list of addresses, * not just a special case. Use abstractions to access these; don't do it * directly. */ tor_addr_t ipv6_addr; uint16_t ipv6_orport; crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */ crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ /** Public curve25519 key for onions */ curve25519_public_key_t *onion_curve25519_pkey; char *platform; /**< What software/operating system is this OR using? */ /* link info */ uint32_t bandwidthrate; /**< How many bytes does this OR add to its token * bucket per second? */ uint32_t bandwidthburst; /**< How large is this OR's token bucket? */ /** How many bytes/s is this router known to handle? */ uint32_t bandwidthcapacity; smartlist_t *exit_policy; /**< What streams will this OR permit * to exit on IPv4? NULL for 'reject *:*'. */ /** What streams will this OR permit to exit on IPv6? * NULL for 'reject *:*' */ struct short_policy_t *ipv6_exit_policy; long uptime; /**< How many seconds the router claims to have been up */ smartlist_t *declared_family; /**< Nicknames of router which this router * claims are its family. */ char *contact_info; /**< Declared contact info for this router. */ unsigned int is_hibernating:1; /**< Whether the router claims to be * hibernating */ unsigned int caches_extra_info:1; /**< Whether the router says it caches and * serves extrainfo documents. */ unsigned int allow_single_hop_exits:1; /**< Whether the router says * it allows single hop exits. */ unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be * a hidden service directory. */ unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this * router rejects everything. */ /** True if, after we have added this router, we should re-launch * tests for it. */ unsigned int needs_retest_if_added:1; /** Tor can use this router for general positions in circuits; we got it * from a directory server as usual, or we're an authority and a server * uploaded it. */ #define ROUTER_PURPOSE_GENERAL 0 /** Tor should avoid using this router for circuit-building: we got it * from a crontroller. If the controller wants to use it, it'll have to * ask for it by identity. */ #define ROUTER_PURPOSE_CONTROLLER 1 /** Tor should use this router only for bridge positions in circuits: we got * it via a directory request from the bridge itself, or a bridge * authority. x*/ #define ROUTER_PURPOSE_BRIDGE 2 /** Tor should not use this router; it was marked in cached-descriptors with * a purpose we didn't recognize. */ #define ROUTER_PURPOSE_UNKNOWN 255 /* In what way did we find out about this router? One of ROUTER_PURPOSE_*. * Routers of different purposes are kept segregated and used for different * things; see notes on ROUTER_PURPOSE_* macros above. */ uint8_t purpose; } routerinfo_t; /** Information needed to keep and cache a signed extra-info document. */ typedef struct extrainfo_t { signed_descriptor_t cache_info; /** The router's nickname. */ char nickname[MAX_NICKNAME_LEN+1]; /** True iff we found the right key for this extra-info, verified the * signature, and found it to be bad. */ unsigned int bad_sig : 1; /** If present, we didn't have the right key to verify this extra-info, * so this is a copy of the signature in the document. */ char *pending_sig; /** Length of pending_sig. */ size_t pending_sig_len; } extrainfo_t; /** Contents of a single router entry in a network status object. */ typedef struct routerstatus_t { time_t published_on; /**< When was this router published? */ char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it * has. */ char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity * key. */ /** Digest of the router's most recent descriptor or microdescriptor. * If it's a descriptor, we only use the first DIGEST_LEN bytes. */ char descriptor_digest[DIGEST256_LEN]; uint32_t addr; /**< IPv4 address for this router. */ uint16_t or_port; /**< OR port for this router. */ uint16_t dir_port; /**< Directory port for this router. */ tor_addr_t ipv6_addr; /**< IPv6 address for this router. */ uint16_t ipv6_orport; /**