| // 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 <limits> | 
 | #include <set> | 
 |  | 
 | #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] | 
 |     6697,    // IRC + TLS | 
 |     0xFFFF,  // Used to block all invalid port numbers (see | 
 |              // third_party/WebKit/Source/platform/weborigin/KURL.cpp, | 
 |              // KURL::port()) | 
 | }; | 
 |  | 
 | // FTP overrides the following restricted port. | 
 | const int kAllowedFtpPorts[] = { | 
 |     21,  // ftp data | 
 | }; | 
 |  | 
 | base::LazyInstance<std::multiset<int>>::Leaky g_explicitly_allowed_ports = | 
 |     LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 | }  // namespace | 
 |  | 
 | bool IsPortValid(int port) { | 
 |   return port >= 0 && port <= std::numeric_limits<uint16_t>::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<int> 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<int>::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 |