mirror of
https://github.com/jambonz/sbc-inbound.git
synced 2026-07-24 12:51:55 +00:00
c324f0425b
major merge of features from the hosted branch that was created temporarily during the initial launch of jambonz.org
131 lines
4.9 KiB
JavaScript
131 lines
4.9 KiB
JavaScript
const assert = require('assert');
|
|
const CIDRMatcher = require('cidr-matcher');
|
|
const {parseUri} = require('drachtio-srf');
|
|
const {normalizeDID} = require('./utils');
|
|
|
|
const sqlSelectAllCarriersForAccountByRealm =
|
|
`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
|
|
FROM sip_gateways sg, voip_carriers vc, accounts acc
|
|
WHERE acc.sip_realm = ?
|
|
AND vc.account_sid = acc.account_sid
|
|
AND sg.voip_carrier_sid = vc.voip_carrier_sid`;
|
|
|
|
const sqlSelectAllGatewaysForSP =
|
|
`SELECT sg.sip_gateway_sid, sg.voip_carrier_sid, vc.name, vc.service_provider_sid,
|
|
vc.application_sid, sg.inbound, sg.outbound, sg.is_active, sg.ipv4, sg.netmask
|
|
FROM sip_gateways sg, voip_carriers vc
|
|
WHERE sg.voip_carrier_sid = vc.voip_carrier_sid
|
|
AND vc.service_provider_sid IS NOT NULL
|
|
AND vc.is_active = 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
|
|
FROM sip_gateways sg, voip_carriers vc, accounts acc
|
|
WHERE acc.account_sid = ?
|
|
AND vc.account_sid = acc.account_sid
|
|
AND sg.voip_carrier_sid = vc.voip_carrier_sid`;
|
|
|
|
const sqlAccountByRealm = 'SELECT * from accounts WHERE sip_realm = ?';
|
|
const sqlAccountBySid = 'SELECT * from accounts WHERE account_sid = ?';
|
|
|
|
const sqlQueryApplicationByDid = `
|
|
SELECT * FROM phone_numbers
|
|
WHERE number = ?
|
|
AND voip_carrier_sid = ?`;
|
|
|
|
const gatewayMatchesSourceAddress = (source_address, gw) => {
|
|
if (32 === gw.netmask && gw.ipv4 === source_address) return true;
|
|
if (gw.netmask < 32) {
|
|
const matcher = new CIDRMatcher([`${gw.ipv4}/${gw.netmask}`]);
|
|
return matcher.contains(source_address);
|
|
}
|
|
return false;
|
|
};
|
|
|
|
module.exports = (srf, logger) => {
|
|
const {pool} = srf.locals.dbHelpers;
|
|
const pp = pool.promise();
|
|
|
|
const getApplicationForDidAndCarrier = async(req, voip_carrier_sid) => {
|
|
const did = normalizeDID(req.calledNumber);
|
|
|
|
try {
|
|
const [r] = await pp.query(sqlQueryApplicationByDid, [did, voip_carrier_sid]);
|
|
if (0 === r.length) return null;
|
|
return r[0].application_sid;
|
|
} catch (err) {
|
|
logger.error({err}, 'getApplicationForDidAndCarrier');
|
|
}
|
|
};
|
|
|
|
const wasOriginatedFromCarrier = async(req) => {
|
|
const failure = {fromCarrier: false};
|
|
const uri = parseUri(req.uri);
|
|
const isDotDecimal = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(uri.host);
|
|
|
|
if (isDotDecimal) {
|
|
if (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;
|
|
return {fromCarrier: true, gateway: r[0], account_sid: process.env.SBC_ACCOUNT_SID};
|
|
}
|
|
else {
|
|
/* we may have a carrier at the service provider level */
|
|
const [gw] = await pp.query(sqlSelectAllGatewaysForSP);
|
|
const matches = gw.filter(gatewayMatchesSourceAddress.bind(null, req.source_address));
|
|
if (matches.length) {
|
|
/* we have one or more carriers that match. Now we need to find one with a provisioned phone number */
|
|
const vc_sids = matches.map((m) => `'${m.voip_carrier_sid}'`).join(',');
|
|
const did = normalizeDID(req.calledNumber);
|
|
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 carrier, but number is not provisioned */
|
|
return {fromCarrier: true};
|
|
}
|
|
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,
|
|
account_sid: r[0].account_sid,
|
|
application_sid: r[0].application_sid,
|
|
account: accounts[0]
|
|
};
|
|
}
|
|
return failure;
|
|
}
|
|
}
|
|
|
|
/* get all the carriers and gateways for the account owning this sip realm */
|
|
const [gw] = await pp.query(sqlSelectAllCarriersForAccountByRealm, uri.host);
|
|
const selected = gw.find(gatewayMatchesSourceAddress.bind(null, req.source_address));
|
|
if (selected) {
|
|
const [a] = await pp.query(sqlAccountByRealm, uri.host);
|
|
if (0 === a.length) return failure;
|
|
return {
|
|
fromCarrier: true,
|
|
gateway: selected,
|
|
account_sid: a[0].account_sid,
|
|
application_sid: selected.application_sid,
|
|
account: a[0]
|
|
};
|
|
}
|
|
return failure;
|
|
};
|
|
|
|
return {
|
|
wasOriginatedFromCarrier,
|
|
getApplicationForDidAndCarrier
|
|
};
|
|
};
|