1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/port_util.h"
6
7 #include <limits>
8 #include <set>
9
10 #include "base/lazy_instance.h"
11 #include "base/notreached.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "url/url_constants.h"
15
16 namespace net {
17
18 namespace {
19
20 // The general list of blocked ports. Will be blocked unless a specific
21 // protocol overrides it. (Ex: ftp can use ports 20 and 21)
22 const int kRestrictedPorts[] = {
23 1, // tcpmux
24 7, // echo
25 9, // discard
26 11, // systat
27 13, // daytime
28 15, // netstat
29 17, // qotd
30 19, // chargen
31 20, // ftp data
32 21, // ftp access
33 22, // ssh
34 23, // telnet
35 25, // smtp
36 37, // time
37 42, // name
38 43, // nicname
39 53, // domain
40 69, // tftp
41 77, // priv-rjs
42 79, // finger
43 87, // ttylink
44 95, // supdup
45 101, // hostriame
46 102, // iso-tsap
47 103, // gppitnp
48 104, // acr-nema
49 109, // pop2
50 110, // pop3
51 111, // sunrpc
52 113, // auth
53 115, // sftp
54 117, // uucp-path
55 119, // nntp
56 123, // NTP
57 135, // loc-srv /epmap
58 137, // netbios
59 139, // netbios
60 143, // imap2
61 161, // snmp
62 179, // BGP
63 389, // ldap
64 427, // SLP (Also used by Apple Filing Protocol)
65 465, // smtp+ssl
66 512, // print / exec
67 513, // login
68 514, // shell
69 515, // printer
70 526, // tempo
71 530, // courier
72 531, // chat
73 532, // netnews
74 540, // uucp
75 548, // AFP (Apple Filing Protocol)
76 556, // remotefs
77 563, // nntp+ssl
78 587, // smtp (rfc6409)
79 601, // syslog-conn (rfc3195)
80 636, // ldap+ssl
81 993, // ldap+ssl
82 995, // pop3+ssl
83 1719, // h323gatestat
84 1720, // h323hostcall
85 1723, // pptp
86 2049, // nfs
87 3659, // apple-sasl / PasswordServer
88 4045, // lockd
89 5060, // sip
90 5061, // sips
91 6000, // X11
92 6566, // sane-port
93 6665, // Alternate IRC [Apple addition]
94 6666, // Alternate IRC [Apple addition]
95 6667, // Standard IRC [Apple addition]
96 6668, // Alternate IRC [Apple addition]
97 6669, // Alternate IRC [Apple addition]
98 6697, // IRC + TLS
99 };
100
101 // FTP overrides the following restricted port.
102 const int kAllowedFtpPorts[] = {
103 21, // ftp data
104 };
105
106 base::LazyInstance<std::multiset<int>>::Leaky g_explicitly_allowed_ports =
107 LAZY_INSTANCE_INITIALIZER;
108
109 } // namespace
110
IsPortValid(int port)111 bool IsPortValid(int port) {
112 return port >= 0 && port <= std::numeric_limits<uint16_t>::max();
113 }
114
IsWellKnownPort(int port)115 bool IsWellKnownPort(int port) {
116 return port >= 0 && port < 1024;
117 }
118
IsPortAllowedForScheme(int port,base::StringPiece url_scheme)119 bool IsPortAllowedForScheme(int port, base::StringPiece url_scheme) {
120 // Reject invalid ports.
121 if (!IsPortValid(port))
122 return false;
123
124 // Allow explitly allowed ports for any scheme.
125 if (g_explicitly_allowed_ports.Get().count(port) > 0)
126 return true;
127
128 // FTP requests have an extra set of allowed schemes.
129 if (base::LowerCaseEqualsASCII(url_scheme, url::kFtpScheme)) {
130 for (int allowed_ftp_port : kAllowedFtpPorts) {
131 if (allowed_ftp_port == port)
132 return true;
133 }
134 }
135
136 // Finally check against the generic list of restricted ports for all
137 // schemes.
138 for (int restricted_port : kRestrictedPorts) {
139 if (restricted_port == port)
140 return false;
141 }
142
143 return true;
144 }
145
GetCountOfExplicitlyAllowedPorts()146 size_t GetCountOfExplicitlyAllowedPorts() {
147 return g_explicitly_allowed_ports.Get().size();
148 }
149
150 // Specifies a comma separated list of port numbers that should be accepted
151 // despite bans. If the string is invalid no allowed ports are stored.
SetExplicitlyAllowedPorts(const std::string & allowed_ports)152 void SetExplicitlyAllowedPorts(const std::string& allowed_ports) {
153 if (allowed_ports.empty())
154 return;
155
156 std::multiset<int> ports;
157 size_t last = 0;
158 size_t size = allowed_ports.size();
159 // The comma delimiter.
160 const std::string::value_type kComma = ',';
161
162 // Overflow is still possible for evil user inputs.
163 for (size_t i = 0; i <= size; ++i) {
164 // The string should be composed of only digits and commas.
165 if (i != size && !base::IsAsciiDigit(allowed_ports[i]) &&
166 (allowed_ports[i] != kComma))
167 return;
168 if (i == size || allowed_ports[i] == kComma) {
169 if (i > last) {
170 int port;
171 base::StringToInt(base::StringPiece(allowed_ports.begin() + last,
172 allowed_ports.begin() + i),
173 &port);
174 ports.insert(port);
175 }
176 last = i + 1;
177 }
178 }
179 g_explicitly_allowed_ports.Get() = ports;
180 }
181
ScopedPortException(int port)182 ScopedPortException::ScopedPortException(int port) : port_(port) {
183 g_explicitly_allowed_ports.Get().insert(port);
184 }
185
~ScopedPortException()186 ScopedPortException::~ScopedPortException() {
187 auto it = g_explicitly_allowed_ports.Get().find(port_);
188 if (it != g_explicitly_allowed_ports.Get().end())
189 g_explicitly_allowed_ports.Get().erase(it);
190 else
191 NOTREACHED();
192 }
193
194 } // namespace net
195