Added ip spoofing protectection.

This commit is contained in:
phr0z3nt04st
2010-06-22 15:31:11 -05:00
parent 80b7af4809
commit b13bbd7b40
11 changed files with 553 additions and 4 deletions

View File

@@ -55,6 +55,7 @@ set(llmessage_SOURCE_FILES
llmessagethrottle.cpp
llmime.cpp
llnamevalue.cpp
llnetcanary.cpp
llnullcipher.cpp
llpacketack.cpp
llpacketbuffer.cpp
@@ -147,6 +148,7 @@ set(llmessage_HEADER_FILES
llmime.h
llmsgvariabletype.h
llnamevalue.h
llnetcanary.h
llnullcipher.h
llpacketack.h
llpacketbuffer.h

View File

@@ -0,0 +1,140 @@
// <edit>
#include "llnetcanary.h"
#include "llerror.h"
#ifdef _MSC_VER
#include <winsock2.h>
static WSADATA trapWSAData;
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
extern int errno; //error number
#define SOCKADDR_IN struct sockaddr_in
#define SOCKADDR struct sockaddr
#define SOCKET int
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SD_BOTH 2
#define closesocket close
#endif
SOCKADDR_IN trapLclAddr;
LLNetCanary::LLNetCanary(int requested_port)
{
mGood = TRUE;
int nRet;
int hSocket;
int snd_size = 400000;
int rec_size = 400000;
int buff_size = 4;
#ifdef _MSC_VER
if(WSAStartup(0x0202, &trapWSAData))
{
S32 err = WSAGetLastError();
WSACleanup();
llwarns << "WSAStartup() failure: " << err << llendl;
mGood = FALSE;
return;
}
#endif
// Get a datagram socket
hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
if (hSocket == INVALID_SOCKET)
{
#ifdef _MSC_VER
S32 err = WSAGetLastError();
WSACleanup();
#else
S32 err = errno;
#endif
mGood = FALSE;
llwarns << "socket() failure: " << err << llendl;
return;
}
// Name the socket (assign the local port number to receive on)
trapLclAddr.sin_family = AF_INET;
trapLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
trapLclAddr.sin_port = htons(requested_port);
//llinfos << "bind() port: " << requested_port << llendl;
nRet = bind(hSocket, (struct sockaddr*) &trapLclAddr, sizeof(trapLclAddr));
if (nRet == SOCKET_ERROR)
{
#ifdef _MSC_VER
S32 err = WSAGetLastError();
WSACleanup();
#else
S32 err = errno;
#endif
mGood = FALSE;
llwarns << "bind() failed: " << err << llendl;
return;
}
// Find out what address we got
SOCKADDR_IN socket_address;
S32 socket_address_size = sizeof(socket_address);
getsockname(hSocket, (SOCKADDR*) &socket_address, (socklen_t *)&socket_address_size);
mPort = ntohs(socket_address.sin_port);
//llinfos << "got port " << mPort << llendl;
// Set socket to be non-blocking
#ifdef _MSC_VER
unsigned long argp = 1;
nRet = ioctlsocket (hSocket, FIONBIO, &argp);
#else
nRet = fcntl(hSocket, F_SETFL, O_NONBLOCK);
#endif
if (nRet == SOCKET_ERROR)
{
#ifdef _MSC_VER
S32 err = WSAGetLastError();
WSACleanup();
#else
S32 err = errno;
#endif
mGood = FALSE;
llwarns << "Failed to set socket non-blocking, Err: " << err << llendl;
return;
}
// set a large receive buffer
nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
if (nRet)
{
llinfos << "Can't set receive buffer size!" << llendl;
}
// set a large send buffer
nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
if (nRet)
{
llinfos << "Can't set send buffer size!" << llendl;
}
//getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
//getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);
//LL_DEBUGS("AppInit") << "startNet - receive buffer size : " << rec_size << LL_ENDL;
//LL_DEBUGS("AppInit") << "startNet - send buffer size : " << snd_size << LL_ENDL;
mSocket = hSocket;
}
LLNetCanary::~LLNetCanary()
{
if(mGood)
{
if(mSocket)
{
shutdown(mSocket, SD_BOTH);
closesocket(mSocket);
}
#ifdef _MSC_VER
WSACleanup();
#endif
}
}
// </edit>

View File

@@ -0,0 +1,25 @@
// <edit>
#ifndef LL_LLNETCANARY_H
#define LL_LLNETCANARY_H
#include "stdtypes.h"
#include <string>
class LLNetCanary
{
public:
LLNetCanary(int requested_port);
~LLNetCanary();
BOOL mGood;
S32 mSocket;
U16 mPort;
U8 mBuffer[8192];
typedef struct
{
F64 time; // LLTimer::getElapsedSeconds();
//U8 message[4];
U32 message;
U32 points;
std::string name;
} entry;
};
#endif
// </edit>

View File

@@ -550,6 +550,76 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count, bool faked_message, U8 fak
S32 receive_size = 0;
do
{
// <edit>
// Expire old canary entries
F64 now = LLTimer::getElapsedSeconds();
std::map<U32, LLNetCanary::entry>::iterator canary_entry_iter;
std::map<U32, LLNetCanary::entry>::iterator canary_entry_end = mCanaryEntries.end();
for( canary_entry_iter = mCanaryEntries.begin();
canary_entry_iter != mCanaryEntries.end(); )
{
if( ((*canary_entry_iter).second.time + 30.0f) < now)
{
llinfos << "Expiring ban on " << (*canary_entry_iter).second.name << " message, " << (*canary_entry_iter).second.points << " points" << llendl;
mCanaryEntries.erase(canary_entry_iter++);
}
else
{
canary_entry_iter++;
}
}
if(!faked_message && mSpoofProtectionLevel > 1)
{
// Canaries receive
std::vector<LLNetCanary*>::iterator canary_iter = mCanaries.begin();
std::vector<LLNetCanary*>::iterator canary_end = mCanaries.end();
for( ; canary_iter != canary_end; ++canary_iter)
{
U8* canary_buffer = (*canary_iter)->mBuffer;
S32 len = receive_packet((*canary_iter)->mSocket, (char*)canary_buffer);
if(len)
{
//llinfos << "canary received " << len << " bytes on port " << (*canary_iter)->mPort << llendl;
zeroCodeExpand(&canary_buffer, &len);
if(len < 7) continue; // too short to be an slmsg
LLNetCanary::entry entry;
entry.message = 0;
if(canary_buffer[6] != 0xFF) // High XX
entry.message = canary_buffer[6];
else if((len >= 8) && (canary_buffer[7] != 0xFF)) // Medium FFXX
entry.message = (255 << 8) | canary_buffer[7];
else if((len >= 10) && (canary_buffer[7] == 0xFF)) // Low FFFFXXXX
{
U16 message_id_U16 = 0;
memcpy(&message_id_U16, &canary_buffer[8], 2);
message_id_U16 = ntohs(message_id_U16);
entry.message = 0xFFFF0000 | message_id_U16;
}
else continue; // not an slmsg
if(mCanaryEntries.find(entry.message) == mCanaryEntries.end())
{
// brand new entry
LLMessageTemplate* temp = get_ptr_in_map(mMessageNumbers, entry.message);
entry.name = temp ? temp->mName : "Invalid";
entry.points = 1;
entry.time = now;
mCanaryEntries[entry.message] = entry;
if(mSpoofProtectionLevel == 2)
llinfos << "Temporarily banning a " << entry.name << " message" << llendl;
}
else
{
// strike two, three...
mCanaryEntries[entry.message].points++;
mCanaryEntries[entry.message].time = now;
if((mSpoofProtectionLevel > 2) && (mCanaryEntries[entry.message].points == 2))
llinfos << "Temporarily banning a " << mCanaryEntries[entry.message].name << " message" << llendl;
}
}
}
}
// </edit>
clearReceiveState();
BOOL recv_reliable = FALSE;
@@ -625,6 +695,61 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count, bool faked_message, U8 fak
// process the message as normal
mIncomingCompressedSize = zeroCodeExpand(&buffer, &receive_size);
mCurrentRecvPacketID = ntohl(*((U32*)(&buffer[1])));
// <edit>
BOOL spoofed_packet = FALSE;
if(mSpoofProtectionLevel > 0)
{
S32 len = receive_size;
U32 message = 0;
if(buffer[6] != 0xFF) // High XX
message = buffer[6];
else if((len >= 8) && (buffer[7] != 0xFF)) // Medium FFXX
message = (255 << 8) | buffer[7];
else if((len >= 10) && (buffer[7] == 0xFF)) // Low FFFFXXXX
{
U16 message_id_U16 = 0;
memcpy(&message_id_U16, &buffer[8], 2);
message_id_U16 = ntohs(message_id_U16);
message = 0xFFFF0000 | message_id_U16;
}
if(!mCurrentRecvPacketID)
{
LL_WARNS("Messaging") << "CODE DONKEY_A" << llendl;
if(mSpoofDroppedCallback)
{
LLNetCanary::entry entry;
LLMessageTemplate* temp = get_ptr_in_map(mMessageNumbers, message);
entry.name = temp ? temp->mName : "Invalid";
entry.message = message;
entry.time = now;
entry.points = 1;
mSpoofDroppedCallback(entry);
}
spoofed_packet = TRUE;
valid_packet = FALSE;
}
else if((mSpoofProtectionLevel > 1) && (receive_size >= 7))
{
if(mCanaryEntries.find(message) != mCanaryEntries.end())
{
if(
(mSpoofProtectionLevel == 2) ||
(mCanaryEntries[message].points > 1)
)
{
LL_WARNS("Messaging") << "Dropped probably spoofed " << mCanaryEntries[message].name << " packet, " << mCanaryEntries[message].points << " points" << llendl;
if(mSpoofDroppedCallback)
{
mSpoofDroppedCallback(mCanaryEntries[message]);
}
spoofed_packet = TRUE;
valid_packet = FALSE;
break;
}
}
}
} // mSpoofProtectionLevel
// </edit>
host = getSender();
const bool resetPacketId = true;
@@ -707,6 +832,9 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count, bool faked_message, U8 fak
// But we don't want to acknowledge UseCircuitCode until the circuit is
// available, which is why the acknowledgement test is done above. JC
bool trusted = cdp && cdp->getTrusted();
// <edit>
if(!spoofed_packet)
// </edit>
valid_packet = mTemplateMessageReader->validateMessage(
buffer,
receive_size,
@@ -1862,7 +1990,11 @@ void open_circuit(LLMessageSystem *msgsystem, void** /*user_data*/)
msgsystem->getIPPortFast(_PREHASH_CircuitInfo, _PREHASH_Port, port);
// By default, OpenCircuit's are untrusted
msgsystem->enableCircuit(LLHost(ip, port), FALSE);
// <edit>
//#ifndef LL_RELEASE_FOR_DOWNLOAD
llwarns << "OpenCircuit " << LLHost(ip, port) << llendl;
//#endif
// </edit>msgsystem->enableCircuit(LLHost(ip, port), FALSE);
}
void close_circuit(LLMessageSystem *msgsystem, void** /*user_data*/)
@@ -2718,6 +2850,9 @@ void end_messaging_system(bool print_summary)
LLTransferTargetVFile::updateQueue(true); // shutdown LLTransferTargetVFile
if (gMessageSystem)
{
// <edit>
gMessageSystem->stopSpoofProtection();
// </edit>
gMessageSystem->stopLogging();
if (print_summary)
@@ -4080,4 +4215,155 @@ const LLHost& LLMessageSystem::getSender() const
LLHTTPRegistration<LLHTTPNodeAdapter<LLTrustedMessageService> >
gHTTPRegistrationTrustedMessageWildcard("/trusted-message/<message-name>");
// <edit>
void LLMessageSystem::startSpoofProtection(U32 level)
{
if(!mPort)
{
llwarns << "listen port is 0!!!" << llendl;
}
mSpoofProtectionLevel = level;
mCanaries.clear();
mCanaryEntries.clear();
// Make canaries
std::string canary_info("");
if(mSpoofProtectionLevel > 2) // 3 or greater
{
// FULL CANARY POWER
int rPort = 768 + ll_rand(32);
if(mPort < rPort) rPort = mPort - 16;
if(rPort < 1) rPort = 1;
while(rPort < 65536)
{
if(rPort != mPort)
{
LLNetCanary* canary = new LLNetCanary(rPort);
if(canary->mGood)
{
mCanaries.push_back(canary);
canary_info.append(llformat(" %d", canary->mPort));
}
else
delete canary;
}
int dist = llabs(mPort - rPort);
if(dist > 4096)
rPort += ll_rand(2048) + 2048;
else if(dist > 2048)
rPort += ll_rand(1024) + 1024;
else if(dist > 1024)
rPort += ll_rand(512) + 512;
else if(dist > 512)
rPort += ll_rand(256) + 256;
else if(dist > 128)
rPort += ll_rand(64) + 64;
else if(dist > 16)
rPort += ll_rand(8) + 8;
else
rPort += 4;
}
}
else if(mSpoofProtectionLevel == 2)
{
// Minimal canaries
for(int o = -32; o <= 32; o += 8)
{
int rPort = mPort + o;
if(rPort != mPort)
{
LLNetCanary* canary = new LLNetCanary(rPort);
if(canary->mGood)
{
mCanaries.push_back(canary);
canary_info.append(llformat(" %d", canary->mPort));
}
else
delete canary;
}
}
}
if(mCanaries.size())
{
llinfos << "level " << mSpoofProtectionLevel << ", " << mCanaries.size() << " canaries: " << canary_info << llendl;
}
else
{
llinfos << "level " << mSpoofProtectionLevel << ", no canaries" << llendl;
}
}
void LLMessageSystem::stopSpoofProtection()
{
llinfos << "cleaning up" << llendl;
// Shut down canaries
std::vector<LLNetCanary*>::iterator canary_iter = mCanaries.begin();
std::vector<LLNetCanary*>::iterator canary_end = mCanaries.end();
for( ; canary_iter != canary_end; ++canary_iter)
{
LLNetCanary* canary = (*canary_iter);
delete canary;
}
mCanaries.clear();
// Empty canary entries
mCanaryEntries.clear();
}
void LLMessageSystem::setSpoofDroppedCallback(void (*callback)(LLNetCanary::entry))
{
mSpoofDroppedCallback = callback;
}
// Copypasta from LLTemplateMessageReader
BOOL LLMessageSystem::decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template )
{
const U8* header = buffer + LL_PACKET_ID_SIZE;
if (buffer_size <= 0) return FALSE;
U32 num = 0;
if (header[0] != 255)
{
// high frequency message
num = header[0];
}
else if ((buffer_size >= ((S32) LL_MINIMUM_VALID_PACKET_SIZE + 1)) && (header[1] != 255))
{
// medium frequency message
num = (255 << 8) | header[1];
}
else if ((buffer_size >= ((S32) LL_MINIMUM_VALID_PACKET_SIZE + 3)) && (header[1] == 255))
{
// low frequency message
U16 message_id_U16 = 0;
// I think this check busts the message system.
// it appears that if there is a NULL in the message #, it won't copy it....
// what was the goal?
//if(header[2])
memcpy(&message_id_U16, &header[2], 2);
// dependant on endian-ness:
// U32 temp = (255 << 24) | (255 << 16) | header[2];
// independant of endian-ness:
message_id_U16 = ntohs(message_id_U16);
num = 0xFFFF0000 | message_id_U16;
}
else // bogus packet received (too short)
{
return(FALSE);
}
LLMessageTemplate* temp = get_ptr_in_map(mMessageNumbers,num);
if (temp)
{
*msg_template = temp;
}
else
{
return(FALSE);
}
return(TRUE);
}
// </edit

View File

@@ -67,6 +67,9 @@
#include "llstoredmessage.h"
#include "llsocks5.h"
// <edit>
#include "llnetcanary.h"
// </edit>
const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
@@ -215,6 +218,12 @@ class LLMessageSystem : public LLMessageSenderInterface
private:
U8 mSendBuffer[MAX_BUFFER_SIZE];
S32 mSendSize;
// <edit>
U32 mSpoofProtectionLevel;
std::vector<LLNetCanary*> mCanaries;
std::map<U32, LLNetCanary::entry> mCanaryEntries;
void (*mSpoofDroppedCallback)(LLNetCanary::entry);
// </edit>
bool mBlockUntrustedInterface;
LLHost mUntrustedInterface;
@@ -236,7 +245,6 @@ class LLMessageSystem : public LLMessageSenderInterface
// </edit>
message_template_name_map_t mMessageTemplates;
message_template_number_map_t mMessageNumbers;
// <edit>
//public:
// </edit>
@@ -614,6 +622,11 @@ public:
// Change this message to be UDP black listed.
void banUdpMessage(const std::string& name);
// <edit>
void startSpoofProtection(U32 level);
void stopSpoofProtection();
void setSpoofDroppedCallback(void (*callback)(LLNetCanary::entry));
// </edit>
private:
// A list of the circuits that need to be sent DenyTrustedCircuit messages.
@@ -756,7 +769,13 @@ private:
LLUUID mSessionID;
void addTemplate(LLMessageTemplate *templatep);
// <edit>
public:
// </edit>
BOOL decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template );
// <edit>
private:
// </edit>
void logMsgFromInvalidCircuit( const LLHost& sender, BOOL recv_reliable );
void logTrustedMsgFromUntrustedCircuit( const LLHost& sender );

View File

@@ -784,6 +784,28 @@
<string>S32</string>
<key>Value</key>
<integer>5</integer>
</map>
<key>SpoofProtectionAlerts</key>
<map>
<key>Comment</key>
<string>Enables IP Spoofing protection alerts</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SpoofProtectionLevel</key>
<map>
<key>Comment</key>
<string>IP Spoofing protection level</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>Socks5ProxyEnabled</key>
<map>

View File

@@ -74,6 +74,7 @@ private:
U32 mLinksForChattingObjects;
U32 mTimeFormat;
U32 mDateFormat;
U32 mSpoofProtectionAtOpen;
};
@@ -180,6 +181,7 @@ void LLPrefsInertImpl::refresh()
{
combo->setCurrentByIndex(mDateFormat);
}
mSpoofProtectionAtOpen = gSavedSettings.getU32("SpoofProtectionLevel");
}
void LLPrefsInertImpl::cancel()
@@ -199,7 +201,8 @@ void LLPrefsInertImpl::cancel()
gSavedSettings.setBOOL("RevokePermsOnStandUp", mRevokePermsOnStandUp);
gSavedSettings.setBOOL("WindEnabled", mEnableLLWind);
gSavedSettings.setBOOL("BroadcastViewerEffects", mBroadcastViewerEffects);
gSavedSettings.setU32("SpoofProtectionLevel", mSpoofProtectionAtOpen);
gLLWindEnabled = mEnableLLWind;
if(mInitialEnableClouds != gSavedSettings.getBOOL("CloudsEnabled"))
@@ -261,7 +264,16 @@ void LLPrefsInertImpl::apply()
gSavedSettings.setString("ShortTimeFormat", short_time);
gSavedSettings.setString("LongTimeFormat", long_time);
gSavedSettings.setString("TimestampFormat", timestamp);
if(gMessageSystem)
{
U32 new_spoof_protection = gSavedSettings.getU32("SpoofProtectionLevel");
if(new_spoof_protection != mSpoofProtectionAtOpen)
{
mSpoofProtectionAtOpen = new_spoof_protection;
gMessageSystem->stopSpoofProtection();
gMessageSystem->startSpoofProtection(new_spoof_protection);
}
}
refreshValues();
}

