blob: ea3e30bf697576f326092801c5edade54d2c6e1a [file] [log] [blame]
// 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
427, // SLP (Also used by Apple Filing Protocol)
465, // smtp+ssl
512, // print / exec
513, // login
514, // shell
515, // printer
526, // tempo
530, // courier
531, // chat
532, // netnews
540, // uucp
548, // AFP (Apple Filing Protocol)
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
};
// 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() {
auto 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