mirror of
https://github.com/jambonz/sbc-outbound.git
synced 2026-01-25 02:07:59 +00:00
bugfix #8: maintain Call-ID when sending follow-up INVITE with credentials to endpoint that challenged with 401/407
This commit is contained in:
6
app.js
6
app.js
@@ -26,6 +26,12 @@ const {performLcr, lookupAllTeamsFQDNs, lookupAccountBySipRealm} = require('@jam
|
||||
connectionLimit: process.env.JAMBONES_MYSQL_CONNECTION_LIMIT || 10
|
||||
}, logger);
|
||||
srf.locals.dbHelpers = {performLcr, lookupAllTeamsFQDNs, lookupAccountBySipRealm};
|
||||
const {createHash, retrieveHash} = require('@jambonz/realtimedb-helpers')({
|
||||
host: process.env.JAMBONES_REDIS_HOST || 'localhost',
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
}, logger);
|
||||
srf.locals.realtimeDbHelpers = {createHash, retrieveHash};
|
||||
|
||||
const {getRtpEngine} = require('@jambonz/rtpengine-utils')(process.env.JAMBONES_RTPENGINES.split(','), logger, {
|
||||
emitter: srf.locals.stats
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ const {SipError} = require('drachtio-srf');
|
||||
const {parseUri} = require('drachtio-srf');
|
||||
const debug = require('debug')('jambonz:sbc-outbound');
|
||||
|
||||
const makeInviteInProgressKey = (callid) => `sbc-out-iip${callid}`;
|
||||
/**
|
||||
* this is to make sure the outgoing From has the number in the incoming From
|
||||
* and not the incoming PAI
|
||||
@@ -48,6 +49,7 @@ class CallSession extends Emitter {
|
||||
}
|
||||
debug(`got engine: ${JSON.stringify(engine)}`);
|
||||
const {offer, answer, del} = engine;
|
||||
const {createHash, retrieveHash} = this.srf.locals.realtimeDbHelpers;
|
||||
this.offer = offer;
|
||||
this.answer = answer;
|
||||
this.del = del;
|
||||
@@ -127,6 +129,20 @@ class CallSession extends Emitter {
|
||||
while (uris.length) {
|
||||
const uri = uris.shift();
|
||||
const passFailure = 0 === uris.length; // only a single target
|
||||
if (0 === uris.length) {
|
||||
try {
|
||||
const key = makeInviteInProgressKey(this.req.get('Call-ID'));
|
||||
const obj = await retrieveHash(key);
|
||||
if (obj.callId && obj.cseq) {
|
||||
Object.assign(headers, {
|
||||
'Call-ID': obj.callId,
|
||||
'CSeq': `${obj.cseq} INVITE`
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.info({err}, 'Error retrieving iip key');
|
||||
}
|
||||
}
|
||||
debug(`sending INVITE to ${uri} via ${proxy})`);
|
||||
this.logger.info(`sending INVITE to ${uri}`);
|
||||
try {
|
||||
@@ -150,6 +166,18 @@ class CallSession extends Emitter {
|
||||
return response.sdp;
|
||||
}
|
||||
}, {
|
||||
cbRequest: async(err, inv) => {
|
||||
const opts = {
|
||||
callId: inv.get('Call-ID'),
|
||||
cseq: ++inv.getParsedHeader('CSeq').seq
|
||||
};
|
||||
try {
|
||||
const key = makeInviteInProgressKey(this.req.get('Call-ID'));
|
||||
await createHash(key, opts, 5);
|
||||
} catch (err) {
|
||||
this.logger.error({err}, 'Error saving Call-ID/CSeq');
|
||||
}
|
||||
},
|
||||
cbProvisional: (response) => {
|
||||
if (!earlyMedia && [180, 183].includes(response.status) && response.body) earlyMedia = true;
|
||||
}
|
||||
|
||||
798
package-lock.json
generated
798
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -28,18 +28,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.5.1",
|
||||
"@jambonz/realtimedb-helpers": "^0.2.19",
|
||||
"@jambonz/rtpengine-utils": "^0.1.7",
|
||||
"@jambonz/stats-collector": "0.1.1",
|
||||
"debug": "^4.3.1",
|
||||
"drachtio-fn-b2b-sugar": "^0.0.12",
|
||||
"drachtio-srf": "^4.4.40",
|
||||
"drachtio-srf": "^4.4.44",
|
||||
"jambonz-mw-registrar": "^0.1.3",
|
||||
"pino": "^6.7.0",
|
||||
"pino": "^6.8.0",
|
||||
"rtpengine-client": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"blue-tape": "^1.0.0",
|
||||
"eslint": "^7.14.0",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"nyc": "^15.1.0",
|
||||
"tap-spec": "^5.0.0"
|
||||
|
||||
@@ -89,3 +89,13 @@ services:
|
||||
networks:
|
||||
sbc-outbound:
|
||||
ipv4_address: 172.39.0.23
|
||||
|
||||
sip-uri-auth:
|
||||
image: drachtio/sipp:latest
|
||||
command: sipp -sf /tmp/uas-auth.xml
|
||||
volumes:
|
||||
- ./scenarios:/tmp
|
||||
tty: true
|
||||
networks:
|
||||
sbc-outbound:
|
||||
ipv4_address: 172.39.0.24
|
||||
|
||||
167
test/scenarios/uac-sip-uri-auth-success.xml
Normal file
167
test/scenarios/uac-sip-uri-auth-success.xml
Normal file
@@ -0,0 +1,167 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp 'uac' scenario with pcap (rtp) play -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="UAC with media">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:john@172.39.0.24 SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: <sip:john@172.39.0.24>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-sip-uri-auth-success
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="401" auth="true">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:sip:john@172.39.0.24 SIP/2.0
|
||||
[last_Via:]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: <sip:sip:john@jambonz.org>[peer_tag_param]
|
||||
[last_Call-ID:]
|
||||
CSeq: 1 ACK
|
||||
Subject: uac-sip-uri-auth-success
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:john@172.39.0.24 SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]xx
|
||||
To: <sip:john@172.39.0.24>
|
||||
[last_Call-ID:]
|
||||
CSeq: 2 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
[authentication username=foo password=bar]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-sip-uri-auth-success
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="180" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="200">
|
||||
</recv>
|
||||
|
||||
<!-- Packet lost can be simulated in any send/recv message by -->
|
||||
<!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:john@172.39.0.24 SIP/2.0
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
To: <sip:sip:john@jambonz.org>[peer_tag_param]
|
||||
[last_Call-ID:]
|
||||
CSeq: 2 ACK
|
||||
Subject: uac-sip-uri-auth-success
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<!-- Play a pre-recorded PCAP file (RTP stream) -->
|
||||
<nop>
|
||||
<action>
|
||||
<exec play_pcap_audio="pcap/g711a.pcap"/>
|
||||
</action>
|
||||
</nop>
|
||||
|
||||
<!-- Pause briefly -->
|
||||
<pause milliseconds="2000"/>
|
||||
|
||||
<!-- The 'crlf' option inserts a blank line in the statistics report. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
BYE sip:john@172.39.0.24 SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
[last_From:]
|
||||
[last_To:]
|
||||
[last_Call-ID:]
|
||||
CSeq: 3 BYE
|
||||
Max-Forwards: 70
|
||||
Subject: uac-sip-uri-auth-success
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" crlf="true">
|
||||
</recv>
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
|
||||
</scenario>
|
||||
155
test/scenarios/uas-auth.xml
Normal file
155
test/scenarios/uas-auth.xml
Normal file
@@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uas' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic UAS responder">
|
||||
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
|
||||
<!-- are saved and used for following messages sent. Useful to test -->
|
||||
<!-- against stateful SIP proxies/B2BUAs. -->
|
||||
<recv request="INVITE" crlf="true">
|
||||
</recv>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 401 Unauthorized
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
WWW-Authenticate: Digest realm="jambonz.org", nonce="4cdbb733645816512687270b83d2ae5d11e4d9d8"
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv request="ACK"
|
||||
rtd="true"
|
||||
crlf="true">
|
||||
</recv>
|
||||
|
||||
<recv request="INVITE" crlf="true">
|
||||
<action>
|
||||
<verifyauth assign_to="authvalid" username="foo" password="bar" />
|
||||
</action>
|
||||
</recv>
|
||||
<nop hide="true" test="authvalid" next="goodauth" />
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 403 Forbidden
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>;expires=60
|
||||
Content-Type: application/sdp
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv request="ACK" next="endit"
|
||||
rtd="true"
|
||||
crlf="true">
|
||||
</recv>
|
||||
|
||||
<label id="goodauth"/>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 100 Trying
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 200 OK
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[media_ip_type] [media_ip]
|
||||
t=0 0
|
||||
m=audio [media_port] RTP/AVP 0
|
||||
a=rtpmap:0 PCMU/8000
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv request="ACK"
|
||||
optional="true"
|
||||
rtd="true"
|
||||
crlf="true">
|
||||
</recv>
|
||||
|
||||
<recv request="BYE">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 200 OK
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<label id="endit"/>
|
||||
|
||||
<!-- Keep the call open for a while in case the 200 is lost to be -->
|
||||
<!-- able to retransmit it if we receive the BYE again. -->
|
||||
<timewait milliseconds="4000"/>
|
||||
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
|
||||
</scenario>
|
||||
|
||||
@@ -54,6 +54,10 @@ test('sbc-outbound tests', async(t) => {
|
||||
await sippUac('uac-pcap-carrier-success-reinvite.xml');
|
||||
t.pass('successfully handled reinvite during lcr outdial');
|
||||
|
||||
/* invite to sipUri that challenges */
|
||||
await sippUac('uac-sip-uri-auth-success.xml');
|
||||
t.pass('successfully connected to sip uri that requires auth');
|
||||
|
||||
srf.disconnect();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
Reference in New Issue
Block a user