aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmessage
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llmessage')
-rw-r--r--linden/indra/llmessage/CMakeLists.txt2
-rw-r--r--linden/indra/llmessage/llcurl.cpp40
-rw-r--r--linden/indra/llmessage/llpacketring.cpp56
-rw-r--r--linden/indra/llmessage/llpacketring.h3
-rw-r--r--linden/indra/llmessage/llsocks5.cpp210
-rw-r--r--linden/indra/llmessage/llsocks5.h248
-rw-r--r--linden/indra/llmessage/message.cpp8
-rw-r--r--linden/indra/llmessage/message.h14
-rw-r--r--linden/indra/llmessage/net.cpp158
-rw-r--r--linden/indra/llmessage/net.h3
10 files changed, 731 insertions, 11 deletions
diff --git a/linden/indra/llmessage/CMakeLists.txt b/linden/indra/llmessage/CMakeLists.txt
index 9965191..b3f2b4c 100644
--- a/linden/indra/llmessage/CMakeLists.txt
+++ b/linden/indra/llmessage/CMakeLists.txt
@@ -98,6 +98,7 @@ set(llmessage_SOURCE_FILES
98 patch_code.cpp 98 patch_code.cpp
99 patch_dct.cpp 99 patch_dct.cpp
100 patch_idct.cpp 100 patch_idct.cpp
101 llsocks5.cpp
101 sound_ids.cpp 102 sound_ids.cpp
102 ) 103 )
103 104
@@ -198,6 +199,7 @@ set(llmessage_HEADER_FILES
198 patch_code.h 199 patch_code.h
199 patch_dct.h 200 patch_dct.h
200 sound_ids.h 201 sound_ids.h
202 llsocks5.h
201 ) 203 )
202 204
203set_source_files_properties(${llmessage_HEADER_FILES} 205set_source_files_properties(${llmessage_HEADER_FILES}
diff --git a/linden/indra/llmessage/llcurl.cpp b/linden/indra/llmessage/llcurl.cpp
index 9ecfee4..b23ef33 100644
--- a/linden/indra/llmessage/llcurl.cpp
+++ b/linden/indra/llmessage/llcurl.cpp
@@ -56,6 +56,8 @@
56#include "llsdserialize.h" 56#include "llsdserialize.h"
57#include "llthread.h" 57#include "llthread.h"
58 58
59#include "llsocks5.h"
60
59////////////////////////////////////////////////////////////////////////////// 61//////////////////////////////////////////////////////////////////////////////
60/* 62/*
61 The trick to getting curl to do keep-alives is to reuse the 63 The trick to getting curl to do keep-alives is to reuse the
@@ -270,6 +272,25 @@ LLCurl::Easy* LLCurl::Easy::getEasy()
270 // set no DMS caching as default for all easy handles. This prevents them adopting a 272 // set no DMS caching as default for all easy handles. This prevents them adopting a
271 // multi handles cache if they are added to one. 273 // multi handles cache if they are added to one.
272 curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); 274 curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
275
276 if (LLSocks::getInstance()->isHttpProxyEnabled())
277 {
278 std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString();
279 U16 port = LLSocks::getInstance()->getHTTPProxy().getPort();
280 curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXY,address.c_str());
281 curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYPORT,port);
282 if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS)
283 {
284 curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
285 if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD)
286 curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd().c_str());
287 }
288 else
289 {
290 curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
291 }
292 }
293
273 ++gCurlEasyCount; 294 ++gCurlEasyCount;
274 return easy; 295 return easy;
275} 296}
@@ -443,6 +464,24 @@ void LLCurl::Easy::prepRequest(const std::string& url,
443// setopt(CURLOPT_VERBOSE, 1); // usefull for debugging 464// setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
444 setopt(CURLOPT_NOSIGNAL, 1); 465 setopt(CURLOPT_NOSIGNAL, 1);
445 466
467 if (LLSocks::getInstance()->isHttpProxyEnabled())
468 {
469 std::string address = LLSocks::getInstance()->getHTTPProxy().getIPString();
470 U16 port = LLSocks::getInstance()->getHTTPProxy().getPort();
471 setoptString(CURLOPT_PROXY, address.c_str());
472 setopt(CURLOPT_PROXYPORT, port);
473 if (LLSocks::getInstance()->getHttpProxyType() == LLPROXY_SOCKS)
474 {
475 setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
476 if(LLSocks::getInstance()->getSelectedAuthMethod()==METHOD_PASSWORD)
477 setoptString(CURLOPT_PROXYUSERPWD,LLSocks::getInstance()->getProxyUserPwd());
478 }
479 else
480 {
481 setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
482 }
483 }
484
446 mOutput.reset(new LLBufferArray); 485 mOutput.reset(new LLBufferArray);
447 setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback); 486 setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
448 setopt(CURLOPT_WRITEDATA, (void*)this); 487 setopt(CURLOPT_WRITEDATA, (void*)this);
@@ -742,6 +781,7 @@ bool LLCurlRequest::getByteRange(const std::string& url,
742 if (length > 0) 781 if (length > 0)
743 { 782 {
744 std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1); 783 std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1);
784 //llinfos << "http url: " << url << " " << range << llendl;
745 easy->slist_append(range.c_str()); 785 easy->slist_append(range.c_str());
746 } 786 }
747 easy->setHeaders(); 787 easy->setHeaders();
diff --git a/linden/indra/llmessage/llpacketring.cpp b/linden/indra/llmessage/llpacketring.cpp
index 7f9617f..e7dad79 100644
--- a/linden/indra/llmessage/llpacketring.cpp
+++ b/linden/indra/llmessage/llpacketring.cpp
@@ -43,6 +43,15 @@
43#include "llmessagelog.h" 43#include "llmessagelog.h"
44#include "message.h" 44#include "message.h"
45 45
46#include "llsocks5.h"
47
48#if LL_WINDOWS
49 #include <winsock2.h>
50#else
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53#endif
54
46/////////////////////////////////////////////////////////// 55///////////////////////////////////////////////////////////
47LLPacketRing::LLPacketRing () : 56LLPacketRing::LLPacketRing () :
48 mUseInThrottle(FALSE), 57 mUseInThrottle(FALSE),
@@ -224,8 +233,25 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)
224 else 233 else
225 { 234 {
226 // no delay, pull straight from net 235 // no delay, pull straight from net
227 packet_size = receive_packet(socket, datap); 236 if (LLSocks::isEnabled())
228 mLastSender = ::get_sender(); 237 {
238 proxywrap_t * header;
239 datap = datap-10;
240 header = (proxywrap_t *)datap;
241 packet_size = receive_packet(socket, datap);
242 mLastSender.setAddress(header->addr);
243 mLastSender.setPort(ntohs(header->port));
244 if (packet_size > 10)
245 {
246 packet_size -= 10;
247 }
248 }
249 else
250 {
251 packet_size = receive_packet(socket, datap);
252 mLastSender = ::get_sender();
253 }
254
229 mLastReceivingIF = ::get_receiving_interface(); 255 mLastReceivingIF = ::get_receiving_interface();
230 256
231 if (packet_size) // did we actually get a packet? 257 if (packet_size) // did we actually get a packet?
@@ -254,7 +280,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
254 BOOL status = TRUE; 280 BOOL status = TRUE;
255 if (!mUseOutThrottle) 281 if (!mUseOutThrottle)
256 { 282 {
257 return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() ); 283 return doSendPacket(h_socket, send_buffer, buf_size, host );
258 } 284 }
259 else 285 else
260 { 286 {
@@ -275,7 +301,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
275 mOutBufferLength -= packetp->getSize(); 301 mOutBufferLength -= packetp->getSize();
276 packet_size = packetp->getSize(); 302 packet_size = packetp->getSize();
277 303
278 status = send_packet(h_socket, packetp->getData(), packet_size, packetp->getHost().getAddress(), packetp->getHost().getPort()); 304 status = doSendPacket(h_socket, packetp->getData(), packet_size, packetp->getHost());
279 305
280 delete packetp; 306 delete packetp;
281 // Update the throttle 307 // Update the throttle
@@ -284,7 +310,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
284 else 310 else
285 { 311 {
286 // If the queue's empty, we can just send this packet right away. 312 // If the queue's empty, we can just send this packet right away.
287 status = send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() ); 313 status = doSendPacket(h_socket, send_buffer, buf_size, host );
288 packet_size = buf_size; 314 packet_size = buf_size;
289 315
290 // Update the throttle 316 // Update the throttle
@@ -322,3 +348,23 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
322 348
323 return status; 349 return status;
324} 350}
351
352BOOL LLPacketRing::doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
353{
354
355 if (!LLSocks::isEnabled())
356 {
357 return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
358 }
359
360 proxywrap_t *socks_header = (proxywrap_t *)&mProxyWrappedSendBuffer;
361 socks_header->rsv = 0;
362 socks_header->addr = host.getAddress();
363 socks_header->port = htons(host.getPort());
364 socks_header->atype = ADDRESS_IPV4;
365 socks_header->frag = 0;
366
367 memcpy(mProxyWrappedSendBuffer+10, send_buffer, buf_size);
368
369 return send_packet(h_socket,(const char*) mProxyWrappedSendBuffer, buf_size+10, LLSocks::getInstance()->getUDPPproxy().getAddress(), LLSocks::getInstance()->getUDPPproxy().getPort());
370}
diff --git a/linden/indra/llmessage/llpacketring.h b/linden/indra/llmessage/llpacketring.h
index 4408abe..5d2c246 100644
--- a/linden/indra/llmessage/llpacketring.h
+++ b/linden/indra/llmessage/llpacketring.h
@@ -88,6 +88,9 @@ protected:
88 88
89 LLHost mLastSender; 89 LLHost mLastSender;
90 LLHost mLastReceivingIF; 90 LLHost mLastReceivingIF;
91
92 BOOL doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
93 U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE];
91}; 94};
92 95
93 96
diff --git a/linden/indra/llmessage/llsocks5.cpp b/linden/indra/llmessage/llsocks5.cpp
new file mode 100644
index 0000000..7326e80
--- /dev/null
+++ b/linden/indra/llmessage/llsocks5.cpp
@@ -0,0 +1,210 @@
1/**
2 * @file llsocks5.cpp
3 * @brief Socks 5 implementation
4 *
5 * $LicenseInfo:firstyear=2000&license=viewergpl$
6 *
7 * Copyright (c) 2000-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include <string>
34
35#include "linden_common.h"
36#include "net.h"
37#include "llhost.h"
38#include "message.h"
39#include "llsocks5.h"
40
41// Static class variable instances
42
43// We want this to be static to avoid excessive indirection on every
44// incomming packet just to do a simple bool test. The getter for this
45// member is also static
46bool LLSocks::sUdpProxyEnabled;
47bool LLSocks::sHttpProxyEnabled;
48
49LLSocks::LLSocks()
50{
51 sUdpProxyEnabled = false;
52 sHttpProxyEnabled = false;
53 mNeedUpdate = false;
54}
55
56// Perform a Socks5 authentication and UDP assioacation to the proxy
57// specified by proxy, and assiocate UDP port message_port
58int LLSocks::proxyHandshake(LLHost proxy, U32 message_port)
59{
60 int result;
61
62 /* Socks 5 Auth request */
63 socks_auth_request_t socks_auth_request;
64 socks_auth_response_t socks_auth_response;
65
66 socks_auth_request.version = SOCKS_VERSION; // Socks version 5
67 socks_auth_request.num_methods = 1; // Sending 1 method
68 socks_auth_request.methods = mAuthMethodSelected; // send only the selected metho
69
70 result = tcp_handshake(hProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request_t), (char*)&socks_auth_response, sizeof(socks_auth_response_t));
71 if (result != 0)
72 {
73 llwarns << "Socks authentication request failed, error on TCP control channel : " << result << llendl;
74 stopProxy();
75 return SOCKS_CONNECT_ERROR;
76 }
77
78 if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)
79 {
80 llwarns << "Socks5 server refused all our authentication methods" << llendl;
81 stopProxy();
82 return SOCKS_NOT_ACCEPTABLE;
83 }
84
85 // SOCKS5 USERNAME/PASSWORD authentication
86 if (socks_auth_response.method == METHOD_PASSWORD)
87 {
88 // The server has requested a username/password combination
89 U32 request_size = mSocksUsername.size() + mSocksPassword.size() + 3;
90 char * password_auth = (char *)malloc(request_size);
91 password_auth[0] = 0x01;
92 password_auth[1] = mSocksUsername.size();
93 memcpy(&password_auth[2],mSocksUsername.c_str(), mSocksUsername.size());
94 password_auth[mSocksUsername.size()+2] = mSocksPassword.size();
95 memcpy(&password_auth[mSocksUsername.size()+3], mSocksPassword.c_str(), mSocksPassword.size());
96
97 authmethod_password_reply_t password_reply;
98
99 result = tcp_handshake(hProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(authmethod_password_reply_t));
100 free (password_auth);
101
102 if (result != 0)
103 {
104 llwarns << "Socks authentication failed, error on TCP control channel : " << result << llendl;
105 stopProxy();
106 return SOCKS_CONNECT_ERROR;
107 }
108
109 if (password_reply.status != AUTH_SUCCESS)
110 {
111 llwarns << "Socks authentication failed" << llendl;
112 stopProxy();
113 return SOCKS_AUTH_FAIL;
114 }
115 }
116
117 /* SOCKS5 connect request */
118
119 socks_command_request_t connect_request;
120 socks_command_response_t connect_reply;
121
122 connect_request.version = SOCKS_VERSION; //Socks V5
123 connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP
124 connect_request.flag = FIELD_RESERVED;
125 connect_request.atype = ADDRESS_IPV4;
126 connect_request.address = 0; // 0.0.0.0 We are not fussy about address
127 // UDP is promiscious receive for our protocol
128 connect_request.port = 0; // Port must be 0 if you ever want to connect via NAT and your router does port rewrite for you
129
130 result = tcp_handshake(hProxyControlChannel, (char*)&connect_request, sizeof(socks_command_request_t), (char*)&connect_reply, sizeof(socks_command_response_t));
131 if (result != 0)
132 {
133 llwarns << "Socks connect request failed, error on TCP control channel : " << result << llendl;
134 stopProxy();
135 return SOCKS_CONNECT_ERROR;
136 }
137
138 if (connect_reply.reply != REPLY_REQUEST_GRANTED)
139 {
140 //Something went wrong
141 llwarns << "Connection to SOCKS5 server failed, UDP forward request not granted" << llendl;
142 stopProxy();
143 return SOCKS_UDP_FWD_NOT_GRANTED;
144 }
145
146 mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
147 mUDPProxy.setAddress(proxy.getAddress());
148 // All good now we have been given the UDP port to send requests that need forwarding.
149 llinfos << "Socks 5 UDP proxy connected on " << mUDPProxy << llendl;
150 return SOCKS_OK;
151}
152
153int LLSocks::startProxy(LLHost proxy, U32 message_port)
154{
155 int status;
156
157 mTCPProxy = proxy;
158 mNeedUpdate = false;
159
160 stopProxy();
161 hProxyControlChannel = tcp_open_channel(proxy);
162 if (hProxyControlChannel == -1)
163 {
164 return SOCKS_HOST_CONNECT_FAILED;
165 }
166
167 status = proxyHandshake(proxy, message_port);
168 if (status == SOCKS_OK)
169 {
170 sUdpProxyEnabled=true;
171 }
172 return status;
173}
174
175int LLSocks::startProxy(std::string host, U32 port)
176{
177 mTCPProxy.setHostByName(host);
178 mTCPProxy.setPort(port);
179 return startProxy(mTCPProxy, (U32)gMessageSystem->mPort);
180}
181
182void LLSocks::stopProxy()
183{
184 sUdpProxyEnabled = false;
185
186 if (hProxyControlChannel)
187 {
188 tcp_close_channel(hProxyControlChannel);
189 }
190}
191
192void LLSocks::setAuthNone()
193{
194 mAuthMethodSelected = METHOD_NOAUTH;
195}
196
197
198void LLSocks::setAuthPassword(std::string username, std::string password)
199{
200 mAuthMethodSelected = METHOD_PASSWORD;
201 mSocksUsername = username;
202 mSocksPassword = password;
203}
204
205void LLSocks::EnableHttpProxy(LLHost httpHost, LLHttpProxyType type)
206{
207 sHttpProxyEnabled = true;
208 mHTTPProxy = httpHost;
209 mProxyType = type;
210}
diff --git a/linden/indra/llmessage/llsocks5.h b/linden/indra/llmessage/llsocks5.h
new file mode 100644
index 0000000..d422d20
--- /dev/null
+++ b/linden/indra/llmessage/llsocks5.h
@@ -0,0 +1,248 @@
1/**
2 * @file llsocks5.h
3 * @brief Socks 5 implementation
4 *
5 * $LicenseInfo:firstyear=2001&license=viewergpl$
6 *
7 * Copyright (c) 2001-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#ifndef LL_SOCKS5_H
34#define LL_SOCKS5_H
35
36#include "llhost.h"
37#include "llmemory.h"
38#include <string>
39
40// Error codes returned from the StartProxy method
41
42#define SOCKS_OK 0
43#define SOCKS_CONNECT_ERROR -1
44#define SOCKS_NOT_PERMITTED -2
45#define SOCKS_NOT_ACCEPTABLE -3
46#define SOCKS_AUTH_FAIL -4
47#define SOCKS_UDP_FWD_NOT_GRANTED -5
48#define SOCKS_HOST_CONNECT_FAILED -6
49
50#ifndef MAXHOSTNAMELEN
51#define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */
52#endif
53
54#define SOCKS_VERSION 0x05 // we are using socks 5
55
56// socks 5 address/hostname types
57#define ADDRESS_IPV4 0x01
58#define ADDRESS_HOSTNAME 0x03
59#define ADDRESS_IPV6 0x04
60
61// Lets just use our own ipv4 struct rather than dragging in system
62// specific headers
63union ipv4_address_t {
64 unsigned char octects[4];
65 U32 addr32;
66};
67
68// Socks 5 control channel commands
69#define COMMAND_TCP_STREAM 0x01
70#define COMMAND_TCP_BIND 0x02
71#define COMMAND_UDP_ASSOCIATE 0x03
72
73// Socks 5 command replys
74#define REPLY_REQUEST_GRANTED 0x00
75#define REPLY_GENERAL_FAIL 0x01
76#define REPLY_RULESET_FAIL 0x02
77#define REPLY_NETWORK_UNREACHABLE 0x03
78#define REPLY_HOST_UNREACHABLE 0x04
79#define REPLY_CONNECTION_REFUSED 0x05
80#define REPLY_TTL_EXPIRED 0x06
81#define REPLY_PROTOCOL_ERROR 0x07
82#define REPLY_TYPE_NOT_SUPPORTED 0x08
83
84#define FIELD_RESERVED 0x00
85
86// The standard socks5 request packet
87// Push current alignment to stack and set alignment to 1 byte boundary
88// This enabled us to use structs directly to set up and receive network packets
89// into the correct fields, without fear of boundary alignment causing issues
90#pragma pack(push,1)
91
92// Socks5 command packet
93struct socks_command_request_t {
94 unsigned char version;
95 unsigned char command;
96 unsigned char flag;
97 unsigned char atype;
98 U32 address;
99 U16 port;
100};
101
102// Standard socks5 reply packet
103struct socks_command_response_t {
104 unsigned char version;
105 unsigned char reply;
106 unsigned char flag;
107 unsigned char atype;
108 unsigned char add_bytes[4];
109 U16 port;
110};
111
112#define AUTH_NOT_ACCEPTABLE 0xFF // reply if prefered methods are not avaiable
113#define AUTH_SUCCESS 0x00 // reply if authentication successfull
114
115// socks 5 authentication request, stating which methods the client supports
116struct socks_auth_request_t {
117 unsigned char version;
118 unsigned char num_methods;
119 unsigned char methods; // We are only using a single method currently
120};
121
122// socks 5 authentication response packet, stating server prefered method
123struct socks_auth_response_t {
124 unsigned char version;
125 unsigned char method;
126};
127
128// socks 5 password reply packet
129struct authmethod_password_reply_t {
130 unsigned char version;
131 unsigned char status;
132};
133
134// socks 5 UDP packet header
135struct proxywrap_t {
136 U16 rsv;
137 U8 frag;
138 U8 atype;
139 U32 addr;
140 U16 port;
141};
142
143#pragma pack(pop) /* restore original alignment from stack */
144
145
146// Currently selected http proxy type
147enum LLHttpProxyType
148{
149 LLPROXY_SOCKS=0,
150 LLPROXY_HTTP=1
151};
152
153// Auth types
154enum LLSocks5AuthType
155{
156 METHOD_NOAUTH=0x00, // Client supports no auth
157 METHOD_GSSAPI=0x01, // Client supports GSSAPI (Not currently supported)
158 METHOD_PASSWORD=0x02 // Client supports username/password
159};
160
161class LLSocks: public LLSingleton<LLSocks>
162{
163public:
164 LLSocks();
165
166 // Start a connection to the socks 5 proxy
167 int startProxy(std::string host,U32 port);
168 int startProxy(LLHost proxy,U32 messagePort);
169
170 // Disconnect and clean up any connection to the socks 5 proxy
171 void stopProxy();
172
173 // Set up to use Password auth when connecting to the socks proxy
174 void setAuthPassword(std::string username,std::string password);
175
176 // Set up to use No Auth when connecting to the socks proxy;
177 void setAuthNone();
178
179 // get the currently selected auth method
180 LLSocks5AuthType getSelectedAuthMethod() { return mAuthMethodSelected; };
181
182 // static check for enabled status for UDP packets
183 static bool isEnabled(){return sUdpProxyEnabled;};
184
185 // static check for enabled status for http packets
186 static bool isHttpProxyEnabled(){return sHttpProxyEnabled;};
187
188 // Proxy http packets via httpHost, which can be a Socks5 or a http proxy
189 // as specified in type
190 void EnableHttpProxy(LLHost httpHost,LLHttpProxyType type);
191
192 // Stop proxying http packets
193 void DisableHttpProxy() {sHttpProxyEnabled = false;};
194
195 // get the UDP proxy address and port
196 LLHost getUDPPproxy(){return mUDPProxy;};
197 // get the socks 5 TCP control channel address and port
198 LLHost getTCPProxy(){return mTCPProxy;};
199 //get the http proxy address and port
200 LLHost getHTTPProxy(){return mHTTPProxy;};
201
202 // get the currently selected http proxy type
203 LLHttpProxyType getHttpProxyType(){return mProxyType;};
204
205 // mark that we need an update due to a settings change
206 void updated() { mNeedUpdate = true; };
207 // report if the current settings are applied or dirty pending a startProxy
208 bool needsUpdate() { return mNeedUpdate; };
209
210 //Get the username password in a curl compatible format
211 std::string getProxyUserPwd(){ return (mSocksUsername+":"+mSocksPassword);};
212
213private:
214
215 // Open a communication channel to the socks5 proxy proxy, at port messagePort
216 int proxyHandshake(LLHost proxy,U32 messagePort);
217
218 // socket handle to proxy tcp control channel
219 S32 hProxyControlChannel;
220
221 // is the UDP proxy enabled
222 static bool sUdpProxyEnabled;
223 // is the http proxy enabled
224 static bool sHttpProxyEnabled;
225
226 // Have all settings been applied
227 bool mNeedUpdate;
228
229 // currently selected http proxy type
230 LLHttpProxyType mProxyType;
231
232 // UDP proxy address and port
233 LLHost mUDPProxy;
234 // TCP Proxy control channel address and port
235 LLHost mTCPProxy;
236 // HTTP proxy address and port
237 LLHost mHTTPProxy;
238
239 // socks 5 auth method selected
240 LLSocks5AuthType mAuthMethodSelected;
241
242 // socks 5 username
243 std::string mSocksUsername;
244 // socks 5 password
245 std::string mSocksPassword;
246};
247
248#endif
diff --git a/linden/indra/llmessage/message.cpp b/linden/indra/llmessage/message.cpp
index 9a80d7b..3eda579 100644
--- a/linden/indra/llmessage/message.cpp
+++ b/linden/indra/llmessage/message.cpp
@@ -548,9 +548,9 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count, bool faked_message, U8 fak
548 S32 acks = 0; 548 S32 acks = 0;
549 S32 true_rcv_size = 0; 549 S32 true_rcv_size = 0;
550 550
551 U8* buffer = mTrueReceiveBuffer; 551 U8* buffer = mTrueReceiveBuffer.buffer;
552 552
553 mTrueReceiveSize = mPacketRing.receivePacket(mSocket, (char *)mTrueReceiveBuffer); 553 mTrueReceiveSize = mPacketRing.receivePacket(mSocket, (char *)mTrueReceiveBuffer.buffer);
554 // If you want to dump all received packets into SecondLife.log, uncomment this 554 // If you want to dump all received packets into SecondLife.log, uncomment this
555 //dumpPacketToLog(); 555 //dumpPacketToLog();
556 // <edit> 556 // <edit>
@@ -622,7 +622,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count, bool faked_message, U8 fak
622 for(S32 i = 0; i < acks; ++i) 622 for(S32 i = 0; i < acks; ++i)
623 { 623 {
624 true_rcv_size -= sizeof(TPACKETID); 624 true_rcv_size -= sizeof(TPACKETID);
625 memcpy(&mem_id, &mTrueReceiveBuffer[true_rcv_size], /* Flawfinder: ignore*/ 625 memcpy(&mem_id, &buffer[true_rcv_size], /* Flawfinder: ignore*/
626 sizeof(TPACKETID)); 626 sizeof(TPACKETID));
627 packet_id = ntohl(mem_id); 627 packet_id = ntohl(mem_id);
628 //LL_INFOS("Messaging") << "got ack: " << packet_id << llendl; 628 //LL_INFOS("Messaging") << "got ack: " << packet_id << llendl;
@@ -3386,7 +3386,7 @@ void LLMessageSystem::dumpPacketToLog()
3386 { 3386 {
3387 S32 offset = cur_line_pos * 3; 3387 S32 offset = cur_line_pos * 3;
3388 snprintf(line_buffer + offset, sizeof(line_buffer) - offset, 3388 snprintf(line_buffer + offset, sizeof(line_buffer) - offset,
3389 "%02x ", mTrueReceiveBuffer[i]); /* Flawfinder: ignore */ 3389 "%02x ", mTrueReceiveBuffer.buffer[i]); /* Flawfinder: ignore */
3390 cur_line_pos++; 3390 cur_line_pos++;
3391 if (cur_line_pos >= 16) 3391 if (cur_line_pos >= 16)
3392 { 3392 {
diff --git a/linden/indra/llmessage/message.h b/linden/indra/llmessage/message.h
index 660cd2b..1ef15d2 100644
--- a/linden/indra/llmessage/message.h
+++ b/linden/indra/llmessage/message.h
@@ -66,6 +66,7 @@
66#include "llmessagesenderinterface.h" 66#include "llmessagesenderinterface.h"
67 67
68#include "llstoredmessage.h" 68#include "llstoredmessage.h"
69#include "llsocks5.h"
69 70
70const U32 MESSAGE_MAX_STRINGS_LENGTH = 64; 71const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
71const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192; 72const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
@@ -774,7 +775,18 @@ private:
774 LLMessagePollInfo *mPollInfop; 775 LLMessagePollInfo *mPollInfop;
775 776
776 U8 mEncodedRecvBuffer[MAX_BUFFER_SIZE]; 777 U8 mEncodedRecvBuffer[MAX_BUFFER_SIZE];
777 U8 mTrueReceiveBuffer[MAX_BUFFER_SIZE]; 778
779// Push current alignment to stack and set alignment to 1 byte boundary
780#pragma pack(push,1)
781
782 struct ReceiveBuffer_t
783 {
784 proxywrap_t header;
785 U8 buffer[MAX_BUFFER_SIZE];
786 } mTrueReceiveBuffer;
787
788#pragma pack(pop) /* restore original alignment from stack */
789
778 S32 mTrueReceiveSize; 790 S32 mTrueReceiveSize;
779 791
780 // Must be valid during decode 792 // Must be valid during decode
diff --git a/linden/indra/llmessage/net.cpp b/linden/indra/llmessage/net.cpp
index 7166271..fa51645 100644
--- a/linden/indra/llmessage/net.cpp
+++ b/linden/indra/llmessage/net.cpp
@@ -56,6 +56,7 @@
56#include "lltimer.h" 56#include "lltimer.h"
57#include "indra_constants.h" 57#include "indra_constants.h"
58 58
59#include "llsocks5.h"
59 60
60// Globals 61// Globals
61#if LL_WINDOWS 62#if LL_WINDOWS
@@ -179,7 +180,91 @@ U32 ip_string_to_u32(const char* ip_string)
179////////////////////////////////////////////////////////////////////////////////////////// 180//////////////////////////////////////////////////////////////////////////////////////////
180 181
181#if LL_WINDOWS 182#if LL_WINDOWS
182 183
184int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen)
185{
186 int result;
187 result = send(handle, dataout, outlen, 0);
188 if (result != outlen)
189 {
190 S32 err = WSAGetLastError();
191 llwarns << "Error sending data to proxy control channel, number of bytes sent were " << result << " error code was " << err << llendl;
192 return -1;
193 }
194
195 result = recv(handle, datain, maxinlen, 0);
196 if (result != maxinlen)
197 {
198 S32 err = WSAGetLastError();
199 llwarns << "Error receiving data from proxy control channel, number of bytes received were " << result << " error code was " << err << llendl;
200 return -1;
201 }
202
203 return 0;
204}
205
206S32 tcp_open_channel(LLHost host)
207{
208 // Open a TCP channel
209 // Jump through some hoops to ensure that if the request hosts is down
210 // or not reachable connect() does not block
211
212 S32 handle;
213 handle = socket(AF_INET, SOCK_STREAM, 0);
214 if (!handle)
215 {
216 llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl;
217 return -1;
218 }
219
220 struct sockaddr_in address;
221 address.sin_port = htons(host.getPort());
222 address.sin_family = AF_INET;
223 address.sin_addr.s_addr = host.getAddress();
224
225 // Non blocking
226 WSAEVENT hEvent=WSACreateEvent();
227 WSAEventSelect(handle, hEvent, FD_CONNECT) ;
228 connect(handle, (struct sockaddr*)&address, sizeof(address)) ;
229 // Wait fot 5 seconds, if we can't get a TCP channel open in this
230 // time frame then there is something badly wrong.
231 WaitForSingleObject(hEvent, 1000*5); // 5 seconds time out
232
233 WSANETWORKEVENTS netevents;
234 WSAEnumNetworkEvents(handle,hEvent,&netevents);
235
236 // Check the async event status to see if we connected
237 if ((netevents.lNetworkEvents & FD_CONNECT) == FD_CONNECT)
238 {
239 if (netevents.iErrorCode[FD_CONNECT_BIT] != 0)
240 {
241 llwarns << "Unable to open TCP channel, WSA returned an error code of " << netevents.iErrorCode[FD_CONNECT_BIT] << llendl;
242 WSACloseEvent(hEvent);
243 return -1;
244 }
245
246 // Now we are connected disable non blocking
247 // we don't need support an async interface as
248 // currently our only consumer (socks5) will make one round
249 // of packets then just hold the connection open
250 WSAEventSelect(handle, hEvent, NULL) ;
251 unsigned long NonBlock = 0;
252 ioctlsocket(handle, FIONBIO, &NonBlock);
253
254 return handle;
255 }
256
257 llwarns << "Unable to open TCP channel, Timeout is the host up?" << netevents.iErrorCode[FD_CONNECT_BIT] << llendl;
258 return -1;
259}
260
261void tcp_close_channel(S32 handle)
262{
263 llinfos << "Closing TCP channel" << llendl;
264 shutdown(handle, SD_BOTH);
265 closesocket(handle);
266}
267
183S32 start_net(S32& socket_out, int& nPort) 268S32 start_net(S32& socket_out, int& nPort)
184{ 269{
185 // Create socket, make non-blocking 270 // Create socket, make non-blocking
@@ -377,6 +462,77 @@ BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, i
377 462
378#else 463#else
379 464
465
466int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen)
467{
468 if (send(handle, dataout, outlen, 0) != outlen)
469 {
470 llwarns << "Error sending data to proxy control channel" << llendl;
471 return -1;
472 }
473
474 if (recv(handle, datain, maxinlen, 0) != maxinlen)
475 {
476 llwarns << "Error receiving data to proxy control channel" << llendl;
477 return -1;
478 }
479
480 return 0;
481}
482
483S32 tcp_open_channel(LLHost host)
484{
485 S32 handle;
486 handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
487 if (!handle)
488 {
489 llwarns << "Error opening TCP control socket, socket() returned " << handle << llendl;
490 return -1;
491 }
492
493 struct sockaddr_in address;
494 address.sin_port = htons(host.getPort());
495 address.sin_family = AF_INET;
496 address.sin_addr.s_addr = host.getAddress();
497
498 // Set the socket to non blocking for the connect()
499 int flags = fcntl(handle, F_GETFL, 0);
500 fcntl(handle, F_SETFL, flags | O_NONBLOCK);
501
502 S32 error = connect(handle, (sockaddr*)&address, sizeof(address));
503 if (error && (errno != EINPROGRESS))
504 {
505 llwarns << "Unable to open TCP channel, error code: " << errno << llendl;
506 return -1;
507 }
508
509 struct timeval timeout;
510 timeout.tv_sec = 5; // Maximum time to wait for the connect() to complete
511 timeout.tv_usec = 0;
512 fd_set fds;
513 FD_ZERO(&fds);
514 FD_SET(handle, &fds);
515
516 // See if we have connectde or time out after 5 seconds
517 U32 rc = select(sizeof(fds)*8, NULL, &fds, NULL, &timeout);
518
519 if (rc != 1) // we require exactly one descriptor to be set
520 {
521 llwarns << "Unable to open TCP channel" << llendl;
522 return -1;
523 }
524
525 // Return the socket to blocking operations
526 fcntl(handle, F_SETFL, flags);
527
528 return handle;
529}
530
531void tcp_close_channel(S32 handle)
532{
533 close(handle);
534}
535
380// Create socket, make non-blocking 536// Create socket, make non-blocking
381S32 start_net(S32& socket_out, int& nPort) 537S32 start_net(S32& socket_out, int& nPort)
382{ 538{
diff --git a/linden/indra/llmessage/net.h b/linden/indra/llmessage/net.h
index 45b07a0..531b5c3 100644
--- a/linden/indra/llmessage/net.h
+++ b/linden/indra/llmessage/net.h
@@ -64,6 +64,9 @@ U32 ip_string_to_u32(const char* ip_string); // Wrapper for inet_addr()
64 64
65extern const char* LOOPBACK_ADDRESS_STRING; 65extern const char* LOOPBACK_ADDRESS_STRING;
66 66
67void tcp_close_channel(S32 handle);
68S32 tcp_open_channel(LLHost host);
69int tcp_handshake(S32 handle, char * dataout, int outlen, char * datain, int maxinlen);
67 70
68// useful MTU consts 71// useful MTU consts
69 72