View File

@@ -926,6 +926,14 @@ bool idle_startup()
LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().insert("DIAGNOSTIC", diagnostic));
}
// <edit>
if(gMessageSystem)
{
gMessageSystem->startSpoofProtection(gSavedSettings.getU32("SpoofProtectionLevel"));
gMessageSystem->setSpoofDroppedCallback(spoof_dropped_callback);
}
// </edit>
#if LL_WINDOWS
// On the windows dev builds, unpackaged, the message.xml file will
// be located in indra/build-vc**/newview/<config>/app_settings.

View File

@@ -5915,3 +5915,15 @@ void LLOfferInfo::forceResponse(InventoryOfferResponse response)
LLNotifications::instance().forceResponse(params, response);
}
// <edit> lol
void spoof_dropped_callback(LLNetCanary::entry entry)
{
if(gSavedSettings.getBOOL("SpoofProtectionAlerts"))
{
LLSD args;
args["[MESSAGE]"] = llformat("A suspicious %s packet was dropped based on your IP Spoofing Protection settings.", entry.name.c_str());
LLNotifications::instance().add("SystemMessageTip",args);
}
}
// </edit>

View File

@@ -197,6 +197,10 @@ void process_decline_callingcard(LLMessageSystem* msg, void**);
// Message system exception prototypes
void invalid_message_callback(LLMessageSystem*, void*, EMessageException);
// <edit>
void spoof_dropped_callback(LLNetCanary::entry entry);
// </edit>
void process_initiate_download(LLMessageSystem* msg, void**);
void start_new_inventory_observer();

