UNPKG

jssip

Version:

The Javascript SIP library

186 lines (185 loc) 5.92 kB
"use strict"; const Logger = require('./Logger'); const JsSIP_C = require('./Constants'); const SIPMessage = require('./SIPMessage'); const Utils = require('./Utils'); const logger = new Logger('sanityCheck'); // Checks for requests and responses. const all = [minimumHeaders]; // Checks for requests. const requests = [ rfc3261_8_2_2_1, rfc3261_16_3_4, rfc3261_18_3_request, rfc3261_8_2_2_2, ]; // Checks for responses. const responses = [rfc3261_8_1_3_3, rfc3261_18_3_response]; // local variables. let message; let ua; let transport; module.exports = (m, u, t) => { message = m; ua = u; transport = t; for (const check of all) { if (check() === false) { return false; } } if (message instanceof SIPMessage.IncomingRequest) { for (const check of requests) { if (check() === false) { return false; } } } else if (message instanceof SIPMessage.IncomingResponse) { for (const check of responses) { if (check() === false) { return false; } } } // Everything is OK. return true; }; /* * Sanity Check for incoming Messages * * Requests: * - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme * - _rfc3261_16_3_4_ Receive a Request already sent by us * Does not look at via sent-by but at jssip_id, which is inserted as * a prefix in all initial requests generated by the ua * - _rfc3261_18_3_request_ Body Content-Length * - _rfc3261_8_2_2_2_ Merged Requests * * Responses: * - _rfc3261_8_1_3_3_ Multiple Via headers * - _rfc3261_18_3_response_ Body Content-Length * * All: * - Minimum headers in a SIP message */ // Sanity Check functions for requests. function rfc3261_8_2_2_1() { if (message.s('to').uri.scheme !== 'sip') { reply(416); return false; } } function rfc3261_16_3_4() { if (!message.to_tag) { if (message.call_id.substr(0, 5) === ua.configuration.jssip_id) { reply(482); return false; } } } function rfc3261_18_3_request() { const len = Utils.str_utf8_length(message.body); const contentLength = message.getHeader('content-length'); if (len < contentLength) { reply(400); return false; } } function rfc3261_8_2_2_2() { const fromTag = message.from_tag; const call_id = message.call_id; const cseq = message.cseq; let tr; // Accept any in-dialog request. if (message.to_tag) { return; } // INVITE request. if (message.method === JsSIP_C.INVITE) { // If the branch matches the key of any IST then assume it is a retransmission // and ignore the INVITE. // TODO: we should reply the last response. if (ua._transactions.ist[message.via_branch]) { return false; } // Otherwise check whether it is a merged request. else { for (const transaction in ua._transactions.ist) { if (Object.prototype.hasOwnProperty.call(ua._transactions.ist, transaction)) { tr = ua._transactions.ist[transaction]; if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) { reply(482); return false; } } } } } // Non INVITE request. // If the branch matches the key of any NIST then assume it is a retransmission // and ignore the request. // TODO: we should reply the last response. else if (ua._transactions.nist[message.via_branch]) { return false; } // Otherwise check whether it is a merged request. else { for (const transaction in ua._transactions.nist) { if (Object.prototype.hasOwnProperty.call(ua._transactions.nist, transaction)) { tr = ua._transactions.nist[transaction]; if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) { reply(482); return false; } } } } } // Sanity Check functions for responses. function rfc3261_8_1_3_3() { if (message.getHeaders('via').length > 1) { logger.debug('more than one Via header field present in the response, dropping the response'); return false; } } function rfc3261_18_3_response() { const len = Utils.str_utf8_length(message.body), contentLength = message.getHeader('content-length'); if (len < contentLength) { logger.debug('message body length is lower than the value in Content-Length header field, dropping the response'); return false; } } // Sanity Check functions for requests and responses. function minimumHeaders() { const mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via']; for (const header of mandatoryHeaders) { if (!message.hasHeader(header)) { logger.debug(`missing mandatory header field : ${header}, dropping the response`); return false; } } } // Reply. function reply(status_code) { const vias = message.getHeaders('via'); let to; let response = `SIP/2.0 ${status_code} ${JsSIP_C.REASON_PHRASE[status_code]}\r\n`; for (const via of vias) { response += `Via: ${via}\r\n`; } to = message.getHeader('To'); if (!message.to_tag) { to += `;tag=${Utils.newTag()}`; } response += `To: ${to}\r\n`; response += `From: ${message.getHeader('From')}\r\n`; response += `Call-ID: ${message.call_id}\r\n`; response += `CSeq: ${message.cseq} ${message.method}\r\n`; response += '\r\n'; transport.send(response); }