• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2004 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 "webrtc/base/autodetectproxy.h"
12 #include "webrtc/base/httpcommon.h"
13 #include "webrtc/base/httpcommon-inl.h"
14 #include "webrtc/base/nethelpers.h"
15 
16 namespace rtc {
17 
18 static const ProxyType TEST_ORDER[] = {
19   PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN
20 };
21 
22 static const int kSavedStringLimit = 128;
23 
SaveStringToStack(char * dst,const std::string & src,size_t dst_size)24 static void SaveStringToStack(char *dst,
25                               const std::string &src,
26                               size_t dst_size) {
27   strncpy(dst, src.c_str(), dst_size - 1);
28   dst[dst_size - 1] = '\0';
29 }
30 
AutoDetectProxy(const std::string & user_agent)31 AutoDetectProxy::AutoDetectProxy(const std::string& user_agent)
32     : agent_(user_agent), resolver_(NULL), socket_(NULL), next_(0) {
33 }
34 
~AutoDetectProxy()35 AutoDetectProxy::~AutoDetectProxy() {
36   if (resolver_) {
37     resolver_->Destroy(false);
38   }
39 }
40 
DoWork()41 void AutoDetectProxy::DoWork() {
42   // TODO: Try connecting to server_url without proxy first here?
43   if (!server_url_.empty()) {
44     LOG(LS_INFO) << "GetProxySettingsForUrl(" << server_url_ << ") - start";
45     GetProxyForUrl(agent_.c_str(), server_url_.c_str(), &proxy_);
46     LOG(LS_INFO) << "GetProxySettingsForUrl - stop";
47   }
48   Url<char> url(proxy_.address.HostAsURIString());
49   if (url.valid()) {
50     LOG(LS_WARNING) << "AutoDetectProxy removing http prefix on proxy host";
51     proxy_.address.SetIP(url.host());
52   }
53   LOG(LS_INFO) << "AutoDetectProxy found proxy at " << proxy_.address;
54   if (proxy_.type == PROXY_UNKNOWN) {
55     LOG(LS_INFO) << "AutoDetectProxy initiating proxy classification";
56     Next();
57     // Process I/O until Stop()
58     Thread::Current()->ProcessMessages(kForever);
59     // Clean up the autodetect socket, from the thread that created it
60     delete socket_;
61   }
62   // TODO: If we found a proxy, try to use it to verify that it
63   // works by sending a request to server_url. This could either be
64   // done here or by the HttpPortAllocator.
65 }
66 
OnMessage(Message * msg)67 void AutoDetectProxy::OnMessage(Message *msg) {
68   if (MSG_UNRESOLVABLE == msg->message_id) {
69     // If we can't resolve the proxy, skip straight to failure.
70     Complete(PROXY_UNKNOWN);
71   } else if (MSG_TIMEOUT == msg->message_id) {
72     OnCloseEvent(socket_, ETIMEDOUT);
73   } else {
74     // This must be the ST_MSG_WORKER_DONE message that deletes the
75     // AutoDetectProxy object. We have observed crashes within this stack that
76     // seem to be highly reproducible for a small subset of users and thus are
77     // probably correlated with a specific proxy setting, so copy potentially
78     // relevant information onto the stack to make it available in Windows
79     // minidumps.
80 
81     // Save the user agent and the number of auto-detection passes that we
82     // needed.
83     char agent[kSavedStringLimit];
84     SaveStringToStack(agent, agent_, sizeof agent);
85 
86     int next = next_;
87 
88     // Now the detected proxy config (minus the password field, which could be
89     // sensitive).
90     ProxyType type = proxy().type;
91 
92     char address_hostname[kSavedStringLimit];
93     SaveStringToStack(address_hostname,
94                       proxy().address.hostname(),
95                       sizeof address_hostname);
96 
97     IPAddress address_ip = proxy().address.ipaddr();
98 
99     uint16 address_port = proxy().address.port();
100 
101     char autoconfig_url[kSavedStringLimit];
102     SaveStringToStack(autoconfig_url,
103                       proxy().autoconfig_url,
104                       sizeof autoconfig_url);
105 
106     bool autodetect = proxy().autodetect;
107 
108     char bypass_list[kSavedStringLimit];
109     SaveStringToStack(bypass_list, proxy().bypass_list, sizeof bypass_list);
110 
111     char username[kSavedStringLimit];
112     SaveStringToStack(username, proxy().username, sizeof username);
113 
114     SignalThread::OnMessage(msg);
115 
116     // Log the gathered data at a log level that will never actually be enabled
117     // so that the compiler is forced to retain the data on the stack.
118     LOG(LS_SENSITIVE) << agent << " " << next << " " << type << " "
119                       << address_hostname << " " << address_ip << " "
120                       << address_port << " " << autoconfig_url << " "
121                       << autodetect << " " << bypass_list << " " << username;
122   }
123 }
124 
OnResolveResult(AsyncResolverInterface * resolver)125 void AutoDetectProxy::OnResolveResult(AsyncResolverInterface* resolver) {
126   if (resolver != resolver_) {
127     return;
128   }
129   int error = resolver_->GetError();
130   if (error == 0) {
131     LOG(LS_VERBOSE) << "Resolved " << proxy_.address << " to "
132                     << resolver_->address();
133     proxy_.address = resolver_->address();
134     if (!DoConnect()) {
135       Thread::Current()->Post(this, MSG_TIMEOUT);
136     }
137   } else {
138     LOG(LS_INFO) << "Failed to resolve " << resolver_->address();
139     resolver_->Destroy(false);
140     resolver_ = NULL;
141     proxy_.address = SocketAddress();
142     Thread::Current()->Post(this, MSG_UNRESOLVABLE);
143   }
144 }
145 
Next()146 void AutoDetectProxy::Next() {
147   if (TEST_ORDER[next_] >= PROXY_UNKNOWN) {
148     Complete(PROXY_UNKNOWN);
149     return;
150   }
151 
152   LOG(LS_VERBOSE) << "AutoDetectProxy connecting to "
153                   << proxy_.address.ToSensitiveString();
154 
155   if (socket_) {
156     Thread::Current()->Clear(this, MSG_TIMEOUT);
157     Thread::Current()->Clear(this, MSG_UNRESOLVABLE);
158     socket_->Close();
159     Thread::Current()->Dispose(socket_);
160     socket_ = NULL;
161   }
162   int timeout = 2000;
163   if (proxy_.address.IsUnresolvedIP()) {
164     // Launch an asyncresolver. This thread will spin waiting for it.
165     timeout += 2000;
166     if (!resolver_) {
167       resolver_ = new AsyncResolver();
168     }
169     resolver_->SignalDone.connect(this, &AutoDetectProxy::OnResolveResult);
170     resolver_->Start(proxy_.address);
171   } else {
172     if (!DoConnect()) {
173       Thread::Current()->Post(this, MSG_TIMEOUT);
174       return;
175     }
176   }
177   Thread::Current()->PostDelayed(timeout, this, MSG_TIMEOUT);
178 }
179 
DoConnect()180 bool AutoDetectProxy::DoConnect() {
181   if (resolver_) {
182     resolver_->Destroy(false);
183     resolver_ = NULL;
184   }
185   socket_ =
186       Thread::Current()->socketserver()->CreateAsyncSocket(
187           proxy_.address.family(), SOCK_STREAM);
188   if (!socket_) {
189     LOG(LS_VERBOSE) << "Unable to create socket for " << proxy_.address;
190     return false;
191   }
192   socket_->SignalConnectEvent.connect(this, &AutoDetectProxy::OnConnectEvent);
193   socket_->SignalReadEvent.connect(this, &AutoDetectProxy::OnReadEvent);
194   socket_->SignalCloseEvent.connect(this, &AutoDetectProxy::OnCloseEvent);
195   socket_->Connect(proxy_.address);
196   return true;
197 }
198 
Complete(ProxyType type)199 void AutoDetectProxy::Complete(ProxyType type) {
200   Thread::Current()->Clear(this, MSG_TIMEOUT);
201   Thread::Current()->Clear(this, MSG_UNRESOLVABLE);
202   if (socket_) {
203     socket_->Close();
204   }
205 
206   proxy_.type = type;
207   LoggingSeverity sev = (proxy_.type == PROXY_UNKNOWN) ? LS_ERROR : LS_INFO;
208   LOG_V(sev) << "AutoDetectProxy detected "
209              << proxy_.address.ToSensitiveString()
210              << " as type " << proxy_.type;
211 
212   Thread::Current()->Quit();
213 }
214 
OnConnectEvent(AsyncSocket * socket)215 void AutoDetectProxy::OnConnectEvent(AsyncSocket * socket) {
216   std::string probe;
217 
218   switch (TEST_ORDER[next_]) {
219     case PROXY_HTTPS:
220       probe.assign("CONNECT www.google.com:443 HTTP/1.0\r\n"
221                    "User-Agent: ");
222       probe.append(agent_);
223       probe.append("\r\n"
224                    "Host: www.google.com\r\n"
225                    "Content-Length: 0\r\n"
226                    "Proxy-Connection: Keep-Alive\r\n"
227                    "\r\n");
228       break;
229     case PROXY_SOCKS5:
230       probe.assign("\005\001\000", 3);
231       break;
232     default:
233       ASSERT(false);
234       return;
235   }
236 
237   LOG(LS_VERBOSE) << "AutoDetectProxy probing type " << TEST_ORDER[next_]
238                   << " sending " << probe.size() << " bytes";
239   socket_->Send(probe.data(), probe.size());
240 }
241 
OnReadEvent(AsyncSocket * socket)242 void AutoDetectProxy::OnReadEvent(AsyncSocket * socket) {
243   char data[257];
244   int len = socket_->Recv(data, 256);
245   if (len > 0) {
246     data[len] = 0;
247     LOG(LS_VERBOSE) << "AutoDetectProxy read " << len << " bytes";
248   }
249 
250   switch (TEST_ORDER[next_]) {
251     case PROXY_HTTPS:
252       if ((len >= 2) && (data[0] == '\x05')) {
253         Complete(PROXY_SOCKS5);
254         return;
255       }
256       if ((len >= 5) && (strncmp(data, "HTTP/", 5) == 0)) {
257         Complete(PROXY_HTTPS);
258         return;
259       }
260       break;
261     case PROXY_SOCKS5:
262       if ((len >= 2) && (data[0] == '\x05')) {
263         Complete(PROXY_SOCKS5);
264         return;
265       }
266       break;
267     default:
268       ASSERT(false);
269       return;
270   }
271 
272   ++next_;
273   Next();
274 }
275 
OnCloseEvent(AsyncSocket * socket,int error)276 void AutoDetectProxy::OnCloseEvent(AsyncSocket * socket, int error) {
277   LOG(LS_VERBOSE) << "AutoDetectProxy closed with error: " << error;
278   ++next_;
279   Next();
280 }
281 
282 }  // namespace rtc
283