Skip to content

Commit

Permalink
Introduce the beginnings of anti-DoS resource scheduling.
Browse files Browse the repository at this point in the history
This adds code that takes effect if a node gets completely full (this should never happen unless there's an attack or the number of nodes falls dangerously low).

Peers now have a priority that attempts to estimate their importance. Currently it is just based on IP address. The default score is zero. In future it may take into account things like how many blocks were relayed, etc. When a node reaches its max connection slots, it will attempt to find a peer with a lower priority than the one trying to connect and disconnect it, to stay below the max connection limit.

Peer priorities are based on matching the connecting IP against a set of IP groups. For now, the only IP group is one that gives Tor exits a score of -10. This is to address DoS attacks that are being reported on the main network in which an attacker builds many connections via Tor to use up all the connection slots and jam the node for clearnet users. It's a more robust approach than simply banning abused proxies altogether.

The code has both a static list and a list that's downloaded when the node starts.

Other anonymizing proxy networks that are attractive to DoS attackers may also be added as alternative IP groups, as a quick fix. Eventually peer priority can be calculated in a more free floating and dynamic manner and the hardcoded IP approach may become unneeded.
  • Loading branch information
mikehearn committed Aug 6, 2015
1 parent 14de651 commit 73c9efe
Show file tree
Hide file tree
Showing 15 changed files with 1,577 additions and 12 deletions.
10 changes: 10 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ case $host in
openssl_prefix=`$BREW --prefix openssl 2>/dev/null`
bdb_prefix=`$BREW --prefix berkeley-db4 2>/dev/null`
qt5_prefix=`$BREW --prefix qt5 2>/dev/null`
curl_prefix=`$BREW --prefix curl 2>/dev/null`
if test x$openssl_prefix != x; then
PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH
Expand All @@ -285,6 +286,9 @@ case $host in
PKG_CONFIG_PATH="$qt5_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH
fi
if test x$curl_prefix != x; then
PKG_CONFIG_PATH="$curl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
fi
fi
else
case $build_os in
Expand Down Expand Up @@ -662,6 +666,7 @@ if test x$use_pkgconfig = xyes; then
if test x$use_qr != xno; then
BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])])
fi
PKG_CHECK_MODULES([CURL], [libcurl],,[AC_MSG_ERROR(libcurl not found)])
]
)
else
Expand All @@ -676,6 +681,9 @@ else
BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])])
BITCOIN_QT_CHECK([AC_CHECK_HEADER([qrencode.h],, have_qrencode=no)])
fi

AC_CHECK_HEADER([curl/curl.h],,AC_MSG_ERROR(libcurl headers missing))
AC_CHECK_LIB([curl], [main],CURL_LIBS=-lcurl, AC_MSG_ERROR(libcurl missing))
fi

AC_CHECK_LIB([crypto],[RAND_egd],[],[
Expand Down Expand Up @@ -867,6 +875,8 @@ AC_SUBST(BUILD_QT)
AC_SUBST(BUILD_TEST_QT)
AC_SUBST(MINIUPNPC_CPPFLAGS)
AC_SUBST(MINIUPNPC_LIBS)
AC_SUBST(CURL_FLAGS)
AC_SUBST(CURL_LIBS)
AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh])
AC_CONFIG_FILES([qa/pull-tester/tests-config.sh],[chmod +x qa/pull-tester/tests-config.sh])
Expand Down
22 changes: 22 additions & 0 deletions contrib/torips/gen-tor-ips.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python

# Script to generate a C++ source file containing known Tor exits.
# This is used to help nodes treat Tor traffic homogenously.

import urllib2, time

data = urllib2.urlopen("https://check.torproject.org/exit-addresses").read()
exitlines = [line for line in data.split('\n') if line.startswith("ExitAddress")]
ipstrs = [line.split()[1] for line in exitlines]
ipstrs.sort()

contents = """// Generated at %s by gen-tor-ips.py: DO NOT EDIT
static const char *pszTorExits[] = {
"0.1.2.3", // For unit testing
%s
NULL
};
""" % (time.asctime(), "\n".join([" \"%s\"," % ip for ip in ipstrs]))

print contents
22 changes: 22 additions & 0 deletions depends/packages/curl.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package=curl
$(package)_version=7.43.0
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_download_path=http://curl.haxx.se/download
$(package)_sha256_hash=1a084da1edbfc3bd632861358b26af45ba91aaadfb15d6482de55748b8dfc693
$(package)_dependencies=openssl

define $(package)_set_vars
$(package)_config_opts=--disable-shared --with-ssl
endef

define $(package)_config_cmds
$($(package)_autoconf)
endef

define $(package)_build_cmds
$(MAKE)
endef

define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
2 changes: 1 addition & 1 deletion depends/packages/packages.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
packages:=boost openssl
packages:=boost openssl curl
native_packages := native_ccache native_comparisontool

qt_native_packages = native_protobuf
Expand Down
7 changes: 5 additions & 2 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ $(LIBLEVELDB) $(LIBMEMENV):
endif

BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) $(CURL_CFLAGS)

BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include

Expand Down Expand Up @@ -98,6 +98,7 @@ BITCOIN_CORE_H = \
ecwrapper.h \
hash.h \
init.h \
ipgroups.h \
key.h \
keystore.h \
leveldbwrapper.h \
Expand Down Expand Up @@ -137,6 +138,7 @@ BITCOIN_CORE_H = \
threadsafety.h \
timedata.h \
tinyformat.h \
torips.h \
txdb.h \
txmempool.h \
ui_interface.h \
Expand Down Expand Up @@ -180,6 +182,7 @@ libbitcoin_server_a_SOURCES = \
chain.cpp \
checkpoints.cpp \
init.cpp \
ipgroups.cpp \
leveldbwrapper.cpp \
main.cpp \
merkleblock.cpp \
Expand Down Expand Up @@ -328,7 +331,7 @@ if ENABLE_WALLET
bitcoind_LDADD += libbitcoin_wallet.a
endif

bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(CURL_LIBS)
#

# bitcoin-cli binary #
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ if ENABLE_WALLET
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1)
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(CURL_LIBS)
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_bitcoin_qt_LIBTOOLFLAGS = --tag CXX

Expand Down
2 changes: 1 addition & 1 deletion src/Makefile.qttest.include
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1)
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(CURL_LIBS)
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)

CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno
Expand Down
3 changes: 2 additions & 1 deletion src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ BITCOIN_TESTS =\
test/DoS_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
test/ipgroups_tests.cpp \
test/key_tests.cpp \
test/main_tests.cpp \
test/mempool_tests.cpp \
Expand Down Expand Up @@ -92,7 +93,7 @@ if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
endif

test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(CURL_LIBS)
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static

nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
Expand Down
Loading

2 comments on commit 73c9efe

@dagurval
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone was complaining about lack of peer review of this feature on the mailing list, so I took a look at it. Now you have one more.

It looks fine. I just did some nitpicking.

If the unittest framework allows, I think it would be nice to have test that checks that InitTorIPGroups is not called if any of the conditions we don't want it in exist (disableipprio, !fListen, proxy for ipv4 or ipv6 or tor)

@mikehearn
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. It was actually reviewed by Gavin, a Tor developer, and I got some comments via private email too, but more is always welcome.

The Core/XT code base is a bit hard to unit test because so much state is in global variables and there's no easy way to reset things. But yeah testing the init path would be a good improvement too.

Please sign in to comment.