diff --git a/indra/llmessage/llpacketbuffer.cpp b/indra/llmessage/llpacketbuffer.cpp
index 9907ba0070fd27931eb71bd7abc36e6b62ffc804..027d35cf89fdaa9f0cfbb7c40883e2b4bb3427b3 100644
--- a/indra/llmessage/llpacketbuffer.cpp
+++ b/indra/llmessage/llpacketbuffer.cpp
@@ -74,5 +74,6 @@ void LLPacketBuffer::init (S32 hSocket)
 {
 	mSize = receive_packet(hSocket, mData);
 	mHost = ::get_sender();
+	mReceivingIF = ::get_receiving_interface();
 }
-	
+
diff --git a/indra/llmessage/llpacketbuffer.h b/indra/llmessage/llpacketbuffer.h
index 38e1f2f4f00c011df4b22c4a3cecb15eb3d8a7ac..bbcbdf28b21213731170faccefb549a986de3cb7 100644
--- a/indra/llmessage/llpacketbuffer.h
+++ b/indra/llmessage/llpacketbuffer.h
@@ -44,15 +44,17 @@ class LLPacketBuffer
 	LLPacketBuffer(S32 hSocket);           // receive a packet
 	~LLPacketBuffer();
 
-	S32			getSize() const		{ return mSize; }
-	const char	*getData() const	{ return mData; }
-	LLHost		getHost() const		{ return mHost; }
+	S32			getSize() const					{ return mSize; }
+	const char	*getData() const				{ return mData; }
+	LLHost		getHost() const					{ return mHost; }
+	LLHost		getReceivingInterface() const	{ return mReceivingIF; }
 	void init(S32 hSocket);
 
 protected:
 	char	mData[NET_BUFFER_SIZE];        // packet data		/* Flawfinder : ignore */
 	S32		mSize;          // size of buffer in bytes
 	LLHost	mHost;         // source/dest IP and port
+	LLHost	mReceivingIF;         // source/dest IP and port
 };
 
 #endif
diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp
index 6ecdf702ac1811d14c1e453a707469c93665d563..35d5aac7763368d7c3cc54f49eb9fd0c8b289eec 100644
--- a/indra/llmessage/llpacketring.cpp
+++ b/indra/llmessage/llpacketring.cpp
@@ -141,6 +141,7 @@ S32 LLPacketRing::receiveFromRing (S32 socket, char *datap)
 	}
 	// need to set sender IP/port!!
 	mLastSender = packetp->getHost();
+	mLastReceivingIF = packetp->getReceivingInterface();
 	delete packetp;
 
 	this->mInBufferLength -= packet_size;
@@ -223,6 +224,7 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)
 		// no delay, pull straight from net
 		packet_size = receive_packet(socket, datap);		
 		mLastSender = ::get_sender();
+		mLastReceivingIF = ::get_receiving_interface();
 
 		if (packet_size)  // did we actually get a packet?
 		{
diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h
index a1bac5bc7087ef971a996c9c0312f98a1c07cac0..4408abeb5fef4cdce50a0eeaf0e0bff073d5c6bf 100644
--- a/indra/llmessage/llpacketring.h
+++ b/indra/llmessage/llpacketring.h
@@ -62,6 +62,7 @@ class LLPacketRing
 	BOOL sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host);
 
 	inline LLHost getLastSender();
+	inline LLHost getLastReceivingInterface();
 
 	S32 getAndResetActualInBits()				{ S32 bits = mActualBitsIn; mActualBitsIn = 0; return bits;}
 	S32 getAndResetActualOutBits()				{ S32 bits = mActualBitsOut; mActualBitsOut = 0; return bits;}
@@ -86,6 +87,7 @@ class LLPacketRing
 	std::queue<LLPacketBuffer *> mSendQueue;
 
 	LLHost mLastSender;
+	LLHost mLastReceivingIF;
 };
 
 
@@ -94,4 +96,9 @@ inline LLHost LLPacketRing::getLastSender()
 	return mLastSender;
 }
 
+inline LLHost LLPacketRing::getLastReceivingInterface()
+{
+	return mLastReceivingIF;
+}
+
 #endif
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index 83e1ddb8943a8e3326f02809b451ee4ac46dd9d5..d5f362d7800c421aab4913ba912876e868940692 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -306,6 +306,9 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port,
 	// default to not accepting packets from not alive circuits
 	mbProtected = TRUE;
 
+	// default to blocking trusted connections on a public interface if one is specified
+	mBlockUntrustedInterface = true;
+
 	mSendPacketFailureCount = 0;
 
 	mCircuitPrintFreq = 60.f;		// seconds
@@ -440,6 +443,7 @@ void LLMessageSystem::clearReceiveState()
 	mCurrentRecvPacketID = 0;
 	mIncomingCompressedSize = 0;
 	mLastSender.invalidate();
