1 /*
2  *  Copyright 2011 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 "p2p/base/basic_packet_socket_factory.h"
12 
13 #include <stddef.h>
14 
15 #include <string>
16 
17 #include "p2p/base/async_stun_tcp_socket.h"
18 #include "rtc_base/async_tcp_socket.h"
19 #include "rtc_base/async_udp_socket.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/logging.h"
22 #include "rtc_base/net_helpers.h"
23 #include "rtc_base/socket.h"
24 #include "rtc_base/socket_adapters.h"
25 #include "rtc_base/socket_server.h"
26 #include "rtc_base/ssl_adapter.h"
27 #include "rtc_base/thread.h"
28 
29 namespace rtc {
30 
BasicPacketSocketFactory()31 BasicPacketSocketFactory::BasicPacketSocketFactory()
32     : thread_(Thread::Current()), socket_factory_(NULL) {}
33 
BasicPacketSocketFactory(Thread * thread)34 BasicPacketSocketFactory::BasicPacketSocketFactory(Thread* thread)
35     : thread_(thread), socket_factory_(NULL) {}
36 
BasicPacketSocketFactory(SocketFactory * socket_factory)37 BasicPacketSocketFactory::BasicPacketSocketFactory(
38     SocketFactory* socket_factory)
39     : thread_(NULL), socket_factory_(socket_factory) {}
40 
~BasicPacketSocketFactory()41 BasicPacketSocketFactory::~BasicPacketSocketFactory() {}
42 
CreateUdpSocket(const SocketAddress & address,uint16_t min_port,uint16_t max_port)43 AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket(
44     const SocketAddress& address,
45     uint16_t min_port,
46     uint16_t max_port) {
47   // UDP sockets are simple.
48   AsyncSocket* socket =
49       socket_factory()->CreateAsyncSocket(address.family(), SOCK_DGRAM);
50   if (!socket) {
51     return NULL;
52   }
53   if (BindSocket(socket, address, min_port, max_port) < 0) {
54     RTC_LOG(LS_ERROR) << "UDP bind failed with error " << socket->GetError();
55     delete socket;
56     return NULL;
57   }
58   return new AsyncUDPSocket(socket);
59 }
60 
CreateServerTcpSocket(const SocketAddress & local_address,uint16_t min_port,uint16_t max_port,int opts)61 AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket(
62     const SocketAddress& local_address,
63     uint16_t min_port,
64     uint16_t max_port,
65     int opts) {
66   // Fail if TLS is required.
67   if (opts & PacketSocketFactory::OPT_TLS) {
68     RTC_LOG(LS_ERROR) << "TLS support currently is not available.";
69     return NULL;
70   }
71 
72   AsyncSocket* socket =
73       socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM);
74   if (!socket) {
75     return NULL;
76   }
77 
78   if (BindSocket(socket, local_address, min_port, max_port) < 0) {
79     RTC_LOG(LS_ERROR) << "TCP bind failed with error " << socket->GetError();
80     delete socket;
81     return NULL;
82   }
83 
84   // If using fake TLS, wrap the TCP socket in a pseudo-SSL socket.
85   if (opts & PacketSocketFactory::OPT_TLS_FAKE) {
86     RTC_DCHECK(!(opts & PacketSocketFactory::OPT_TLS));
87     socket = new AsyncSSLSocket(socket);
88   }
89 
90   // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
91   // See http://go/gtalktcpnodelayexperiment
92   socket->SetOption(Socket::OPT_NODELAY, 1);
93 
94   if (opts & PacketSocketFactory::OPT_STUN)
95     return new cricket::AsyncStunTCPSocket(socket, true);
96 
97   return new AsyncTCPSocket(socket, true);
98 }
99 
CreateClientTcpSocket(const SocketAddress & local_address,const SocketAddress & remote_address,const ProxyInfo & proxy_info,const std::string & user_agent,const PacketSocketTcpOptions & tcp_options)100 AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
101     const SocketAddress& local_address,
102     const SocketAddress& remote_address,
103     const ProxyInfo& proxy_info,
104     const std::string& user_agent,
105     const PacketSocketTcpOptions& tcp_options) {
106   AsyncSocket* socket =
107       socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM);
108   if (!socket) {
109     return NULL;
110   }
111 
112   if (BindSocket(socket, local_address, 0, 0) < 0) {
113     // Allow BindSocket to fail if we're binding to the ANY address, since this
114     // is mostly redundant in the first place. The socket will be bound when we
115     // call Connect() instead.
116     if (local_address.IsAnyIP()) {
117       RTC_LOG(LS_WARNING) << "TCP bind failed with error " << socket->GetError()
118                           << "; ignoring since socket is using 'any' address.";
119     } else {
120       RTC_LOG(LS_ERROR) << "TCP bind failed with error " << socket->GetError();
121       delete socket;
122       return NULL;
123     }
124   }
125 
126   // If using a proxy, wrap the socket in a proxy socket.
127   if (proxy_info.type == PROXY_SOCKS5) {
128     socket = new AsyncSocksProxySocket(
129         socket, proxy_info.address, proxy_info.username, proxy_info.password);
130   } else if (proxy_info.type == PROXY_HTTPS) {
131     socket =
132         new AsyncHttpsProxySocket(socket, user_agent, proxy_info.address,
133                                   proxy_info.username, proxy_info.password);
134   }
135 
136   // Assert that at most one TLS option is used.
137   int tlsOpts = tcp_options.opts & (PacketSocketFactory::OPT_TLS |
138                                     PacketSocketFactory::OPT_TLS_FAKE |
139                                     PacketSocketFactory::OPT_TLS_INSECURE);
140   RTC_DCHECK((tlsOpts & (tlsOpts - 1)) == 0);
141 
142   if ((tlsOpts & PacketSocketFactory::OPT_TLS) ||
143       (tlsOpts & PacketSocketFactory::OPT_TLS_INSECURE)) {
144     // Using TLS, wrap the socket in an SSL adapter.
145     SSLAdapter* ssl_adapter = SSLAdapter::Create(socket);
146     if (!ssl_adapter) {
147       return NULL;
148     }
149 
150     if (tlsOpts & PacketSocketFactory::OPT_TLS_INSECURE) {
151       ssl_adapter->SetIgnoreBadCert(true);
152     }
153 
154     ssl_adapter->SetAlpnProtocols(tcp_options.tls_alpn_protocols);
155     ssl_adapter->SetEllipticCurves(tcp_options.tls_elliptic_curves);
156     ssl_adapter->SetCertVerifier(tcp_options.tls_cert_verifier);
157 
158     socket = ssl_adapter;
159 
160     if (ssl_adapter->StartSSL(remote_address.hostname().c_str()) != 0) {
161       delete ssl_adapter;
162       return NULL;
163     }
164 
165   } else if (tlsOpts & PacketSocketFactory::OPT_TLS_FAKE) {
166     // Using fake TLS, wrap the TCP socket in a pseudo-SSL socket.
167     socket = new AsyncSSLSocket(socket);
168   }
169 
170   if (socket->Connect(remote_address) < 0) {
171     RTC_LOG(LS_ERROR) << "TCP connect failed with error " << socket->GetError();
172     delete socket;
173     return NULL;
174   }
175 
176   // Finally, wrap that socket in a TCP or STUN TCP packet socket.
177   AsyncPacketSocket* tcp_socket;
178   if (tcp_options.opts & PacketSocketFactory::OPT_STUN) {
179     tcp_socket = new cricket::AsyncStunTCPSocket(socket, false);
180   } else {
181     tcp_socket = new AsyncTCPSocket(socket, false);
182   }
183 
184   // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
185   // See http://go/gtalktcpnodelayexperiment
186   tcp_socket->SetOption(Socket::OPT_NODELAY, 1);
187 
188   return tcp_socket;
189 }
190 
CreateAsyncResolver()191 AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() {
192   return new AsyncResolver();
193 }
194 
BindSocket(AsyncSocket * socket,const SocketAddress & local_address,uint16_t min_port,uint16_t max_port)195 int BasicPacketSocketFactory::BindSocket(AsyncSocket* socket,
196                                          const SocketAddress& local_address,
197                                          uint16_t min_port,
198                                          uint16_t max_port) {
199   int ret = -1;
200   if (min_port == 0 && max_port == 0) {
201     // If there's no port range, let the OS pick a port for us.
202     ret = socket->Bind(local_address);
203   } else {
204     // Otherwise, try to find a port in the provided range.
205     for (int port = min_port; ret < 0 && port <= max_port; ++port) {
206       ret = socket->Bind(SocketAddress(local_address.ipaddr(), port));
207     }
208   }
209   return ret;
210 }
211 
socket_factory()212 SocketFactory* BasicPacketSocketFactory::socket_factory() {
213   if (thread_) {
214     RTC_DCHECK(thread_ == Thread::Current());
215     return thread_->socketserver();
216   } else {
217     return socket_factory_;
218   }
219 }
220 
221 }  // namespace rtc
222