This commit is contained in:
Dave Horton
2024-11-14 17:52:34 -05:00
committed by GitHub
parent 4add329102
commit 50b249544e
4 changed files with 95 additions and 117 deletions
+83 -108
View File
@@ -35,16 +35,6 @@ AND vc.service_provider_sid IS NOT NULL
AND vc.is_active = 1 AND vc.is_active = 1
AND sg.inbound = 1`; AND sg.inbound = 1`;
const sqlCarriersForAccountBySid =
`SELECT sg.sip_gateway_sid, sg.voip_carrier_sid, vc.name, vc.account_sid,
vc.application_sid, sg.inbound, sg.outbound, sg.is_active, sg.ipv4, sg.netmask, sg.pad_crypto
FROM sip_gateways sg, voip_carriers vc, accounts acc
WHERE acc.account_sid = ?
AND vc.account_sid = acc.account_sid
AND vc.is_active = 1
AND sg.inbound = 1
AND sg.voip_carrier_sid = vc.voip_carrier_sid`;
const sqlAccountByRealm = 'SELECT * from accounts WHERE sip_realm = ? AND is_active = 1'; const sqlAccountByRealm = 'SELECT * from accounts WHERE sip_realm = ? AND is_active = 1';
const sqlAccountBySid = 'SELECT * from accounts WHERE account_sid = ?'; const sqlAccountBySid = 'SELECT * from accounts WHERE account_sid = ?';
const sqlApplicationBySid = 'SELECT * from applications WHERE application_sid = ?'; const sqlApplicationBySid = 'SELECT * from applications WHERE application_sid = ?';
@@ -273,115 +263,100 @@ module.exports = (srf, logger) => {
/* no match, so fall through */ /* no match, so fall through */
} }
if (isDotDecimal && process.env.JAMBONES_HOSTING) { /* find all carrier entries that have an inbound gateway matching the source IP */
if (!process.env.SBC_ACCOUNT_SID) return failure; const [gw] = await pp.query(sqlSelectAllGatewaysForSP);
logger.debug({gw}, `checking gateways for source address ${req.source_address}`);
/* look for carrier only within that account */ let matches = gw
const [r] = await pp.query(sqlCarriersForAccountBySid, .sort((a, b) => b.netmask - a.netmask)
[process.env.SBC_ACCOUNT_SID, req.source_address, req.source_port]); .filter(gatewayMatchesSourceAddress.bind(null, logger, req.source_address))
if (0 === r.length) return failure; .map((gw) => {
const service_provider_sid = await getSPForAccount(process.env.SBC_ACCOUNT_SID); return {
return { voip_carrier_sid: gw.voip_carrier_sid,
fromCarrier: true, name: gw.name,
gateway: r[0], service_provider_sid: gw.service_provider_sid,
account_sid: process.env.SBC_ACCOUNT_SID, account_sid: gw.account_sid,
service_provider_sid application_sid: gw.application_sid,
}; pad_crypto: gw.pad_crypto
};
});
/* remove duplicates, winnow down to voip_carriers, not gateways */
if (matches.length > 1) {
matches = [...new Set(matches.map(JSON.stringify))].map(JSON.parse);
} }
else { logger.debug({matches}, `matches for source address ${req.source_address}`);
/* find all carrier entries that have an inbound gateway matching the source IP */ if (matches.length) {
const [gw] = await pp.query(sqlSelectAllGatewaysForSP); /* we have one or more matches. Now check for one with a provisioned phone number matching the DID */
let matches = gw const vc_sids = matches.map((m) => `'${m.voip_carrier_sid}'`).join(',');
.sort((a, b) => b.netmask - a.netmask) const sql = `SELECT * FROM phone_numbers WHERE number = '${did}' AND voip_carrier_sid IN (${vc_sids})`;
.filter(gatewayMatchesSourceAddress.bind(null, logger, req.source_address)) logger.debug({matches, sql, did, vc_sids}, 'looking up DID');
.map((gw) => {
return {
voip_carrier_sid: gw.voip_carrier_sid,
name: gw.name,
service_provider_sid: gw.service_provider_sid,
account_sid: gw.account_sid,
application_sid: gw.application_sid,
pad_crypto: gw.pad_crypto
};
});
/* remove duplicates, winnow down to voip_carriers, not gateways */
if (matches.length > 1) {
matches = [...new Set(matches.map(JSON.stringify))].map(JSON.parse);
}
if (matches.length) {
/* we have one or more matches. Now check for one with a provisioned phone number matching the DID */
const vc_sids = matches.map((m) => `'${m.voip_carrier_sid}'`).join(',');
const sql = `SELECT * FROM phone_numbers WHERE number = '${did}' AND voip_carrier_sid IN (${vc_sids})`;
logger.debug({matches, sql, did, vc_sids}, 'looking up DID');
const [r] = await pp.query(sql); const [r] = await pp.query(sql);
if (0 === r.length) { if (0 === r.length) {
/* came from a provisioned carrier, but the dialed number is not provisioned. /* came from a provisioned carrier, but the dialed number is not provisioned.
check if we have an account with default routing of that carrier to an application check if we have an account with default routing of that carrier to an application
*/ */
const accountLevelGateways = matches.filter((m) => m.account_sid && m.application_sid); const accountLevelGateways = matches.filter((m) => m.account_sid && m.application_sid);
if (accountLevelGateways.length > 1) { if (accountLevelGateways.length > 1) {
logger.info({accounts: accountLevelGateways.map((m) => m.account_sid)}, logger.info({accounts: accountLevelGateways.map((m) => m.account_sid)},
'multiple accounts have added this carrier with default routing -- cannot determine which to use');
return {
fromCarrier: true,
error: 'Multiple accounts are attempting to default route this carrier'
};
}
else if (accountLevelGateways.length === 1) {
const [accounts] = await pp.query('SELECT * from accounts where account_sid = ?',
[accountLevelGateways[0].account_sid]);
return {
fromCarrier: true,
gateway: accountLevelGateways[0],
service_provider_sid: accountLevelGateways[0].service_provider_sid,
account_sid: accountLevelGateways[0].account_sid,
application_sid: accountLevelGateways[0].application_sid,
account: accounts[0]
};
}
else {
/* check if we only have a single account, otherwise we have no
- way of knowing which account this is for
*/
const [r] = await pp.query('SELECT count(*) as count from accounts where service_provider_sid = ?',
[matches[0].service_provider_sid]);
if (r[0].count === 0 || r[0].count > 1) return {fromCarrier: true};
else {
const [accounts] = await pp.query('SELECT * from accounts where service_provider_sid = ?',
[matches[0].service_provider_sid]);
return {
fromCarrier: true,
gateway: matches[0],
service_provider_sid: accounts[0].service_provider_sid,
account_sid: accounts[0].account_sid,
account: accounts[0]
};
}
}
}
else if (r.length > 1) {
logger.info({r},
'multiple accounts have added this carrier with default routing -- cannot determine which to use'); 'multiple accounts have added this carrier with default routing -- cannot determine which to use');
return { return {
fromCarrier: true, fromCarrier: true,
error: 'Multiple accounts are attempting to route the same phone number from the same carrier' error: 'Multiple accounts are attempting to default route this carrier'
}; };
} }
else if (accountLevelGateways.length === 1) {
/* we have a route for this phone number and carrier combination */ const [accounts] = await pp.query('SELECT * from accounts where account_sid = ?',
const gateway = matches.find((m) => m.voip_carrier_sid === r[0].voip_carrier_sid); [accountLevelGateways[0].account_sid]);
const [accounts] = await pp.query(sqlAccountBySid, [r[0].account_sid]); return {
assert(accounts.length); fromCarrier: true,
gateway: accountLevelGateways[0],
service_provider_sid: accountLevelGateways[0].service_provider_sid,
account_sid: accountLevelGateways[0].account_sid,
application_sid: accountLevelGateways[0].application_sid,
account: accounts[0]
};
}
else {
/* check if we only have a single account, otherwise we have no
- way of knowing which account this is for
*/
const [r] = await pp.query('SELECT count(*) as count from accounts where service_provider_sid = ?',
[matches[0].service_provider_sid]);
if (r[0].count === 0 || r[0].count > 1) return {fromCarrier: true};
else {
const [accounts] = await pp.query('SELECT * from accounts where service_provider_sid = ?',
[matches[0].service_provider_sid]);
return {
fromCarrier: true,
gateway: matches[0],
service_provider_sid: accounts[0].service_provider_sid,
account_sid: accounts[0].account_sid,
account: accounts[0]
};
}
}
}
else if (r.length > 1) {
logger.info({r},
'multiple accounts have added this carrier with default routing -- cannot determine which to use');
return { return {
fromCarrier: true, fromCarrier: true,
gateway, error: 'Multiple accounts are attempting to route the same phone number from the same carrier'
service_provider_sid: accounts[0].service_provider_sid,
account_sid: r[0].account_sid,
application_sid: r[0].application_sid,
account: accounts[0]
}; };
} }
/* we have a route for this phone number and carrier combination */
const gateway = matches.find((m) => m.voip_carrier_sid === r[0].voip_carrier_sid);
const [accounts] = await pp.query(sqlAccountBySid, [r[0].account_sid]);
assert(accounts.length);
return {
fromCarrier: true,
gateway,
service_provider_sid: accounts[0].service_provider_sid,
account_sid: r[0].account_sid,
application_sid: r[0].application_sid,
account: accounts[0]
};
} }
return failure; return failure;
}; };
+6 -3
View File
@@ -19,7 +19,8 @@ values ('f4e1848d-3ff8-40eb-b9c1-30e1ef053f94','ed649e33-e771-403a-8c99-1780eabb
insert into account_products(account_product_sid, account_subscription_sid, product_sid,quantity) insert into account_products(account_product_sid, account_subscription_sid, product_sid,quantity)
values ('f23ff996-6534-4aba-8666-4b347391eca2', 'f4e1848d-3ff8-40eb-b9c1-30e1ef053f94', 'c4403cdb-8e75-4b27-9726-7d8315e3216d', 10); values ('f23ff996-6534-4aba-8666-4b347391eca2', 'f4e1848d-3ff8-40eb-b9c1-30e1ef053f94', 'c4403cdb-8e75-4b27-9726-7d8315e3216d', 10);
insert into voip_carriers (voip_carrier_sid, name, account_sid) values ('287c1452-620d-4195-9f19-c9814ef90d78', 'westco', 'ed649e33-e771-403a-8c99-1780eabbc803'); insert into voip_carriers (voip_carrier_sid, name, account_sid, service_provider_sid)
values ('287c1452-620d-4195-9f19-c9814ef90d78', 'westco', 'ed649e33-e771-403a-8c99-1780eabbc803', '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0');
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound) insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound)
values ('124a5339-c62c-4075-9e19-f4de70a96597', '287c1452-620d-4195-9f19-c9814ef90d78', '172.38.0.20', true, true); values ('124a5339-c62c-4075-9e19-f4de70a96597', '287c1452-620d-4195-9f19-c9814ef90d78', '172.38.0.20', true, true);
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, port, inbound, outbound) insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, port, inbound, outbound)
@@ -42,7 +43,8 @@ insert into account_products(account_product_sid, account_subscription_sid, prod
values ('92f137f7-4bc3-4157-b096-6817e54b1874', '73bbcc5d-512f-4cea-8535-9a6e3d2bd19d', 'c4403cdb-8e75-4b27-9726-7d8315e3216d', 0); values ('92f137f7-4bc3-4157-b096-6817e54b1874', '73bbcc5d-512f-4cea-8535-9a6e3d2bd19d', 'c4403cdb-8e75-4b27-9726-7d8315e3216d', 0);
insert into account_limits(account_limits_sid, account_sid, category, quantity) values('a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d', 'd7cc37cb-d152-49ef-a51b-485f6e917089', 'voice_call_session', 0); insert into account_limits(account_limits_sid, account_sid, category, quantity) values('a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d', 'd7cc37cb-d152-49ef-a51b-485f6e917089', 'voice_call_session', 0);
insert into voip_carriers (voip_carrier_sid, name, account_sid) values ('9b1abdc7-0220-4964-bc66-32b5c70cd9ab', 'westco', 'd7cc37cb-d152-49ef-a51b-485f6e917089'); insert into voip_carriers (voip_carrier_sid, name, account_sid, service_provider_sid)
values ('9b1abdc7-0220-4964-bc66-32b5c70cd9ab', 'westco', 'd7cc37cb-d152-49ef-a51b-485f6e917089', '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0');
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound) insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound)
values ('12f401d9-cbb1-49e5-bd33-cefbca0badc3', '9b1abdc7-0220-4964-bc66-32b5c70cd9ab', '172.38.0.20', true, true); values ('12f401d9-cbb1-49e5-bd33-cefbca0badc3', '9b1abdc7-0220-4964-bc66-32b5c70cd9ab', '172.38.0.20', true, true);
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, port, inbound, outbound) insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, port, inbound, outbound)
@@ -52,7 +54,8 @@ values ('1401eb72-0daf-4471-aba6-038a0a2587b3', '9b1abdc7-0220-4964-bc66-32b5c70
insert into applications (application_sid, name, account_sid, call_hook_sid, call_status_hook_sid) insert into applications (application_sid, name, account_sid, call_hook_sid, call_status_hook_sid)
values ('3b43e39f-4346-4218-8434-a53130e8be49', 'test', 'ee9d7d49-b3e4-4fdb-9d66-661149f717e8', '90dda62e-0ea2-47d1-8164-5bd49003476c', '4d7ce0aa-5ead-4e61-9a6b-3daa732218b1'); values ('3b43e39f-4346-4218-8434-a53130e8be49', 'test', 'ee9d7d49-b3e4-4fdb-9d66-661149f717e8', '90dda62e-0ea2-47d1-8164-5bd49003476c', '4d7ce0aa-5ead-4e61-9a6b-3daa732218b1');
insert into voip_carriers (voip_carrier_sid, name, account_sid, application_sid) values ('999c1452-620d-4195-9f19-c9814ef90d78', 'customer PBX', 'ee9d7d49-b3e4-4fdb-9d66-661149f717e8', '3b43e39f-4346-4218-8434-a53130e8be49'); insert into voip_carriers (voip_carrier_sid, name, account_sid, application_sid, service_provider_sid)
values ('999c1452-620d-4195-9f19-c9814ef90d78', 'customer PBX', 'ee9d7d49-b3e4-4fdb-9d66-661149f717e8', '3b43e39f-4346-4218-8434-a53130e8be49', '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0');
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound) insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound)
values ('888a5339-c62c-4075-9e19-f4de70a96597', '999c1452-620d-4195-9f19-c9814ef90d78', '172.38.0.21', true, false); values ('888a5339-c62c-4075-9e19-f4de70a96597', '999c1452-620d-4195-9f19-c9814ef90d78', '172.38.0.21', true, false);
+4 -4
View File
@@ -25,7 +25,7 @@
<send retrans="500"> <send retrans="500">
<![CDATA[ <![CDATA[
INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0 INVITE sip:16173333456@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch] Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number] From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
To: sut <sip:[service]@[remote_ip]:[remote_port]> To: sut <sip:[service]@[remote_ip]:[remote_port]>
@@ -33,7 +33,7 @@
CSeq: 1 INVITE CSeq: 1 INVITE
Contact: sip:sipp@[local_ip]:[local_port] Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70 Max-Forwards: 70
Subject: Performance Test Subject: uac-no-3pcc
Content-Type: application/sdp Content-Type: application/sdp
Content-Length: 0 Content-Length: 0
@@ -49,13 +49,13 @@
<send> <send>
<![CDATA[ <![CDATA[
ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0 ACK sip:16173333456@[remote_ip]:[remote_port] SIP/2.0
[last_Via] [last_Via]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number] From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param] To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
Call-ID: [call_id] Call-ID: [call_id]
CSeq: 1 ACK CSeq: 1 ACK
Subject: uac-device-unknown-user Subject: uac-no-3pcc
Content-Length: 0 Content-Length: 0
]]> ]]>
+2 -2
View File
@@ -34,7 +34,7 @@ test('incoming call tests', async(t) => {
obj = await getJSON('http://127.0.0.1:3050/system-health'); obj = await getJSON('http://127.0.0.1:3050/system-health');
t.ok(obj.calls === 0, 'HTTP GET /system-health works (health check)') t.ok(obj.calls === 0, 'HTTP GET /system-health works (health check)')
await sippUac('uac-late-media.xml', '172.38.0.30'); await sippUac('uac-late-media.xml', '172.38.0.20');
t.pass('incoming call with no SDP packet is rejected with a 488'); t.pass('incoming call with no SDP packet is rejected with a 488');
await sippUac('uac-pcap-carrier-success.xml', '172.38.0.20'); await sippUac('uac-pcap-carrier-success.xml', '172.38.0.20');
@@ -72,7 +72,7 @@ test('incoming call tests', async(t) => {
await waitFor(12); await waitFor(12);
const res = await queryCdrs({account_sid: 'ed649e33-e771-403a-8c99-1780eabbc803'}); const res = await queryCdrs({account_sid: 'ed649e33-e771-403a-8c99-1780eabbc803'});
//console.log(`cdrs: ${JSON.stringify(res)}`); //console.log(`cdrs: ${JSON.stringify(res)}`);
t.ok(8 === res.total, 'successfully wrote 8 cdrs for calls'); t.ok(7 === res.total, 'successfully wrote 8 cdrs for calls');
srf.disconnect(); srf.disconnect();
t.end(); t.end();