+	mLastReceivingIF.invalidate();
 	mMessageReader->clearMessage();
 }
 
@@ -589,6 +593,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count )
 		
 		receive_size = mTrueReceiveSize;
 		mLastSender = mPacketRing.getLastSender();
+		mLastReceivingIF = mPacketRing.getLastReceivingInterface();
 		
 		if (receive_size < (S32) LL_MINIMUM_VALID_PACKET_SIZE)
 		{
@@ -2355,6 +2360,23 @@ void process_create_trusted_circuit(LLMessageSystem *msg, void **)
 		return;
 	}
 
+	U32 untrusted_interface = msg->getUntrustedInterface().getAddress();
+	U32 last_interface = msg->getReceivingInterface().getAddress();
+	if ( ( untrusted_interface != INVALID_HOST_IP_ADDRESS ) && ( untrusted_interface == last_interface ) )
+	{
+		if( msg->getBlockUntrustedInterface() )
+		{
+			LL_WARNS("Messaging") << "Refusing trust on public interface from host: "
+				<< msg->getSender() << llendl;
+			return;
+		}
+		else
+		{
+			LL_WARNS("Messaging") << "Establishing trust on public interface from host: "
+				<< msg->getSender() << llendl;
+		}
+	}
+
 	char their_digest[MD5HEX_STR_SIZE];	/* Flawfinder: ignore */
 	S32 size = msg->getSizeFast(_PREHASH_DataBlock, _PREHASH_Digest);
 	if(size != MD5HEX_STR_BYTES)
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index f4e136ee4d8cb3ea40dcac216014123aa69b2be6..25eeb853239c7ba5f7ddc94741fc52d95c5649c5 100644
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -212,6 +212,9 @@ class LLMessageSystem
 	U8					mSendBuffer[MAX_BUFFER_SIZE];
 	S32					mSendSize;
 
+	bool				mBlockUntrustedInterface;
+	LLHost				mUntrustedInterface;
+
  public:
 	LLPacketRing				mPacketRing;
 	LLReliablePacketParams			mReliablePacketParams;
@@ -352,6 +355,8 @@ class LLMessageSystem
 	U32		getSenderIP() const;			// getSender() is preferred
 	U32		getSenderPort() const;		// getSender() is preferred
 
+	const LLHost& getReceivingInterface() const;
+
 	// This method returns the uuid associated with the sender. The
 	// UUID will be null if it is not yet known or is a server
 	// circuit.
@@ -564,6 +569,12 @@ class LLMessageSystem
 	/** Return false true if name is unknown or trusted */
 	bool isUntrustedMessage(const std::string& name) const;
 
+	// Mark an interface ineligible for trust
+	void setUntrustedInterface( const LLHost host ) { mUntrustedInterface = host; }
+	LLHost getUntrustedInterface() const { return mUntrustedInterface; }
+	void setBlockUntrustedInterface( bool block ) { mBlockUntrustedInterface = block; } // Throw a switch to allow, sending warnings only
+	bool getBlockUntrustedInterface() const { return mBlockUntrustedInterface; }
+
 	// Change this message to be UDP black listed.
 	void banUdpMessage(const std::string& name);
 
@@ -747,6 +758,7 @@ class LLMessageSystem
 	void init(); // ctor shared initialisation.
 
 	LLHost mLastSender;
+	LLHost mLastReceivingIF;
 	S32 mIncomingCompressedSize;		// original size of compressed msg (0 if uncomp.)
 	TPACKETID mCurrentRecvPacketID;       // packet ID of current receive packet (for reporting)
 
@@ -966,6 +978,7 @@ inline void *ntohmemcpy(void *s, const void *ct, EMsgVariableType type, size_t n
 
 
 inline const LLHost& LLMessageSystem::getSender() const {return mLastSender;}
+inline const LLHost& LLMessageSystem::getReceivingInterface() const {return mLastReceivingIF;}
 
 inline U32 LLMessageSystem::getSenderIP() const 
 {
@@ -977,6 +990,7 @@ inline U32 LLMessageSystem::getSenderPort() const
 	return mLastSender.getPort();
 }
 
+
 //-----------------------------------------------------------------------------
 // Transmission aliases
 //-----------------------------------------------------------------------------
diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp
index 4f2242fe52a8c34a5ebab96036ca31d1b9015cb9..94a0feb6a7d0719cfdc6c5b4f726d2d1ceb21546 100644
--- a/indra/llmessage/net.cpp
+++ b/indra/llmessage/net.cpp
@@ -71,6 +71,7 @@ static WSADATA stWSAData;
 struct sockaddr_in stDstAddr;
 struct sockaddr_in stSrcAddr;
 struct sockaddr_in stLclAddr;
+static U32 gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS; // Address to which datagram was sent
 
 #if LL_DARWIN
 #ifndef _SOCKLEN_T
@@ -110,6 +111,16 @@ U32 get_sender_port()
 	return ntohs(stSrcAddr.sin_port);
 }
 
