Re: [reSIProcate] Resiprocate/DUM assert hit when rearrenged/lost packets received
Hello all,
We still have this problem and I still can't solve it unfortunately :(
I have created a barebones testcase that reproduces the scenarios.
The attached sipp scenario XMLs should be run like:
./sipp -i 127.0.0.1 -p 12010 -sf refer100.xml
or
./sipp -i 127.0.0.1 -p 12010 -sf refer.xml
and run the BasicCall from resip/dum/test patched with the attached
diff. This test app has only one leg, the client leg in my original
post, and I simulated the BYE from the "A" leg with end() in the
onNewSubscriptionFromRefer(). The BasicCall app will crash and produce
the stacktrace I described below.
Please take a look!
TIA
br
Szo
On 2016-11-11 11:41, Szokovacs Robert wrote:
> Hi all,
>
> We have found a situation where a malicious third party possibly can
> crash the resiprocate based application by carefully rearranging SIP
> packets.
>
> We have the following setup: the resiprocate-based B2BUA receives the
> incoming call, calls the application server on an other leg, which,
> after some processing, REFERs the call towards it's final destination.
>
> Relevant packet flow:
>
> 1, A leg -> INVITE -> B2BUA
>
> 2, A leg <- 100 <- B2BUA
>
> 3, A leg <- 200OK <- B2BUA
>
> 4, B2BUA -> INVITE -> AppServer
>
> 5, B2BUA <- 100 <- AppServer
>
> 6, B2BUA <- 200OK <- AppServer
>
> 7, B2BUA -> ACK -> AppServer
>
> 8, B2BUA <- REFER <- AppServer
>
> 9, B2BUA -> 202 -> AppServer
>
> Etc, etc.
>
>
> In our situation packet #6 got lost and for reasons not important here
> the AppServer doesn't wait for ACK (#7) before sending the #8 REFER, #9
> is 491 instead of 202. All this is fine and correct behaviour; the
> problem manifests when the A leg sends BYE, causing our B2BUA to end the
> B leg too (bye calling AppDialogSet::end(), which in turn calls
> DialogSet::end() ), before #6 was retransmitted and received. Upon
> receiving the BYE, our app crashed:
>
> #16 in resip::Dialog::cancel (this=<optimized out>) at Dialog.cxx:341
>
> line 338: void
> Dialog::cancel()
> {
> resip_assert(mType == Invitation);
> ClientInviteSession* uac =
> dynamic_cast<ClientInviteSession*>(mInviteSession);
> resip_assert (uac);
> uac->cancel();
> line 345: }
>
> #17 in resip::DialogSet::end (this=0x874a27) at DialogSet.cxx:987
>
> line 983: for (DialogMap::iterator it = mDialogs.begin(); it !=
> mDialogs.end(); it++)
> {
> try
> {
> it->second->cancel();
> }
> catch (UsageUseException& e)
> {
> InfoLog(<< "Caught: " << e);
> }
> line 993: }
>
>
> Further investigation uncovered an other situation, when both #5 and #6
> is missing and not retransmitted, we hit a different assert, when the
> timeout generates the internal 408 response:
>
> #3 in __GI___assert_fail (assertion=0x875e85 "mDialogs.empty()",
> file=0x85b510 "DialogSet.cxx", line=352, function=0x8768c0 "void
> resip::DialogSet::dispatch(const resip::SipMessage&)") at assert.c:103
> #4 in resip::DialogSet::dispatch (this=0x7efec001f8d0, msg=...) at
> DialogSet.cxx:352
>
> line 350: if (mState == WaitingToEnd)
> {
> resip_assert(mDialogs.empty());
> if (msg.isResponse())
> line 354: {
>
> #5 in resip::DialogUsageManager::processResponse (this=<optimized out>,
> response=...) at DialogUsageManager.cxx:2173
> #6 in resip::DialogUsageManager::incomingProcess (this=0x7efefa6690c0,
> msg=...) at DialogUsageManager.cxx:1680
> #7 in resip::DialogUsageManager::internalProcess (this=0x7efefa6690c0,
> msg=...) at DialogUsageManager.cxx:1486
> #8 in resip::DialogUsageManager::process (this=0x7efefa6690c0,
> mutex=<optimized out>) at DialogUsageManager.cxx:1710
>
>
> What common in these scenarios is that the DialogSet has unexpected
> Dialogs hanging around (in the wrong state in the first case, existing
> at all in the second). We think the root of the problem is that after
> DUM sends the 491 response to the wayward REFER, it should get rid of
> the corresponding Dialog, but for some reason, doesn't. We don't see
> where would it fit naturally to do it, so we have no patch proposal yet,
> please comment, advise!
>
> Thanks in advance!
>
> br
>
> Szo
>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<scenario name="">
<recv request="INVITE">
<action>
<ereg regexp="sip:.*[^>]" search_in="hdr" header="Contact:" check_it="true" assign_to="_contact" />
<ereg regexp=".*" search_in="hdr" header="From: " check_it="true" assign_to="_from" />
<ereg regexp=".*" search_in="hdr" header="To: " check_it="true" assign_to="_to" />
</action>
</recv>
<send>
<![CDATA[
REFER [$_contact] SIP/2.0
Via: SIP/2.0/UDP [local_ip]:[local_port];branch=[branch]
From: [$_to]
To: [$_from]
[last_Call-ID:]
[last_Expires:]
Contact: sip:sipp@[local_ip]:[local_port]
CSeq: 12 REFER
Refer-To: sip:0123456789@internal
Expires: 3600
Max-Forwards: 70
User-Agent: SEMS Call Control
B2bua-Note: Call-Control;level=123
Content-Length: 0
]]>
</send>
<recv response="202"> </recv>
</scenario>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<scenario name="">
<recv request="INVITE">
<action>
<ereg regexp="sip:.*[^>]" search_in="hdr" header="Contact:" check_it="true" assign_to="_contact" />
<ereg regexp=".*" search_in="hdr" header="From: " check_it="true" assign_to="_from" />
<ereg regexp=".*" search_in="hdr" header="To: " check_it="true" assign_to="_to" />
</action>
</recv>
<send>
<![CDATA[
SIP/2.0 100 Trying
[last_Via:]
[last_From:]
[last_To:]
[last_Call-ID:]
[last_CSeq:]
Contact: sip:sipp@[local_ip]:[local_port]
Content-Length: 0
]]>
</send>
<send>
<![CDATA[
REFER [$_contact] SIP/2.0
Via: SIP/2.0/UDP [local_ip]:[local_port];branch=[branch]
From: [$_to]
To: [$_from]
[last_Call-ID:]
[last_Expires:]
Contact: sip:sipp@[local_ip]:[local_port]
CSeq: 12 REFER
Refer-To: sip:0123456789@internal
Expires: 3600
Max-Forwards: 70
User-Agent: SEMS Call Control
B2bua-Note: Call-Control;level=123
Content-Length: 0
]]>
</send>
<recv response="202"> </recv>
</scenario>
diff --git a/resip/dum/test/BasicCall.cxx b/resip/dum/test/BasicCall.cxx
index 304dc2e..16d0526 100644
--- a/resip/dum/test/BasicCall.cxx
+++ b/resip/dum/test/BasicCall.cxx
@@ -17,6 +17,7 @@
#include "resip/dum/AppDialog.hxx"
#include "resip/dum/AppDialogSet.hxx"
#include "resip/dum/AppDialogSetFactory.hxx"
+#include "resip/dum/DefaultServerReferHandler.hxx"
#include "rutil/Log.hxx"
#include "rutil/Logger.hxx"
#include "rutil/Random.hxx"
@@ -90,7 +91,7 @@ public:
// Generic InviteSessionHandler
-class TestInviteSessionHandler : public InviteSessionHandler, public ClientRegistrationHandler, public OutOfDialogHandler
+class TestInviteSessionHandler : public InviteSessionHandler, public ClientRegistrationHandler, public OutOfDialogHandler, public DefaultServerReferHandler
{
public:
Data name;
@@ -209,6 +210,12 @@ class TestInviteSessionHandler : public InviteSessionHandler, public ClientRegis
cout << name << ": InviteSession-onRefer - " << msg.brief() << endl;
}
+ virtual void onNewSubscriptionFromRefer(ServerSubscriptionHandle ssh, const SipMessage &msg)
+ {
+ cout << name << ": onNewSubscriptionFromRefer - " << msg.brief() << endl;
+ ssh->getAppDialogSet().get()->end();
+ }
+
virtual void onReferAccepted(InviteSessionHandle, ClientSubscriptionHandle, const SipMessage& msg)
{
cout << name << ": InviteSession-onReferAccepted - " << msg.brief() << endl;
@@ -444,6 +451,9 @@ class TestUas : public TestInviteSessionHandler
cout << name << ": Sending 180 response." << endl;
mSis = sis;
sis->provisional(180);
+/* NameAddr referTo;
+ CallId cid;
+ sis->refer(referTo, cid);*/
}
virtual void onTerminated(InviteSessionHandle, InviteSessionHandler::TerminatedReason reason, const SipMessage* msg)
@@ -608,6 +618,7 @@ main (int argc, char** argv)
TestUac uac;
dumUac->setInviteSessionHandler(&uac);
+ dumUac->addServerSubscriptionHandler("refer", &uac);
dumUac->setClientRegistrationHandler(&uac);
dumUac->addOutOfDialogHandler(OPTIONS, &uac);
@@ -627,91 +638,30 @@ main (int argc, char** argv)
dumUac->getMasterProfile()->setDefaultFrom(uacAor);
dumUac->getMasterProfile()->addSupportedMethod(INFO);
dumUac->getMasterProfile()->addSupportedMethod(MESSAGE);
+ dumUac->getMasterProfile()->addSupportedMethod(REFER);
dumUac->getMasterProfile()->addSupportedMimeType(INFO, PlainContents::getStaticType());
dumUac->getMasterProfile()->addSupportedMimeType(MESSAGE, PlainContents::getStaticType());
dumUac->getMasterProfile()->setDefaultRegistrationTime(70);
- //set up UAS
- SipStack stackUas;
- DialogUsageManager* dumUas = new DialogUsageManager(stackUas);
- stackUas.addTransport(UDP, 12010);
- stackUas.addTransport(TCP, 12010);
+ uac.registered = true;
- SharedPtr<MasterProfile> uasMasterProfile(new MasterProfile);
- std::auto_ptr<ClientAuthManager> uasAuth(new ClientAuthManager);
- dumUas->setMasterProfile(uasMasterProfile);
- dumUas->setClientAuthManager(uasAuth);
-
- if(doReg)
- {
- dumUas->getMasterProfile()->setDigestCredential(uasAor.uri().host(), uasAor.uri().user(), uasPasswd);
- }
- if(useOutbound)
- {
- dumUas->getMasterProfile()->setOutboundProxy(outboundUri);
- dumUas->getMasterProfile()->addSupportedOptionTag(Token(Symbols::Outbound));
- }
-
- dumUas->getMasterProfile()->setDefaultFrom(uasAor);
- dumUas->getMasterProfile()->addSupportedMethod(INFO);
- dumUas->getMasterProfile()->addSupportedMethod(MESSAGE);
- dumUas->getMasterProfile()->addSupportedMimeType(INFO, PlainContents::getStaticType());
- dumUas->getMasterProfile()->addSupportedMimeType(MESSAGE, PlainContents::getStaticType());
- dumUas->getMasterProfile()->setDefaultRegistrationTime(70);
-
- time_t bHangupAt = 0;
- TestUas uas(&bHangupAt);
- dumUas->setClientRegistrationHandler(&uas);
- dumUas->setInviteSessionHandler(&uas);
- dumUas->addOutOfDialogHandler(OPTIONS, &uas);
-
- auto_ptr<AppDialogSetFactory> uas_dsf(new testAppDialogSetFactory);
- dumUas->setAppDialogSetFactory(uas_dsf);
-
- if (doReg)
- {
- SharedPtr<SipMessage> regMessage = dumUas->makeRegistration(uasAor, new testAppDialogSet(*dumUac, "UAS(Registration)"));
- cout << "Sending register for Uas: " << endl << regMessage << endl;
- dumUas->send(regMessage);
- }
- else
- {
- uas.registered = true;
- }
- if (doReg)
- {
- SharedPtr<SipMessage> regMessage = dumUac->makeRegistration(uacAor, new testAppDialogSet(*dumUac, "UAC(Registration)"));
- cout << "Sending register for Uac: " << endl << regMessage << endl;
- dumUac->send(regMessage);
- }
- else
- {
- uac.registered = true;
- }
-
bool finishedTest = false;
bool stoppedRegistering = false;
bool startedCallFlow = false;
bool hungup = false;
- TestShutdownHandler uasShutdownHandler("UAS");
TestShutdownHandler uacShutdownHandler("UAC");
- while (!(uasShutdownHandler.dumShutDown && uacShutdownHandler.dumShutDown))
+ while (!uacShutdownHandler.dumShutDown)
{
if (!uacShutdownHandler.dumShutDown)
{
stackUac.process(50);
while(dumUac->process());
}
- if (!uasShutdownHandler.dumShutDown)
- {
- stackUas.process(50);
- while(dumUas->process());
- }
- if (!(uas.done && uac.done))
+ if (!uac.done)
{
- if (uas.registered && uac.registered && !startedCallFlow)
+ if (uac.registered && !startedCallFlow)
{
if (!startedCallFlow)
{
@@ -721,23 +671,14 @@ main (int argc, char** argv)
}
// Kick off call flow by sending an OPTIONS request then an INVITE request from the UAC to the UAS
- cout << "UAC: Sending Options Request to UAS." << endl;
- dumUac->send(dumUac->makeOutOfDialogRequest(uasAor, OPTIONS, new testAppDialogSet(*dumUac, "UAC(OPTIONS)"))); // Should probably add Allow, Accept, Accept-Encoding, Accept-Language and Supported headers - but this is fine for testing/demonstration
+ //cout << "UAC: Sending Options Request to UAS." << endl;
+ //dumUac->send(dumUac->makeOutOfDialogRequest(uasAor, OPTIONS, new testAppDialogSet(*dumUac, "UAC(OPTIONS)"))); // Should probably add Allow, Accept, Accept-Encoding, Accept-Language and Supported headers - but this is fine for testing/demonstration
cout << "UAC: Sending Invite Request to UAS." << endl;
dumUac->send(dumUac->makeInviteSession(uasAor, uac.mSdp, new testAppDialogSet(*dumUac, "UAC(INVITE)")));
}
}
- // Check if we should hangup yet
- if (bHangupAt!=0)
- {
- if (time(NULL)>bHangupAt && !hungup)
- {
- hungup = true;
- uas.hangup();
- }
- }
}
else
{
@@ -745,11 +686,9 @@ main (int argc, char** argv)
{
finishedTest = true;
stoppedRegistering = true;
- dumUas->shutdown(&uasShutdownHandler);
dumUac->shutdown(&uacShutdownHandler);
if ( doReg )
{
- uas.registerHandle->stopRegistering();
uac.registerHandle->stopRegistering();
}
}
@@ -758,7 +697,6 @@ main (int argc, char** argv)
// OK to delete DUM objects now
delete dumUac;
- delete dumUas;
cout << "!!!!!!!!!!!!!!!!!! Successful !!!!!!!!!! " << endl;
#if defined(WIN32) && defined(_DEBUG) && defined(LEAK_CHECK)