Commit 96bd27bc authored by pkasting@chromium.org's avatar pkasting@chromium.org

Clean up SSL false start blacklist code. Numerous changes, including:

  * Handle trailing dots in LastTwoLabels() as in http://codereview.chromium.org/7518035/ .  Rename this function to LastTwoComponents() to match the terminology used in the RegistryControlledDomainService and elsewhere in Chrome.
  * Since callers are using std::string anyway, make the functions in the header take const std::string& instead of char*.  This also allows doing string operations on them.
  * Use string operations (like find_last_of()) in place of hand-written algorithms, for brevity, clarity, and safety.
  * Avoid "unsigned", which the style guide forbids, and use allowed types like size_t, uint32, or int (depending on the situation).
  * Avoid #define and "using".
  * Use standard algorithms for similar reasons as using string ops.
  * Use file_util functions to significantly abbreviate file reading/writing code.
  * Use wmain() (on Windows) in combination with FilePath to avoid issues if the provided pathname has extended characters that don't flatten losslessly to the default codepage (thanks Darin for pointing out this issue).
  * Avoid casting where possible.  Avoid some casts for printf()-style calls by using a string stream, which also allows for slightly less boilerplate.
  * Convert non-error uses of stderr to the chrome-standard VLOG(1).
  * Correctly handle hostnames with trailing dots in the input file.
  * In general, shorten code where possible.

Because this adds a dependency on base, and ssl_false_start_blacklist_process has the "#host" specifier in net.gyp, bradnelson tells me that base and its dependencies need an explicit "host, target" toolchain list for the Linux builds to work correctly.  It would be nice if we could avoid this but I guess gyp would have to be smarter or something.