View File

@@ -96,6 +96,25 @@
mouse_opaque="true" name="enable_clouds" radio_style="false"
width="400" />
</panel>
<panel border="true" left="1" bottom="-408" height="408" width="500" mouse_opaque="true"
follows="left|top|right|bottom" label="Security" name="Security">
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom="-20" drop_shadow_visible="true" enabled="true" follows="left|top"
font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12"
mouse_opaque="false" name="text_box" v_pad="0" width="500">
IP Spoofing Protection (0 being off, 3 being highest)
</text>
<slider bottom_delta="-25" can_edit_text="false"
decimal_digits="0" enabled="true" follows="left|top" height="15"
increment="1" initial_val="0" left_delta="0" max_val="3" min_val="0"
mouse_opaque="true" control_name="SpoofProtectionLevel" name="ip_spoof_slider" show_text="true"
width="180" />
<check_box bottom_delta="-25" control_name="SpoofProtectionAlerts" enabled="true"
follows="left|top" font="SansSerifSmall" height="16" initial_value="true"
label="Enable Alerts" left="10"
mouse_opaque="true" name="enable_alerts" radio_style="false"
width="400" />
</panel>
<panel border="true" left="1" bottom="-408" height="408" width="500" mouse_opaque="true"
follows="left|top|right|bottom" label="Miscellaneous" name="Miscellaneous">
<check_box bottom_delta="-30" control_name="DoubleClickTeleport" enabled="true"