1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <Ice/NetworkProxy.h>
6 #include <Ice/HttpParser.h>
7 #include <Ice/LocalException.h>
8 #include <Ice/Properties.h>
9
10 using namespace std;
11 using namespace IceInternal;
12
upCast(NetworkProxy * p)13 IceUtil::Shared* IceInternal::upCast(NetworkProxy* p) { return p; }
14
~NetworkProxy()15 NetworkProxy::~NetworkProxy()
16 {
17 // Out of line to avoid weak vtable
18 }
19
20 #ifndef ICE_OS_UWP
21
22 namespace
23 {
24
25 class SOCKSNetworkProxy : public NetworkProxy
26 {
27 public:
28
29 SOCKSNetworkProxy(const string&, int);
30 SOCKSNetworkProxy(const Address&);
31
32 virtual void beginWrite(const Address&, Buffer&);
33 virtual SocketOperation endWrite(Buffer&);
34 virtual void beginRead(Buffer&);
35 virtual SocketOperation endRead(Buffer&);
36 virtual void finish(Buffer&, Buffer&);
37 virtual NetworkProxyPtr resolveHost(ProtocolSupport) const;
38 virtual Address getAddress() const;
39 virtual string getName() const;
40 virtual ProtocolSupport getProtocolSupport() const;
41
42 private:
43
44 string _host;
45 int _port;
46 Address _address;
47 };
48
49 class HTTPNetworkProxy : public NetworkProxy
50 {
51 public:
52
53 HTTPNetworkProxy(const string&, int);
54 HTTPNetworkProxy(const Address&, ProtocolSupport);
55
56 virtual void beginWrite(const Address&, Buffer&);
57 virtual SocketOperation endWrite(Buffer&);
58 virtual void beginRead(Buffer&);
59 virtual SocketOperation endRead(Buffer&);
60 virtual void finish(Buffer&, Buffer&);
61 virtual NetworkProxyPtr resolveHost(ProtocolSupport) const;
62 virtual Address getAddress() const;
63 virtual string getName() const;
64 virtual ProtocolSupport getProtocolSupport() const;
65
66 private:
67
68 string _host;
69 int _port;
70 Address _address;
71 ProtocolSupport _protocol;
72 };
73
74 }
75
SOCKSNetworkProxy(const string & host,int port)76 SOCKSNetworkProxy::SOCKSNetworkProxy(const string& host, int port) : _host(host), _port(port)
77 {
78 assert(!host.empty());
79 }
80
SOCKSNetworkProxy(const Address & addr)81 SOCKSNetworkProxy::SOCKSNetworkProxy(const Address& addr) : _port(0), _address(addr)
82 {
83 }
84
85 void
beginWrite(const Address & addr,Buffer & buf)86 SOCKSNetworkProxy::beginWrite(const Address& addr, Buffer& buf)
87 {
88 //
89 // SOCKS connect request
90 //
91 buf.b.resize(9);
92 buf.i = buf.b.begin();
93 Ice::Byte* dest = &buf.b[0];
94 *dest++ = 0x04; // SOCKS version 4.
95 *dest++ = 0x01; // Command, establish a TCP/IP stream connection
96
97 const Ice::Byte* src;
98
99 //
100 // Port (already in big-endian order)
101 //
102 src = reinterpret_cast<const Ice::Byte*>(&addr.saIn.sin_port);
103 *dest++ = *src++;
104 *dest++ = *src;
105
106 //
107 // IPv4 address (already in big-endian order)
108 //
109 src = reinterpret_cast<const Ice::Byte*>(&addr.saIn.sin_addr.s_addr);
110 *dest++ = *src++;
111 *dest++ = *src++;
112 *dest++ = *src++;
113 *dest++ = *src;
114
115 *dest = 0x00; // User ID.
116 }
117
118 SocketOperation
endWrite(Buffer & buf)119 SOCKSNetworkProxy::endWrite(Buffer& buf)
120 {
121 // Once the request is sent, read the response
122 return buf.i != buf.b.end() ? SocketOperationWrite : SocketOperationRead;
123 }
124
125 void
beginRead(Buffer & buf)126 SOCKSNetworkProxy::beginRead(Buffer& buf)
127 {
128 //
129 // Read the SOCKS4 response whose size is 8 bytes.
130 //
131 buf.b.resize(8);
132 buf.i = buf.b.begin();
133 }
134
135 SocketOperation
endRead(Buffer & buf)136 SOCKSNetworkProxy::endRead(Buffer& buf)
137 {
138 // We're done once we read the response
139 return buf.i != buf.b.end() ? SocketOperationRead : SocketOperationNone;
140 }
141
142 void
finish(Buffer & readBuffer,Buffer &)143 SOCKSNetworkProxy::finish(Buffer& readBuffer, Buffer&)
144 {
145 readBuffer.i = readBuffer.b.begin();
146
147 if(readBuffer.b.end() - readBuffer.i < 2)
148 {
149 throw Ice::UnmarshalOutOfBoundsException(__FILE__, __LINE__);
150 }
151
152 const Ice::Byte* src = &(*readBuffer.i);
153 const Ice::Byte b1 = *src++;
154 const Ice::Byte b2 = *src++;
155 if(b1 != 0x00 || b2 != 0x5a)
156 {
157 throw Ice::ConnectFailedException(__FILE__, __LINE__);
158 }
159 }
160
161 NetworkProxyPtr
resolveHost(ProtocolSupport protocol) const162 SOCKSNetworkProxy::resolveHost(ProtocolSupport protocol) const
163 {
164 assert(!_host.empty());
165 return new SOCKSNetworkProxy(getAddresses(_host, _port, protocol, Ice::ICE_ENUM(EndpointSelectionType, Random), false, true)[0]);
166 }
167
168 Address
getAddress() const169 SOCKSNetworkProxy::getAddress() const
170 {
171 assert(_host.empty()); // Host must be resolved.
172 return _address;
173 }
174
175 string
getName() const176 SOCKSNetworkProxy::getName() const
177 {
178 return "SOCKS";
179 }
180
181 ProtocolSupport
getProtocolSupport() const182 SOCKSNetworkProxy::getProtocolSupport() const
183 {
184 return EnableIPv4;
185 }
186
HTTPNetworkProxy(const string & host,int port)187 HTTPNetworkProxy::HTTPNetworkProxy(const string& host, int port) :
188 _host(host), _port(port), _protocol(EnableBoth)
189 {
190 assert(!host.empty());
191 }
192
HTTPNetworkProxy(const Address & addr,ProtocolSupport protocol)193 HTTPNetworkProxy::HTTPNetworkProxy(const Address& addr, ProtocolSupport protocol) :
194 _port(0), _address(addr), _protocol(protocol)
195 {
196 }
197
198 void
beginWrite(const Address & addr,Buffer & buf)199 HTTPNetworkProxy::beginWrite(const Address& addr, Buffer& buf)
200 {
201 //
202 // HTTP connect request
203 //
204 ostringstream out;
205 out << "CONNECT " << addrToString(addr) << " HTTP/1.1\r\n" << "Host: " << addrToString(addr) << "\r\n\r\n";
206 string str = out.str();
207 buf.b.resize(str.size());
208 memcpy(&buf.b[0], str.c_str(), str.size());
209 buf.i = buf.b.begin();
210 }
211
212 SocketOperation
endWrite(Buffer & buf)213 HTTPNetworkProxy::endWrite(Buffer& buf)
214 {
215 // Once the request is sent, read the response
216 return buf.i != buf.b.end() ? SocketOperationWrite : SocketOperationRead;
217 }
218
219 void
beginRead(Buffer & buf)220 HTTPNetworkProxy::beginRead(Buffer& buf)
221 {
222 //
223 // Read the Http response
224 //
225 buf.b.resize(7); // Enough space for reading at least HTTP1.1
226 buf.i = buf.b.begin();
227 }
228
229 SocketOperation
endRead(Buffer & buf)230 HTTPNetworkProxy::endRead(Buffer& buf)
231 {
232 //
233 // Check if we received the full HTTP response, if not, continue
234 // reading otherwise we're done.
235 //
236 const Ice::Byte* end = HttpParser().isCompleteMessage(buf.b.begin(), buf.i);
237 if(!end && buf.i == buf.b.end())
238 {
239 //
240 // Read one more byte, we can't easily read bytes in advance
241 // since the transport implenentation might be be able to read
242 // the data from the memory instead of the socket. This is for
243 // instance the case with the OpenSSL transport (or we would
244 // have to use a buffering BIO).
245 //
246 buf.b.resize(buf.b.size() + 1);
247 buf.i = buf.b.begin() + buf.b.size() - 1;
248 return SocketOperationRead;
249 }
250 return SocketOperationNone;
251 }
252
253 void
finish(Buffer & readBuffer,Buffer &)254 HTTPNetworkProxy::finish(Buffer& readBuffer, Buffer&)
255 {
256 HttpParser parser;
257 parser.parse(readBuffer.b.begin(), readBuffer.b.end());
258 if(parser.status() != 200)
259 {
260 throw Ice::ConnectFailedException(__FILE__, __LINE__);
261 }
262 }
263
264 NetworkProxyPtr
resolveHost(ProtocolSupport protocol) const265 HTTPNetworkProxy::resolveHost(ProtocolSupport protocol) const
266 {
267 assert(!_host.empty());
268 return new HTTPNetworkProxy(getAddresses(_host, _port, protocol, Ice::ICE_ENUM(EndpointSelectionType, Random), false, true)[0], protocol);
269 }
270
271 Address
getAddress() const272 HTTPNetworkProxy::getAddress() const
273 {
274 assert(_host.empty()); // Host must be resolved.
275 return _address;
276 }
277
278 string
getName() const279 HTTPNetworkProxy::getName() const
280 {
281 return "HTTP";
282 }
283
284 ProtocolSupport
getProtocolSupport() const285 HTTPNetworkProxy::getProtocolSupport() const
286 {
287 return _protocol;
288 }
289
290 #endif
291
292 NetworkProxyPtr
createNetworkProxy(const Ice::PropertiesPtr & properties,ProtocolSupport protocolSupport)293 IceInternal::createNetworkProxy(const Ice::PropertiesPtr& properties, ProtocolSupport protocolSupport)
294 {
295 string proxyHost;
296
297 proxyHost = properties->getProperty("Ice.SOCKSProxyHost");
298 if(!proxyHost.empty())
299 {
300 #ifdef ICE_OS_UWP
301 UNREFERENCED_PARAMETER(protocolSupport);
302 throw Ice::InitializationException(__FILE__, __LINE__, "SOCKS proxy not supported with UWP");
303 #else
304 if(protocolSupport == EnableIPv6)
305 {
306 throw Ice::InitializationException(__FILE__, __LINE__, "IPv6 only is not supported with SOCKS4 proxies");
307 }
308 int proxyPort = properties->getPropertyAsIntWithDefault("Ice.SOCKSProxyPort", 1080);
309 return new SOCKSNetworkProxy(proxyHost, proxyPort);
310 #endif
311 }
312
313 proxyHost = properties->getProperty("Ice.HTTPProxyHost");
314 if(!proxyHost.empty())
315 {
316 #ifdef ICE_OS_UWP
317 throw Ice::InitializationException(__FILE__, __LINE__, "HTTP proxy not supported with UWP");
318 #else
319 return new HTTPNetworkProxy(proxyHost, properties->getPropertyAsIntWithDefault("Ice.HTTPProxyPort", 1080));
320 #endif
321 }
322
323 return 0;
324 }
325