BUG=none
TEST=none
Review URL: http://codereview.chromium.org/7550002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95907 0039d316-1c4b-4281-b951-d872f2087c98
parent f684678c
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
# base depends on base_static. # base depends on base_static.
'target_name': 'base_static', 'target_name': 'base_static',
'type': 'static_library', 'type': 'static_library',
'toolsets': ['host', 'target'],
'sources': [ 'sources': [
'base_switches.cc', 'base_switches.cc',
'base_switches.h', 'base_switches.h',
......
...@@ -446,6 +446,7 @@ ...@@ -446,6 +446,7 @@
{ {
'target_name': 'base', 'target_name': 'base',
'type': '<(component)', 'type': '<(component)',
'toolsets': ['host', 'target'],
'variables': { 'variables': {
'base_target': 1, 'base_target': 1,
}, },
...@@ -664,6 +665,7 @@ ...@@ -664,6 +665,7 @@
{ {
'target_name': 'symbolize', 'target_name': 'symbolize',
'type': 'static_library', 'type': 'static_library',
'toolsets': ['host', 'target'],
'variables': { 'variables': {
'chromium_code': 0, 'chromium_code': 0,
}, },
...@@ -689,6 +691,7 @@ ...@@ -689,6 +691,7 @@
{ {
'target_name': 'xdg_mime', 'target_name': 'xdg_mime',
'type': 'static_library', 'type': 'static_library',
'toolsets': ['host', 'target'],
'variables': { 'variables': {
'chromium_code': 0, 'chromium_code': 0,
}, },
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
{ {
'target_name': 'dynamic_annotations', 'target_name': 'dynamic_annotations',
'type': 'static_library', 'type': 'static_library',
'toolsets': ['host', 'target'],
'include_dirs': [ 'include_dirs': [
'../../../', '../../../',
], ],
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
{ {
'target_name': 'gtk', 'target_name': 'gtk',
'type': 'settings', 'type': 'settings',
'toolsets': ['host', 'target'],
'conditions': [ 'conditions': [
['_toolset=="target"', { ['_toolset=="target"', {
'direct_dependent_settings': { 'direct_dependent_settings': {
...@@ -46,12 +47,27 @@ ...@@ -46,12 +47,27 @@
'<!@(<(pkg-config) --libs-only-l gtk+-2.0 gthread-2.0)', '<!@(<(pkg-config) --libs-only-l gtk+-2.0 gthread-2.0)',
], ],
}, },
}], }, {
[ 'chromeos==1', { 'direct_dependent_settings': {
'link_settings': { 'cflags': [
'libraries': [ '-lXtst' ] '<!@(pkg-config --cflags gtk+-2.0 gthread-2.0)',
} ],
}]] },
'link_settings': {
'ldflags': [
'<!@(pkg-config --libs-only-L --libs-only-other gtk+-2.0 gthread-2.0)',
],
'libraries': [
'<!@(pkg-config --libs-only-l gtk+-2.0 gthread-2.0)',
],
},
}],
['chromeos==1', {
'link_settings': {
'libraries': [ '-lXtst' ]
}
}],
],
}, },
{ {
'target_name': 'gtkprint', 'target_name': 'gtkprint',
...@@ -71,7 +87,8 @@ ...@@ -71,7 +87,8 @@
'<!@(<(pkg-config) --libs-only-l gtk+-unix-print-2.0)', '<!@(<(pkg-config) --libs-only-l gtk+-unix-print-2.0)',
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'ssl', 'target_name': 'ssl',
...@@ -152,7 +169,8 @@ ...@@ -152,7 +169,8 @@
'<!@(<(pkg-config) --libs-only-l freetype2)', '<!@(<(pkg-config) --libs-only-l freetype2)',
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'fontconfig', 'target_name': 'fontconfig',
...@@ -172,7 +190,8 @@ ...@@ -172,7 +190,8 @@
'<!@(<(pkg-config) --libs-only-l fontconfig)', '<!@(<(pkg-config) --libs-only-l fontconfig)',
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'gdk', 'target_name': 'gdk',
...@@ -192,7 +211,8 @@ ...@@ -192,7 +211,8 @@
'<!@(<(pkg-config) --libs-only-l gdk-2.0)', '<!@(<(pkg-config) --libs-only-l gdk-2.0)',
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'gconf', 'target_name': 'gconf',
...@@ -215,7 +235,8 @@ ...@@ -215,7 +235,8 @@
'<!@(<(pkg-config) --libs-only-l gconf-2.0)', '<!@(<(pkg-config) --libs-only-l gconf-2.0)',
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'gio', 'target_name': 'gio',
...@@ -250,11 +271,13 @@ ...@@ -250,11 +271,13 @@
}], }],
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'x11', 'target_name': 'x11',
'type': 'settings', 'type': 'settings',
'toolsets': ['host', 'target'],
'conditions': [ 'conditions': [
['_toolset=="target"', { ['_toolset=="target"', {
'direct_dependent_settings': { 'direct_dependent_settings': {
...@@ -270,7 +293,21 @@ ...@@ -270,7 +293,21 @@
'<!@(<(pkg-config) --libs-only-l x11 xi)', '<!@(<(pkg-config) --libs-only-l x11 xi)',
], ],
}, },
}], }, {
'direct_dependent_settings': {
'cflags': [
'<!@(pkg-config --cflags x11)',
],
},
'link_settings': {
'ldflags': [
'<!@(pkg-config --libs-only-L --libs-only-other x11 xi)',
],
'libraries': [
'<!@(pkg-config --libs-only-l x11 xi)',
],
},
}],
], ],
}, },
{ {
...@@ -291,7 +328,8 @@ ...@@ -291,7 +328,8 @@
'<!@(<(pkg-config) --libs-only-l xext)', '<!@(<(pkg-config) --libs-only-l xext)',
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'libgcrypt', 'target_name': 'libgcrypt',
...@@ -308,7 +346,8 @@ ...@@ -308,7 +346,8 @@
'<!@(libgcrypt-config --libs)', '<!@(libgcrypt-config --libs)',
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'selinux', 'target_name': 'selinux',
...@@ -320,7 +359,8 @@ ...@@ -320,7 +359,8 @@
'-lselinux', '-lselinux',
], ],
}, },
}]] }],
],
}, },
{ {
'target_name': 'gnome_keyring', 'target_name': 'gnome_keyring',
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
{ {
'target_name': 'lastchange', 'target_name': 'lastchange',
'type': 'none', 'type': 'none',
'toolsets': ['host', 'target'],
'variables': { 'variables': {
'lastchange_out_path': '<(SHARED_INTERMEDIATE_DIR)/build/LASTCHANGE', 'lastchange_out_path': '<(SHARED_INTERMEDIATE_DIR)/build/LASTCHANGE',
'default_lastchange_path': '../LASTCHANGE.in', 'default_lastchange_path': '../LASTCHANGE.in',
......
...@@ -52,7 +52,7 @@ SSLConfigService::SSLConfigService() ...@@ -52,7 +52,7 @@ SSLConfigService::SSLConfigService()
// static // static
bool SSLConfigService::IsKnownFalseStartIncompatibleServer( bool SSLConfigService::IsKnownFalseStartIncompatibleServer(
const std::string& hostname) { const std::string& hostname) {
return SSLFalseStartBlacklist::IsMember(hostname.c_str()); return SSLFalseStartBlacklist::IsMember(hostname);
} }
static bool g_cached_info_enabled = false; static bool g_cached_info_enabled = false;
......
// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -7,22 +7,19 @@ ...@@ -7,22 +7,19 @@
namespace net { namespace net {
// static // static
bool SSLFalseStartBlacklist::IsMember(const char* host) { bool SSLFalseStartBlacklist::IsMember(const std::string& host) {
const char* last_two_labels = LastTwoLabels(host); const std::string last_two_components(LastTwoComponents(host));
if (!last_two_labels) if (last_two_components.empty())
return false; return false;
const unsigned bucket = Hash(last_two_labels) & (kBuckets - 1);
const uint32 start = kHashTable[bucket];
const uint32 end = kHashTable[bucket + 1];
const size_t len = strlen(host);
for (size_t i = start; i < end;) { const size_t bucket = Hash(last_two_components) & (kBuckets - 1);
for (size_t i = kHashTable[bucket]; i < kHashTable[bucket + 1]; ) {
const size_t blacklist_entry_len = static_cast<uint8>(kHashData[i]); const size_t blacklist_entry_len = static_cast<uint8>(kHashData[i]);
if (len >= blacklist_entry_len && if (host.length() >= blacklist_entry_len &&
memcmp(&host[len - blacklist_entry_len], &kHashData[i + 1], !host.compare(host.length() - blacklist_entry_len, blacklist_entry_len,
blacklist_entry_len) == 0 && &kHashData[i + 1], blacklist_entry_len) &&
(len == blacklist_entry_len || (host.length() == blacklist_entry_len ||
host[len - blacklist_entry_len - 1] == '.')) { host[host.length() - blacklist_entry_len - 1] == '.')) {
return true; return true;
} }
i += blacklist_entry_len + 1; i += blacklist_entry_len + 1;
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
#ifndef NET_BASE_SSL_FALSE_START_BLACKLIST_H_ #ifndef NET_BASE_SSL_FALSE_START_BLACKLIST_H_
#define NET_BASE_SSL_FALSE_START_BLACKLIST_H_ #define NET_BASE_SSL_FALSE_START_BLACKLIST_H_
#include "base/basictypes.h" #include <string>
#include "base/logging.h"
#include "net/base/net_api.h" #include "net/base/net_api.h"
namespace net { namespace net {
...@@ -16,64 +18,42 @@ namespace net { ...@@ -16,64 +18,42 @@ namespace net {
// table for fast lookups. // table for fast lookups.
class SSLFalseStartBlacklist { class SSLFalseStartBlacklist {
public: public:
// IsMember returns true if the given host is in the blacklist. // Returns true if |host| (a DNS name in dotted form, e.g. "www.example.com")
// host: a DNS name in dotted form (i.e. "www.example.com") // is in the blacklist.
NET_TEST static bool IsMember(const char* host); NET_TEST static bool IsMember(const std::string& host);
// Hash returns the modified djb2 hash of the given string. // Returns the modified djb2 hash of |host|.
static unsigned Hash(const char* str) { // NOTE: This is inline because the code which generates the hash table needs
// This is inline because the code which generates the hash table needs to // to use it. However, the generating code cannot link against
// use it. However, the generating code cannot link against // ssl_false_start_blacklist.cc because that needs the tables which it
// ssl_false_start_blacklist.cc because that needs the tables which it // generates.
// generates. static uint32 Hash(const std::string& host) {
const unsigned char* in = reinterpret_cast<const unsigned char*>(str); uint32 hash = 5381;
unsigned hash = 5381; for (const uint8* in = reinterpret_cast<const uint8*>(host.c_str());
unsigned char c; *in != 0; ++in)
hash = ((hash << 5) + hash) ^ *in;
while ((c = *in++))
hash = ((hash << 5) + hash) ^ c;
return hash; return hash;
} }
// LastTwoLabels returns a pointer within |host| to the last two labels of // Returns the last two dot-separated components of |host|, ignoring any
// |host|. For example, if |host| is "a.b.c.d" then LastTwoLabels will return // trailing dots. For example, returns "c.d" for "a.b.c.d.". Returns an
// "c.d". // empty string if |host| does not have two dot-separated components.
// host: a DNS name in dotted form. // NOTE: Inline for the same reason as Hash().
// returns: NULL on error, otherwise a pointer inside |host|. static std::string LastTwoComponents(const std::string& host) {
static const char* LastTwoLabels(const char* host) { size_t last_nondot = host.find_last_not_of('.');
// See comment in |Hash| for why this function is inline. if (last_nondot == std::string::npos)
const size_t len = strlen(host); return std::string();
if (len == 0) size_t last_dot = host.find_last_of('.', last_nondot);
return NULL; if ((last_dot == 0) || (last_dot == std::string::npos))
return std::string();
unsigned dots_found = 0; // NOTE: This next line works correctly even when the call returns npos.
size_t i; size_t components_begin = host.find_last_of('.', last_dot - 1) + 1;
for (i = len - 1; i < len; i--) { return host.substr(components_begin, last_nondot - components_begin + 1);
if (host[i] == '.') {
dots_found++;
if (dots_found == 2) {
i++;
break;
}
}
}
if (i > len)
i = 0;
if (dots_found == 0)
return NULL; // no names with less than two labels are in the blacklist.
if (dots_found == 1) {
if (host[0] == '.')
return NULL; // ditto
}
return &host[i];
} }
// This is the number of buckets in the blacklist hash table. (Must be a // This is the number of buckets in the blacklist hash table. (Must be a
// power of two). // power of two).
static const unsigned kBuckets = 128; static const size_t kBuckets = 128;
private: private:
// The following two members are defined in // The following two members are defined in
......
...@@ -7,18 +7,17 @@ ...@@ -7,18 +7,17 @@
namespace net { namespace net {
TEST(SSLFalseStartBlacklistTest, LastTwoLabels) { TEST(SSLFalseStartBlacklistTest, LastTwoComponents) {
#define F SSLFalseStartBlacklist::LastTwoLabels EXPECT_EQ(SSLFalseStartBlacklist::LastTwoComponents("a.b.c.d"), "c.d");
EXPECT_STREQ(F("a.b.c.d"), "c.d"); EXPECT_EQ(SSLFalseStartBlacklist::LastTwoComponents("a.b"), "a.b");
EXPECT_STREQ(F("a.b"), "a.b"); EXPECT_EQ(SSLFalseStartBlacklist::LastTwoComponents("www.a.de"), "a.de");
EXPECT_STREQ(F("example.com"), "example.com"); EXPECT_EQ(SSLFalseStartBlacklist::LastTwoComponents("www.www.a.de"), "a.de");
EXPECT_STREQ(F("www.example.com"), "example.com"); EXPECT_EQ(SSLFalseStartBlacklist::LastTwoComponents("a.com."), "a.com");
EXPECT_STREQ(F("www.www.example.com"), "example.com"); EXPECT_EQ(SSLFalseStartBlacklist::LastTwoComponents("a.com.."), "a.com");
EXPECT_TRUE(F("com") == NULL); EXPECT_TRUE(SSLFalseStartBlacklist::LastTwoComponents("com").empty());
EXPECT_TRUE(F(".com") == NULL); EXPECT_TRUE(SSLFalseStartBlacklist::LastTwoComponents(".com").empty());
EXPECT_TRUE(F("") == NULL); EXPECT_TRUE(SSLFalseStartBlacklist::LastTwoComponents("").empty());
#undef F
} }
TEST(SSLFalseStartBlacklistTest, IsMember) { TEST(SSLFalseStartBlacklistTest, IsMember) {
......
...@@ -194,6 +194,7 @@ ...@@ -194,6 +194,7 @@
'base/ssl_config_service_defaults.cc', 'base/ssl_config_service_defaults.cc',
'base/ssl_config_service_defaults.h', 'base/ssl_config_service_defaults.h',
'base/ssl_false_start_blacklist.cc', 'base/ssl_false_start_blacklist.cc',
'base/ssl_false_start_blacklist.h',
'base/ssl_info.cc', 'base/ssl_info.cc',
'base/ssl_info.h', 'base/ssl_info.h',
'base/static_cookie_policy.cc', 'base/static_cookie_policy.cc',
...@@ -1332,11 +1333,16 @@ ...@@ -1332,11 +1333,16 @@
'target_name': 'ssl_false_start_blacklist_process', 'target_name': 'ssl_false_start_blacklist_process',
'type': 'executable', 'type': 'executable',
'toolsets': ['host'], 'toolsets': ['host'],
'dependencies': [
'../base/base.gyp:base',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
],
'include_dirs': [ 'include_dirs': [
'..', '..',
], ],
'sources': [ 'sources': [
'base/ssl_false_start_blacklist_process.cc', 'base/ssl_false_start_blacklist_process.cc',
'base/ssl_false_start_blacklist.h',
], ],
}, },
], ],
...@@ -1351,7 +1357,7 @@ ...@@ -1351,7 +1357,7 @@
], ],
'dependencies': [ 'dependencies': [
'../base/base.gyp:base', '../base/base.gyp:base',
'net.gyp:net', 'net',
'../third_party/openssl/openssl.gyp:openssl', '../third_party/openssl/openssl.gyp:openssl',
], ],
'sources': [ 'sources': [
...@@ -1413,7 +1419,7 @@ ...@@ -1413,7 +1419,7 @@
'type': 'static_library', 'type': 'static_library',
'dependencies': [ 'dependencies': [
'../base/base.gyp:base', '../base/base.gyp:base',
'net.gyp:net', 'net',
], ],
'sources': [ 'sources': [
'curvecp/circular_buffer.cc', 'curvecp/circular_buffer.cc',
...@@ -1448,8 +1454,8 @@ ...@@ -1448,8 +1454,8 @@
'type': 'executable', 'type': 'executable',
'dependencies': [ 'dependencies': [
'../base/base.gyp:base', '../base/base.gyp:base',
'net.gyp:curvecp', 'curvecp',
'net.gyp:net', 'net',
'net_test_support', 'net_test_support',
'../testing/gmock.gyp:gmock', '../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest', '../testing/gtest.gyp:gtest',
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
'target_name': 'libevent', 'target_name': 'libevent',
'product_name': 'event', 'product_name': 'event',
'type': 'static_library', 'type': 'static_library',
'toolsets': ['host', 'target'],
'sources': [ 'sources': [
'buffer.c', 'buffer.c',
'evbuffer.c', 'evbuffer.c',
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
{ {
'target_name': 'modp_b64', 'target_name': 'modp_b64',
'type': 'static_library', 'type': 'static_library',
'toolsets': ['host', 'target'],
'sources': [ 'sources': [
'modp_b64.cc', 'modp_b64.cc',
'modp_b64.h', 'modp_b64.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment