1 /*
2 * Copyright 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "pc/ice_server_parsing.h"
12
13 #include <string>
14 #include <vector>
15
16 #include "p2p/base/port_interface.h"
17 #include "rtc_base/ip_address.h"
18 #include "rtc_base/socket_address.h"
19 #include "test/gtest.h"
20
21 namespace webrtc {
22
23 class IceServerParsingTest : public ::testing::Test {
24 public:
25 // Convenience functions for parsing a single URL. Result is stored in
26 // `stun_servers_` and `turn_servers_`.
ParseUrl(const std::string & url)27 bool ParseUrl(const std::string& url) {
28 return ParseUrl(url, std::string(), std::string());
29 }
30
ParseTurnUrl(const std::string & url)31 bool ParseTurnUrl(const std::string& url) {
32 return ParseUrl(url, "username", "password");
33 }
34
ParseUrl(const std::string & url,const std::string & username,const std::string & password)35 bool ParseUrl(const std::string& url,
36 const std::string& username,
37 const std::string& password) {
38 return ParseUrl(
39 url, username, password,
40 PeerConnectionInterface::TlsCertPolicy::kTlsCertPolicySecure);
41 }
42
ParseUrl(const std::string & url,const std::string & username,const std::string & password,PeerConnectionInterface::TlsCertPolicy tls_certificate_policy)43 bool ParseUrl(const std::string& url,
44 const std::string& username,
45 const std::string& password,
46 PeerConnectionInterface::TlsCertPolicy tls_certificate_policy) {
47 return ParseUrl(url, username, password, tls_certificate_policy, "");
48 }
49
ParseUrl(const std::string & url,const std::string & username,const std::string & password,PeerConnectionInterface::TlsCertPolicy tls_certificate_policy,const std::string & hostname)50 bool ParseUrl(const std::string& url,
51 const std::string& username,
52 const std::string& password,
53 PeerConnectionInterface::TlsCertPolicy tls_certificate_policy,
54 const std::string& hostname) {
55 stun_servers_.clear();
56 turn_servers_.clear();
57 PeerConnectionInterface::IceServers servers;
58 PeerConnectionInterface::IceServer server;
59 server.urls.push_back(url);
60 server.username = username;
61 server.password = password;
62 server.tls_cert_policy = tls_certificate_policy;
63 server.hostname = hostname;
64 servers.push_back(server);
65 return webrtc::ParseIceServersOrError(servers, &stun_servers_,
66 &turn_servers_)
67 .ok();
68 }
69
70 protected:
71 cricket::ServerAddresses stun_servers_;
72 std::vector<cricket::RelayServerConfig> turn_servers_;
73 };
74
75 // Make sure all STUN/TURN prefixes are parsed correctly.
TEST_F(IceServerParsingTest,ParseStunPrefixes)76 TEST_F(IceServerParsingTest, ParseStunPrefixes) {
77 EXPECT_TRUE(ParseUrl("stun:hostname"));
78 EXPECT_EQ(1U, stun_servers_.size());
79 EXPECT_EQ(0U, turn_servers_.size());
80
81 EXPECT_TRUE(ParseUrl("stuns:hostname"));
82 EXPECT_EQ(1U, stun_servers_.size());
83 EXPECT_EQ(0U, turn_servers_.size());
84
85 EXPECT_TRUE(ParseTurnUrl("turn:hostname"));
86 EXPECT_EQ(0U, stun_servers_.size());
87 EXPECT_EQ(1U, turn_servers_.size());
88 EXPECT_EQ(cricket::PROTO_UDP, turn_servers_[0].ports[0].proto);
89
90 EXPECT_TRUE(ParseTurnUrl("turns:hostname"));
91 EXPECT_EQ(0U, stun_servers_.size());
92 EXPECT_EQ(1U, turn_servers_.size());
93 EXPECT_EQ(cricket::PROTO_TLS, turn_servers_[0].ports[0].proto);
94 EXPECT_TRUE(turn_servers_[0].tls_cert_policy ==
95 cricket::TlsCertPolicy::TLS_CERT_POLICY_SECURE);
96
97 EXPECT_TRUE(ParseUrl(
98 "turns:hostname", "username", "password",
99 PeerConnectionInterface::TlsCertPolicy::kTlsCertPolicyInsecureNoCheck));
100 EXPECT_EQ(0U, stun_servers_.size());
101 EXPECT_EQ(1U, turn_servers_.size());
102 EXPECT_TRUE(turn_servers_[0].tls_cert_policy ==
103 cricket::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK);
104 EXPECT_EQ(cricket::PROTO_TLS, turn_servers_[0].ports[0].proto);
105
106 // invalid prefixes
107 EXPECT_FALSE(ParseUrl("stunn:hostname"));
108 EXPECT_FALSE(ParseUrl(":hostname"));
109 EXPECT_FALSE(ParseUrl(":"));
110 EXPECT_FALSE(ParseUrl(""));
111 }
112
TEST_F(IceServerParsingTest,VerifyDefaults)113 TEST_F(IceServerParsingTest, VerifyDefaults) {
114 // TURNS defaults
115 EXPECT_TRUE(ParseTurnUrl("turns:hostname"));
116 EXPECT_EQ(1U, turn_servers_.size());
117 EXPECT_EQ(5349, turn_servers_[0].ports[0].address.port());
118 EXPECT_EQ(cricket::PROTO_TLS, turn_servers_[0].ports[0].proto);
119
120 // TURN defaults
121 EXPECT_TRUE(ParseTurnUrl("turn:hostname"));
122 EXPECT_EQ(1U, turn_servers_.size());
123 EXPECT_EQ(3478, turn_servers_[0].ports[0].address.port());
124 EXPECT_EQ(cricket::PROTO_UDP, turn_servers_[0].ports[0].proto);
125
126 // STUN defaults
127 EXPECT_TRUE(ParseUrl("stun:hostname"));
128 EXPECT_EQ(1U, stun_servers_.size());
129 EXPECT_EQ(3478, stun_servers_.begin()->port());
130 }
131
132 // Check that the 6 combinations of IPv4/IPv6/hostname and with/without port
133 // can be parsed correctly.
TEST_F(IceServerParsingTest,ParseHostnameAndPort)134 TEST_F(IceServerParsingTest, ParseHostnameAndPort) {
135 EXPECT_TRUE(ParseUrl("stun:1.2.3.4:1234"));
136 EXPECT_EQ(1U, stun_servers_.size());
137 EXPECT_EQ("1.2.3.4", stun_servers_.begin()->hostname());
138 EXPECT_EQ(1234, stun_servers_.begin()->port());
139
140 EXPECT_TRUE(ParseUrl("stun:[1:2:3:4:5:6:7:8]:4321"));
141 EXPECT_EQ(1U, stun_servers_.size());
142 EXPECT_EQ("1:2:3:4:5:6:7:8", stun_servers_.begin()->hostname());
143 EXPECT_EQ(4321, stun_servers_.begin()->port());
144
145 EXPECT_TRUE(ParseUrl("stun:hostname:9999"));
146 EXPECT_EQ(1U, stun_servers_.size());
147 EXPECT_EQ("hostname", stun_servers_.begin()->hostname());
148 EXPECT_EQ(9999, stun_servers_.begin()->port());
149
150 EXPECT_TRUE(ParseUrl("stun:1.2.3.4"));
151 EXPECT_EQ(1U, stun_servers_.size());
152 EXPECT_EQ("1.2.3.4", stun_servers_.begin()->hostname());
153 EXPECT_EQ(3478, stun_servers_.begin()->port());
154
155 EXPECT_TRUE(ParseUrl("stun:[1:2:3:4:5:6:7:8]"));
156 EXPECT_EQ(1U, stun_servers_.size());
157 EXPECT_EQ("1:2:3:4:5:6:7:8", stun_servers_.begin()->hostname());
158 EXPECT_EQ(3478, stun_servers_.begin()->port());
159
160 EXPECT_TRUE(ParseUrl("stun:hostname"));
161 EXPECT_EQ(1U, stun_servers_.size());
162 EXPECT_EQ("hostname", stun_servers_.begin()->hostname());
163 EXPECT_EQ(3478, stun_servers_.begin()->port());
164
165 // Both TURN IP and host exist
166 EXPECT_TRUE(
167 ParseUrl("turn:1.2.3.4:1234", "username", "password",
168 PeerConnectionInterface::TlsCertPolicy::kTlsCertPolicySecure,
169 "hostname"));
170 EXPECT_EQ(1U, turn_servers_.size());
171 rtc::SocketAddress address = turn_servers_[0].ports[0].address;
172 EXPECT_EQ("hostname", address.hostname());
173 EXPECT_EQ(1234, address.port());
174 EXPECT_FALSE(address.IsUnresolvedIP());
175 EXPECT_EQ("1.2.3.4", address.ipaddr().ToString());
176
177 // Try some invalid hostname:port strings.
178 EXPECT_FALSE(ParseUrl("stun:hostname:99a99"));
179 EXPECT_FALSE(ParseUrl("stun:hostname:-1"));
180 EXPECT_FALSE(ParseUrl("stun:hostname:port:more"));
181 EXPECT_FALSE(ParseUrl("stun:hostname:port more"));
182 EXPECT_FALSE(ParseUrl("stun:hostname:"));
183 EXPECT_FALSE(ParseUrl("stun:[1:2:3:4:5:6:7:8]junk:1000"));
184 EXPECT_FALSE(ParseUrl("stun::5555"));
185 EXPECT_FALSE(ParseUrl("stun:"));
186 // Test illegal URLs according to RFC 3986 (URI generic syntax)
187 // and RFC 7064 (URI schemes for STUN and TURN)
188 EXPECT_FALSE(ParseUrl("stun:/hostname")); // / is not allowed
189 EXPECT_FALSE(ParseUrl("stun:?hostname")); // ? is not allowed
190 EXPECT_FALSE(ParseUrl("stun:#hostname")); // # is not allowed
191 }
192
193 // Test parsing the "?transport=xxx" part of the URL.
TEST_F(IceServerParsingTest,ParseTransport)194 TEST_F(IceServerParsingTest, ParseTransport) {
195 EXPECT_TRUE(ParseTurnUrl("turn:hostname:1234?transport=tcp"));
196 EXPECT_EQ(1U, turn_servers_.size());
197 EXPECT_EQ(cricket::PROTO_TCP, turn_servers_[0].ports[0].proto);
198
199 EXPECT_TRUE(ParseTurnUrl("turn:hostname?transport=udp"));
200 EXPECT_EQ(1U, turn_servers_.size());
201 EXPECT_EQ(cricket::PROTO_UDP, turn_servers_[0].ports[0].proto);
202
203 EXPECT_FALSE(ParseTurnUrl("turn:hostname?transport=invalid"));
204 EXPECT_FALSE(ParseTurnUrl("turn:hostname?transport="));
205 EXPECT_FALSE(ParseTurnUrl("turn:hostname?="));
206 EXPECT_FALSE(ParseTurnUrl("turn:hostname?"));
207 EXPECT_FALSE(ParseTurnUrl("?"));
208 }
209
210 // Reject pre-RFC 7065 syntax with ICE username contained in URL.
TEST_F(IceServerParsingTest,ParseRejectsUsername)211 TEST_F(IceServerParsingTest, ParseRejectsUsername) {
212 EXPECT_FALSE(ParseTurnUrl("turn:user@hostname"));
213 }
214
215 // Test that username and password from IceServer is copied into the resulting
216 // RelayServerConfig.
TEST_F(IceServerParsingTest,CopyUsernameAndPasswordFromIceServer)217 TEST_F(IceServerParsingTest, CopyUsernameAndPasswordFromIceServer) {
218 EXPECT_TRUE(ParseUrl("turn:hostname", "username", "password"));
219 EXPECT_EQ(1U, turn_servers_.size());
220 EXPECT_EQ("username", turn_servers_[0].credentials.username);
221 EXPECT_EQ("password", turn_servers_[0].credentials.password);
222 }
223
224 // Ensure that if a server has multiple URLs, each one is parsed.
TEST_F(IceServerParsingTest,ParseMultipleUrls)225 TEST_F(IceServerParsingTest, ParseMultipleUrls) {
226 PeerConnectionInterface::IceServers servers;
227 PeerConnectionInterface::IceServer server;
228 server.urls.push_back("stun:hostname");
229 server.urls.push_back("turn:hostname");
230 server.username = "foo";
231 server.password = "bar";
232 servers.push_back(server);
233 EXPECT_TRUE(
234 webrtc::ParseIceServersOrError(servers, &stun_servers_, &turn_servers_)
235 .ok());
236 EXPECT_EQ(1U, stun_servers_.size());
237 EXPECT_EQ(1U, turn_servers_.size());
238 }
239
240 } // namespace webrtc
241