+LLHost get_receiving_interface()
+{
+	return LLHost(gsnReceivingIFAddr, INVALID_PORT);
+}
+
+U32 get_receiving_interface_ip(void)
+{
+	return gsnReceivingIFAddr;
+}
+
 const char* u32_to_ip_string(U32 ip)
 {
 	static char buffer[MAXADDRSTR];	 /* Flawfinder: ignore */ 
@@ -455,6 +466,21 @@ S32 start_net(S32& socket_out, int& nPort)
 	llinfos << "startNet - receive buffer size : " << rec_size << llendl;
 	llinfos << "startNet - send buffer size    : " << snd_size << llendl;
 
+#if LL_LINUX
+	// Turn on recipient address tracking
+	{
+		int use_pktinfo = 1;
+		if( setsockopt( hSocket, SOL_IP, IP_PKTINFO, &use_pktinfo, sizeof(use_pktinfo) ) == -1 )
+		{
+			llwarns << "No IP_PKTINFO available" << llendl;
+		}
+		else
+		{
+			llinfos << "IP_PKKTINFO enabled" << llendl;
+		}
+	}
+#endif
+
 	//  Setup a destination address
 	char achMCAddr[MAXADDRSTR] = "127.0.0.1";	/* Flawfinder: ignore */ 
 	stDstAddr.sin_family =      AF_INET;
@@ -473,6 +499,52 @@ void end_net(S32& socket_out)
 	}
 }
 
+#if LL_LINUX
+static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *from, socklen_t *fromlen, U32 *dstip )
+{
+	int size;
+	struct iovec iov[1];
+	char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
+	struct cmsghdr *cmsgptr;
+	struct msghdr msg = {0};
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = len;
+
+	memset( &msg, 0, sizeof msg );
+	msg.msg_name = from;
+	msg.msg_namelen = *fromlen;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = &cmsg;
+	msg.msg_controllen = sizeof(cmsg);
+
+	size = recvmsg( socket, &msg, 0 );
+
+	if( size == -1 )
+	{
+		return -1;
+	}
+
+	for( cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr ) )
+	{
+		if( cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO )
+		{
+			in_pktinfo *pktinfo = (in_pktinfo *)CMSG_DATA(cmsgptr);
+			if( pktinfo )
+			{
+				// Two choices. routed and specified. ipi_addr is routed, ipi_spec_dst is
+				// routed. We should stay with specified until we go to multiple
+				// interfaces
+				*dstip = pktinfo->ipi_spec_dst.s_addr;
+			}
+		}
+	}
+
+	return size;
+}
+#endif
+
 int receive_packet(int hSocket, char * receiveBuffer)
 {
 	//  Receives data asynchronously from the socket set by initNet().
@@ -482,7 +554,14 @@ int receive_packet(int hSocket, char * receiveBuffer)
 	int nRet;
 	socklen_t addr_size = sizeof(struct sockaddr_in);
 
-	nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, 0, (struct sockaddr*)&stSrcAddr, &addr_size);
+	gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS;
+
+#if LL_LINUX
+	nRet = recvfrom_destip(hSocket, receiveBuffer, NET_BUFFER_SIZE, (struct sockaddr*)&stSrcAddr, &addr_size, &gsnReceivingIFAddr);
+#else	
+	int recv_flags = 0;
+	nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, recv_flags, (struct sockaddr*)&stSrcAddr, &addr_size);
+#endif
 
 	if (nRet == -1)
 	{
@@ -490,6 +569,9 @@ int receive_packet(int hSocket, char * receiveBuffer)
 		return 0;
 	}
 
+	// Uncomment for testing if/when implementing for Mac or Windows:
+	// llinfos << "Received datagram to in addr " << u32_to_ip_string(get_receiving_interface_ip()) << llendl;
+
 	return nRet;
 }
 
diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h
index 9a97b3410088ad9b765cc1b6e3dc7d966f217796..45b07a0ab8ad73340e9dba4515d82f7cc3d1e8d8 100644
--- a/indra/llmessage/net.h
+++ b/indra/llmessage/net.h
@@ -55,6 +55,8 @@ BOOL	send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, i
 LLHost  get_sender();
 U32		get_sender_port();
 U32		get_sender_ip(void);
+LLHost  get_receiving_interface();
+U32		get_receiving_interface_ip(void);
 
 const char*	u32_to_ip_string(U32 ip);					// Returns pointer to internal string buffer, "(bad IP addr)" on failure, cannot nest calls 
 char*		u32_to_ip_string(U32 ip, char *ip_string);	// NULL on failure, ip_string on success, you must allocate at least MAXADDRSTR chars