// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/base/port_util.h" #include #include #include "base/lazy_instance.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "url/url_constants.h" namespace net { namespace { // The general list of blocked ports. Will be blocked unless a specific // protocol overrides it. (Ex: ftp can use ports 20 and 21) const int kRestrictedPorts[] = { 1, // tcpmux 7, // echo 9, // discard 11, // systat 13, // daytime 15, // netstat 17, // qotd 19, // chargen 20, // ftp data 21, // ftp access 22, // ssh 23, // telnet 25, // smtp 37, // time 42, // name 43, // nicname 53, // domain 77, // priv-rjs 79, // finger 87, // ttylink 95, // supdup 101, // hostriame 102, // iso-tsap 103, // gppitnp 104, // acr-nema 109, // pop2 110, // pop3 111, // sunrpc 113, // auth 115, // sftp 117, // uucp-path 119, // nntp 123, // NTP 135, // loc-srv /epmap 139, // netbios 143, // imap2 179, // BGP 389, // ldap 465, // smtp+ssl 512, // print / exec 513, // login 514, // shell 515, // printer 526, // tempo 530, // courier 531, // chat 532, // netnews 540, // uucp 556, // remotefs 563, // nntp+ssl 587, // stmp? 601, // ?? 636, // ldap+ssl 993, // ldap+ssl 995, // pop3+ssl 2049, // nfs 3659, // apple-sasl / PasswordServer 4045, // lockd 6000, // X11 6665, // Alternate IRC [Apple addition] 6666, // Alternate IRC [Apple addition] 6667, // Standard IRC [Apple addition] 6668, // Alternate IRC [Apple addition] 6669, // Alternate IRC [Apple addition] 0xFFFF, // Used to block all invalid port numbers (see // third_party/WebKit/Source/platform/weborigin/KURL.cpp, // KURL::port()) }; // FTP overrides the following restricted ports. const int kAllowedFtpPorts[] = { 21, // ftp data 22, // ssh }; base::LazyInstance>::Leaky g_explicitly_allowed_ports = LAZY_INSTANCE_INITIALIZER; } // namespace bool IsPortValid(int port) { return port >= 0 && port <= std::numeric_limits::max(); } bool IsWellKnownPort(int port) { return port >= 0 && port < 1024; } bool IsPortAllowedForScheme(int port, const std::string& url_scheme) { // Reject invalid ports. if (!IsPortValid(port)) return false; // Allow explitly allowed ports for any scheme. if (g_explicitly_allowed_ports.Get().count(port) > 0) return true; // FTP requests have an extra set of whitelisted schemes. if (base::LowerCaseEqualsASCII(url_scheme, url::kFtpScheme)) { for (int allowed_ftp_port : kAllowedFtpPorts) { if (allowed_ftp_port == port) return true; } } // Finally check against the generic list of restricted ports for all // schemes. for (int restricted_port : kRestrictedPorts) { if (restricted_port == port) return false; } return true; } size_t GetCountOfExplicitlyAllowedPorts() { return g_explicitly_allowed_ports.Get().size(); } // Specifies a comma separated list of port numbers that should be accepted // despite bans. If the string is invalid no allowed ports are stored. void SetExplicitlyAllowedPorts(const std::string& allowed_ports) { if (allowed_ports.empty()) return; std::multiset ports; size_t last = 0; size_t size = allowed_ports.size(); // The comma delimiter. const std::string::value_type kComma = ','; // Overflow is still possible for evil user inputs. for (size_t i = 0; i <= size; ++i) { // The string should be composed of only digits and commas. if (i != size && !base::IsAsciiDigit(allowed_ports[i]) && (allowed_ports[i] != kComma)) return; if (i == size || allowed_ports[i] == kComma) { if (i > last) { int port; base::StringToInt(base::StringPiece(allowed_ports.begin() + last, allowed_ports.begin() + i), &port); ports.insert(port); } last = i + 1; } } g_explicitly_allowed_ports.Get() = ports; } ScopedPortException::ScopedPortException(int port) : port_(port) { g_explicitly_allowed_ports.Get().insert(port); } ScopedPortException::~ScopedPortException() { std::multiset::iterator it = g_explicitly_allowed_ports.Get().find(port_); if (it != g_explicitly_allowed_ports.Get().end()) g_explicitly_allowed_ports.Get().erase(it); else NOTREACHED(); } } // namespace net