From 50b249544e7c137f660f0f2fadc777957a784ce4 Mon Sep 17 00:00:00 2001 From: Dave Horton Date: Thu, 14 Nov 2024 17:52:34 -0500 Subject: [PATCH] fix #180 (#181) --- lib/db-utils.js | 191 +++++++++++++----------------- test/db/populate-test-data.sql | 9 +- test/scenarios/uac-late-media.xml | 8 +- test/sip-tests.js | 4 +- 4 files changed, 95 insertions(+), 117 deletions(-) diff --git a/lib/db-utils.js b/lib/db-utils.js index 6a09354..9b492a3 100644 --- a/lib/db-utils.js +++ b/lib/db-utils.js @@ -35,16 +35,6 @@ AND vc.service_provider_sid IS NOT NULL AND vc.is_active = 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 sqlAccountBySid = 'SELECT * from accounts WHERE account_sid = ?'; const sqlApplicationBySid = 'SELECT * from applications WHERE application_sid = ?'; @@ -273,115 +263,100 @@ module.exports = (srf, logger) => { /* no match, so fall through */ } - if (isDotDecimal && process.env.JAMBONES_HOSTING) { - if (!process.env.SBC_ACCOUNT_SID) return failure; - - /* look for carrier only within that account */ - const [r] = await pp.query(sqlCarriersForAccountBySid, - [process.env.SBC_ACCOUNT_SID, req.source_address, req.source_port]); - if (0 === r.length) return failure; - const service_provider_sid = await getSPForAccount(process.env.SBC_ACCOUNT_SID); - return { - fromCarrier: true, - gateway: r[0], - account_sid: process.env.SBC_ACCOUNT_SID, - service_provider_sid - }; + /* find all carrier entries that have an inbound gateway matching the source IP */ + const [gw] = await pp.query(sqlSelectAllGatewaysForSP); + logger.debug({gw}, `checking gateways for source address ${req.source_address}`); + let matches = gw + .sort((a, b) => b.netmask - a.netmask) + .filter(gatewayMatchesSourceAddress.bind(null, logger, req.source_address)) + .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); } - else { - /* find all carrier entries that have an inbound gateway matching the source IP */ - const [gw] = await pp.query(sqlSelectAllGatewaysForSP); - let matches = gw - .sort((a, b) => b.netmask - a.netmask) - .filter(gatewayMatchesSourceAddress.bind(null, logger, req.source_address)) - .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'); + logger.debug({matches}, `matches for source address ${req.source_address}`); + 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); - if (0 === r.length) { - /* 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 - */ - const accountLevelGateways = matches.filter((m) => m.account_sid && m.application_sid); - if (accountLevelGateways.length > 1) { - 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}, + const [r] = await pp.query(sql); + if (0 === r.length) { + /* 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 + */ + const accountLevelGateways = matches.filter((m) => m.account_sid && m.application_sid); + if (accountLevelGateways.length > 1) { + 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 route the same phone number from the same carrier' + error: 'Multiple accounts are attempting to default route this carrier' }; } - - /* 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); + 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'); 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] + error: 'Multiple accounts are attempting to route the same phone number from the same carrier' }; } + + /* 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; }; diff --git a/test/db/populate-test-data.sql b/test/db/populate-test-data.sql index 6d88b03..4f1446c 100644 --- a/test/db/populate-test-data.sql +++ b/test/db/populate-test-data.sql @@ -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) 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) 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) @@ -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); 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) 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) @@ -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) 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) values ('888a5339-c62c-4075-9e19-f4de70a96597', '999c1452-620d-4195-9f19-c9814ef90d78', '172.38.0.21', true, false); diff --git a/test/scenarios/uac-late-media.xml b/test/scenarios/uac-late-media.xml index 19f80ca..8b96729 100644 --- a/test/scenarios/uac-late-media.xml +++ b/test/scenarios/uac-late-media.xml @@ -25,7 +25,7 @@ ;tag=[call_number] To: sut @@ -33,7 +33,7 @@ CSeq: 1 INVITE Contact: sip:sipp@[local_ip]:[local_port] Max-Forwards: 70 - Subject: Performance Test + Subject: uac-no-3pcc Content-Type: application/sdp Content-Length: 0 @@ -49,13 +49,13 @@ ;tag=[pid]SIPpTag09[call_number] To: [service] [peer_tag_param] Call-ID: [call_id] CSeq: 1 ACK - Subject: uac-device-unknown-user + Subject: uac-no-3pcc Content-Length: 0 ]]> diff --git a/test/sip-tests.js b/test/sip-tests.js index d0bba60..8560bbd 100644 --- a/test/sip-tests.js +++ b/test/sip-tests.js @@ -34,7 +34,7 @@ test('incoming call tests', async(t) => { obj = await getJSON('http://127.0.0.1:3050/system-health'); 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'); await sippUac('uac-pcap-carrier-success.xml', '172.38.0.20'); @@ -72,7 +72,7 @@ test('incoming call tests', async(t) => { await waitFor(12); const res = await queryCdrs({account_sid: 'ed649e33-e771-403a-8c99-1780eabbc803'}); //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(); t.end();