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