[reSIProcate] STUN over TCP
My company has modified 1.9.6 to do STUN over TCP. I am cross-posting
this to return-devel and resiprocate-devel because the two files we
changed are in resip/stack, but I figure changes involving STUN might
interest the reTurn folks as well. We enclosed our changes in the
conditional compilatoin flag AYLUS_CHANGE_STUN_OVER_TCP, which should be
removed if/when this code is ever incorporated into the codebase. Also,
because we only act as a STUN server, we #if 0'ed the code that
processes STUN responses. No guarantees about the disabled code. Diff
files attached (ConnectionBase.cxx and ConnectionBase.hxx changes from
1.9.6).
-John Gregg
Index: ConnectionBase.cxx
===================================================================
--- ConnectionBase.cxx (revision 27529)
+++ ConnectionBase.cxx (working copy)
@@ -33,12 +33,20 @@
#include <osc/StateChanges.h>
#endif
+#if AYLUS_CHANGE_STUN_OVER_TCP
+#include "rutil/stun/Stun.hxx"
+#endif
+
using namespace resip;
#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
char
-ConnectionBase::connectionStates[ConnectionBase::MAX][32] = { "NewMessage", "ReadingHeaders", "PartialBody" };
+ConnectionBase::connectionStates[ConnectionBase::MAX][32] = { "NewMessage", "ReadingHeaders", "PartialBody",
+#if AYLUS_CHANGE_STUN_OVER_TCP
+ "PartialStunRequest"
+#endif
+};
#ifndef RESIP_SIP_MSG_MAX_BYTES
#define RESIP_SIP_MSG_MAX_BYTES 10485760
@@ -64,6 +72,9 @@
mBuffer(0),
mBufferPos(0),
mBufferSize(0),
+#if AYLUS_CHANGE_STUN_OVER_TCP
+ mStunLength(0),
+#endif
mWsFrameExtractor(messageSizeMax),
mLastUsed(Timer::getTimeMs()),
mConnState(NewMessage)
@@ -130,6 +141,69 @@
return mWho.mFlowKey;
}
+#if AYLUS_CHANGE_STUN_OVER_TCP
+
+
+// Cut and pasted from UdpTransport::processRxParse()
+void
+ConnectionBase::ProcessStunRequest()
+{
+ bool changePort = false;
+ bool changeIp = false;
+
+ StunAddress4 myAddr;
+ const sockaddr_in& bi = (const sockaddr_in&) transport()->boundInterface();
+ myAddr.addr = ntohl(bi.sin_addr.s_addr);
+ myAddr.port = ntohs(bi.sin_port);
+
+ StunAddress4 from; // packet source
+ const sockaddr_in& fi = (const sockaddr_in&) who().getSockaddr();
+ from.addr = ntohl(fi.sin_addr.s_addr);
+ from.port = ntohs(fi.sin_port);
+
+ StunMessage resp;
+ StunAddress4 dest;
+ StunAtrString hmacPassword;
+ hmacPassword.sizeValue = 0;
+
+ StunAddress4 secondary;
+ secondary.port = 0;
+ secondary.addr = 0;
+
+ bool ok = stunServerProcessMsg( mBuffer, mStunLength, // input buffer
+ from, // packet source
+ secondary, // not used
+ myAddr, // address to fill into response
+ myAddr, // not used
+ &resp, // stun response
+ &dest, // where to send response
+ &hmacPassword, // not used
+ &changePort, // not used
+ &changeIp, // not used
+ true ); // logging
+
+ if (ok)
+ {
+ DebugLog(<<"Got TCP STUN request. Sending response...");
+ char* response = new char[STUN_MAX_MESSAGE_SIZE];
+ size_t rlen = stunEncodeMessage( resp,
+ response,
+ STUN_MAX_MESSAGE_SIZE,
+ hmacPassword,
+ false );
+
+ std::auto_ptr<SendData> respSendData(new SendData(who(), response, rlen));
+
+ transport()->send(respSendData);
+ }
+ else
+ {
+ ErrLog(<< "Failed to parse STUN request");
+ }
+}
+
+#endif
+
bool
ConnectionBase::preparseNewBytes(int bytesRead)
{
@@ -141,6 +215,9 @@
{
case NewMessage:
{
+#if AYLUS_CHANGE_STUN_OVER_TCP
+ char * buffer = mBuffer + mBufferPos;
+#endif
if (strncmp(mBuffer + mBufferPos, Symbols::CRLFCRLF, 4) == 0)
{
DebugLog(<< "Got incoming double-CRLF keepalive (aka ping).");
@@ -176,6 +253,113 @@
}
}
+#if AYLUS_CHANGE_STUN_OVER_TCP
+ // AYLUS_CHANGE: STUN processing BEGIN
+ // Cut/pasted from UdpTransport.cxx
+
+#if 0
+
+ // We don't need to worry about STUN responses (yet)
+
+ // this must be a STUN response (or garbage)
+ else if ((bytesRead >= 4) && buffer[0] == 1 && buffer[1] == 1)
+ {
+ StunMessage resp;
+ memset(&resp, 0, sizeof(StunMessage));
+
+ if (stunParseMessage(buffer, len, resp, false))
+ {
+ in_addr sin_addr;
+ // Use XorMappedAddress if present - if not use MappedAddress
+ if(resp.hasXorMappedAddress)
+ {
+ UInt16 id16 = resp.msgHdr.id.octet[0]<<8
+ | resp.msgHdr.id.octet[1];
+ UInt32 id32 = resp.msgHdr.id.octet[0]<<24
+ | resp.msgHdr.id.octet[1]<<16
+ | resp.msgHdr.id.octet[2]<<8
+ | resp.msgHdr.id.octet[3];
+ resp.xorMappedAddress.ipv4.port = resp.xorMappedAddress.ipv4.port^id16;
+ resp.xorMappedAddress.ipv4.addr = resp.xorMappedAddress.ipv4.addr^id32;
+
+#if defined(WIN32)
+ sin_addr.S_un.S_addr = htonl(resp.xorMappedAddress.ipv4.addr);
+#else
+ sin_addr.s_addr = htonl(resp.xorMappedAddress.ipv4.addr);
+#endif
+ mStunMappedAddress = Tuple(sin_addr,resp.xorMappedAddress.ipv4.port, UDP);
+ mStunSuccess = true;
+ }
+ else if(resp.hasMappedAddress)
+ {
+#if defined(WIN32)
+ sin_addr.S_un.S_addr = htonl(resp.mappedAddress.ipv4.addr);
+#else
+ sin_addr.s_addr = htonl(resp.mappedAddress.ipv4.addr);
+#endif
+
+ mStunMappedAddress = Tuple(sin_addr,resp.mappedAddress.ipv4.port, UDP);
+ mStunSuccess = true;
+ }
+ }
+ return false;
+ }
+#endif // 0
+
+ // this must be a STUN request (or garbage)
+ else if ((bytesRead >= 4) && buffer[0] == 0 && buffer[1] == 1)
+ {
+ mStunLength = ntohs(*((uint16_t *) (&buffer[2])));
+ mStunLength += 20; // total, including header.
+
+ DebugLog(<< "STUN request, mStunLength " << mStunLength << ", bytesRead " << bytesRead);
+
+ if (bytesRead + (int) mBufferPos >= (int) mStunLength)
+ {
+ // good to go
+
+ ProcessStunRequest();
+
+ int overHang = bytesRead - mStunLength;
+
+ mConnState = NewMessage;
+
+ if (overHang > 0)
+ {
+ size_t size = overHang*3/2;
+ if (size < ConnectionBase::ChunkSize)
+ {
+ size = ConnectionBase::ChunkSize;
+ }
+ char* newBuffer = MsgHeaderScanner::allocateBuffer((int)size);
+ memcpy(newBuffer, mBuffer + mStunLength, overHang);
+ delete [] mBuffer;
+
+ mBuffer = newBuffer;
+ mBufferPos = 0;
+ mBufferSize = size;
+ mStunLength = 0;
+
+ DebugLog (<< "Extra bytes after message: " << overHang);
+ DebugLog (<< Data(mBuffer, overHang));
+
+ bytesRead = overHang;
+ goto start;
+ }
+
+ mStunLength = 0;
+ }
+ else
+ {
+ // need more bytes.
+ mBufferPos += bytesRead;
+ mConnState = PartialStunRequest;
+ }
+
+ break;
+ }
+#endif // AYLUS_CHANGE_STUN_OVER_TCP
+
assert(mTransport);
mMessage = new SipMessage(mTransport);
@@ -448,6 +632,56 @@
}
break;
}
+
+#if AYLUS_CHANGE_STUN_OVER_TCP
+
+ case PartialStunRequest:
+ {
+ DebugLog(<< "STUN request, mStunLength " << mStunLength << ", bytesRead " << bytesRead << ", mBufferPos " << mBufferPos);
+ if (bytesRead + mBufferPos >= mStunLength)
+ {
+ // good to go
+
+ ProcessStunRequest();
+
+ int overHang = bytesRead - mStunLength;
+
+ mConnState = NewMessage;
+
+ if (overHang > 0)
+ {
+ size_t size = overHang*3/2;
+ if (size < ConnectionBase::ChunkSize)
+ {
+ size = ConnectionBase::ChunkSize;
+ }
+ char* newBuffer = MsgHeaderScanner::allocateBuffer((int)size);
+ memcpy(newBuffer, mBuffer + mStunLength, overHang);
+ delete [] mBuffer;
+ mBuffer = newBuffer;
+ mBufferPos = 0;
+ mBufferSize = size;
+ mStunLength = 0;
+
+ DebugLog (<< "Extra bytes after message: " << overHang);
+ DebugLog (<< Data(mBuffer, overHang));
+
+ bytesRead = overHang;
+ goto start;
+ }
+ mStunLength = 0;
+ }
+ else
+ {
+ // need more bytes.
+ mBufferPos += bytesRead;
+ mConnState = PartialStunRequest;
+ }
+ }
+ break;
+
+#endif // AYLUS_CHANGE_STUN_OVER_TCP
+
case PartialBody:
{
size_t contentLength = 0;
Index: ConnectionBase.hxx
===================================================================
--- ConnectionBase.hxx (revision 27529)
+++ ConnectionBase.hxx (working copy)
@@ -12,6 +12,8 @@
#include "resip/stack/WsFrameExtractor.hxx"
#include "resip/stack/Cookie.hxx"
+#define AYLUS_CHANGE_STUN_OVER_TCP 1
+
namespace osc
{
class Stack;
@@ -61,6 +63,9 @@
NewMessage = 0,
ReadingHeaders,
PartialBody,
+#if AYLUS_CHANGE_STUN_OVER_TCP
+ PartialStunRequest,
+#endif
SigComp, // This indicates that incoming bytes are compressed.
WebSocket,
MAX
@@ -76,6 +81,9 @@
} TransmissionFormat;
ConnState getCurrentState() const { return mConnState; }
+#if AYLUS_CHANGE_STUN_OVER_TCP
+ void ProcessStunRequest();
+#endif
bool preparseNewBytes(int bytesRead);
bool wsProcessHandshake(int bytesRead, bool &dropConnection);
bool wsProcessData(int bytesRead);
@@ -121,6 +129,9 @@
char* mBuffer;
size_t mBufferPos;
size_t mBufferSize;
+#if AYLUS_CHANGE_STUN_OVER_TCP
+ size_t mStunLength;
+#endif
WsFrameExtractor mWsFrameExtractor;
static char connectionStates[MAX][32];