O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Dipping to MNP DB

384 visualizações

Publicada em

Recently as per the initiative of BTRC all telecom operator shifted to the Mobile Number Portability (MNP) platform. In this scenario, any subscriber can change operator without changing his/her current number including the prefix. In order to do that, there has been established a central MNP database. All operators require to up to date with this database and perform query for each of their outbound call. MNP database will give the information of current recipient and donor operator routing code. Operator requires to query the current recipient routing code before sending call to the ICX. In this paper, authors target is to give suggestion how to keep this local MNP database up to date and synchronize with the central database. Further, how this local database can be used for dipping to generate outbound calls to current recipient operator using opensource SIP Server and Session Border Controller (SBC). To perform that, authors shows how to use asterisk as dipping server using AGI scripting and it will be used as Back to Back User Agent (B2BUA). Also shows how kamailio an open source SIP Express Router (SER) can be used to perform MNP dipping to MySQL database. Finally, after the implementation of MNP service although calling service is working fine but most ported numbers did not receive the SMS specially OTP. Therefore, on these context author's shows how to create secure post API to perform the dipping to local MNP database from SMS gateway to connect to the original routing number before sending the SMS to client. Here, API will return the current recipient, donor code and routing number to send SMS as JSON data format against a normal cell phone number.

Publicada em: Internet
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Dipping to MNP DB

  1. 1. Dipping to MNP DB: An Approach of using SIP Server and Secure API’s for OTP Service Muhammad Morshed Alam E-mail: morshed@amberit.com.bd Amber IT Ltd.
  2. 2. Mobile Number Portability • Customers can keep their number including the prefix even through switch from one operator to another • Telecom operator gets extra RN along with (CC+RN) • Telecom operator should up to date with the central porting database • Porting DB gives the information of current recipient, donor and number range holder RN including the porting activation timestamp • Several methods to get the porting update from central DB: SOAP message, SFTP based on hour/ daily basis • IPTSP operators get the daily porting DB in xml format • Dialed number RN should be checking before generating call or routing call to ICX
  3. 3. MNP Call Query Types Query Type Description All Call Query Before every call, obtain the routing number corresponding to the called number from a centralized DB. Query on Release Route calls normally (To NRH). If a remote operator returns a redirection response without any destination specified, obtain the routing number corresponding to the called number from a centralized DB Call Drop back Route calls normally. A remote operator may provide a routing number to use to route the call to the current recipient operator Onward Routing Route calls normally. A remote operator may choose to re-route the call by itself or provide a routing number.
  4. 4. Preparing The Recipe
  5. 5. LMNP DB Format: +---------------+-------------------------------+-------------+---------+-------+------------+--------------+ | number | portedDate | recipientRC | donorRC | nrhRC | numberType | portedAction | +---------------+-------------------------------+-------------+---------+-------+------------+--------------+ | 88018XXXXXXXX| 2018-10-01T11:00:01.436+06:00 | 91 | 81 | 81 | MOBILE | INSERT | | 88016XXXXXXXX| 2018-10-01T09:54:41.283+06:00 | 91 | 81 | 81 | MOBILE | INSERT | | 88019XXXXXXXX| 2018-10-01T10:42:41.416+06:00 | 81 | 91 | 91 | MOBILE | INSERT | | 88015XXXXXXXX| 2018-10-01T11:37:53.274+06:00 | 81 | 91 | 51 | MOBILE | UPDATE | +---------------+-------------------------------+-------------+---------+-------+------------+--------------+ Operator CC+RN Code Grameen (013, 017) 88071 Robi/Airtel (016, 018) 88081 Teletalk (015) 88051 Banglalink (014, 019) 88091 nrhRC: Number Range Holder Ported Action: INSERT, UPDATE, DELETE Table-1 Operator Routing Code (RN)
  6. 6. Call Flow in MNP Scenario:
  7. 7. Daily Ported Database Content in XML or CSV XML Format: <ported> <number>88017XXXXXXXX</number> <portedDate>2019-03-14T09:34:36.798+06:00</portedDate> <recipientRC>81</recipientRC> <donorRC>71</donorRC> <nrhRC>71</nrhRC> <numberType>MOBILE</numberType> <portedAction>INSERT</portedAction> </ported> <ported> <number>88017XXXXXXXX</number> <portedDate>2019-03-14T12:46:41.249+06:00</portedDate> <recipientRC>71</recipientRC> <donorRC>81</donorRC> <nrhRC>71</nrhRC> <numberType>MOBILE</numberType> <portedAction>DELETE</portedAction> </ported> <ported> <number>88015XXXXXXXX</number> <portedDate>2019-03-14T11:56:31.378+06:00</portedDate> <recipientRC>81</recipientRC> <donorRC>91</donorRC> <nrhRC>51</nrhRC> <numberType>MOBILE</numberType> <portedAction>UPDATE</portedAction> </ported> In CSV Format: number,portedDate,recipientRC,donorRC,nrhRC,numberType,portedAction 88017XXXXXXXX,2019-03-14T09:34:36.798+06:00,81,71,71,MOBILE,INSERT 88017XXXXXXXX,2019-03-14T14:14:11.096+06:00,71,81,71,MOBILE,DELETE 88015XXXXXXXX,2019-03-14T11:56:31.378+06:00,81,91,51,MOBILE,UPDATE To get ported csv file for previous date: curl -s -X POST -F "api=apikey" "http://sipix.bdix.net/mnp/" > /root/mnpdb/$(date -dy +%Y-%m-%d).csv To get ported csv file for a specific date: curl -s -X POST -F "api=apikey" -F "date=2018-12-22" -F "type=csv" "http://sipix.bdix.net/mnp/" > /root/mnpdb/2018-12- 22.csv To get ported xml file for a specific date: curl -s -X POST -F "api=apikey" -F "date=2018-12-22" -F "type=xml" "http://sipix.bdix.net/mnp/" > /root/mnpdb/2018-12- 22.xml
  8. 8. Ported Daily Database File Structure & Keeping Up to Date Database GET the Daily ported File Ported action=update Save all update number in an Array Run “for each loop” for all update number to delete the previous insert value Ported action= insert Ported action= delete Keep and execute insert data operation as it is Execute DELETE Query in DB Insert Query to DB Ported Action=?
  9. 9. Inserting the Daily Ported Data to Database Call the BDIX MNP POST API using curl to get data file in CSV or XML format for previous date Count the ported Data for log from the csv file INSERT all data in csv file to MySQL DB After successful entry give message to logger
  10. 10. #! /bin/bash curl -s -X POST -F "api=yourapikey" "http://sipix.bdix.net/mnp/" > /root/mnpdb/$(date -dy +%Y-%m-%d).csv echo $(date -dy +%Y-%m-%d).csv file downloaded successfully sleep 5 lnc=$(wc -l /root/mnpdb/$(date -dy +%Y-%m-%d).csv) echo "ported numbers: $lnc" prday=$(date --date="-1 day"| awk '{print $1}') echo "porting day:$prday" sleep 5 mysql -u root –ptest1234 --local_infile=1 mnpdb2 -e "LOAD DATA LOCAL INFILE '/root/mnpdb/$(date -dy +%Y-%m-%d).csv' INTO TABLE mnpdb2tb FIELDS TERMINATED BY ',' enclosed by '"'" mysql -u root -pamber.lom mnpdb2 -e "DELETE FROM mnpdb2tb WHERE number='number'" echo $(date -dy +%Y-%m-%d).csv file uploaded to DB successfully echo "---------------------------------------------------------------------" Inserting the Daily Ported Data to Database Run this script in cron: 10 0 * * * /root/mnpdb/mnpdbfullportedcsv.sh >> /root/mnpdb/mnpdbuploader.log 1 2
  11. 11. Logger Output root@mnpbd:~/mnpdb# tail -n 15 mnpdbuploader.log 2019-04-20.csv file downloaded successfully ported numbers: 2462 /root/mnpdb/2019-04-20.csv porting day:Sat 2019-04-20.csv file uploaded to DB successfully --------------------------------------------------------------------- 2019-04-21.csv file downloaded successfully ported numbers: 2050 /root/mnpdb/2019-04-21.csv porting day:Sun 2019-04-21.csv file uploaded to DB successfully --------------------------------------------------------------------- 2019-04-22.csv file downloaded successfully ported numbers: 0 /root/mnpdb/2019-04-22.csv porting day:Mon 2019-04-22.csv file uploaded to DB successfully ---------------------------------------------------------------------
  12. 12. Delete the Daily Returned List from Database (Ported Action=DELETE) Count the size of daily DELETE list to keep log for each portedAction='DELETE’ as per the entry time stamp User ported data will be removed and call will routed to the original NRH operator Execute the DELETE SQL query for portedAction=‘DELETE’ To keep the DB up to date Execute SQL query to export the daily returned DELETE entry for log purpose to a CSV file and store to a directory
  13. 13. Delete the Daily Returned List from Database (Ported Action=DELETE) #! /bin/bash del_No=$(mysql -uroot –ptest123 mnpdb2 -e "SELECT COUNT(*) as DELETE_MNP_No FROM mnpdb2tb WHERE portedAction='DELETE'") echo "$del_No of date: $(date +"%d-%m-%y")" echo "exporting number of date $(date +"%d-%m-%y") at /tmp directory" mysql -uroot –ptest123 <<EOF use mnpdb2; SELECT * FROM mnpdb2tb WHERE portedAction='DELETE' INTO OUTFILE '/tmp/mnp_del_entry_$(date +"%d-%m-%y").csv' FIELDS TERMINATED BY ', 'ENCLOSED BY '"' LINES TERMINATED BY 'n’; DELETE FROM mnpdb2tb WHERE portedAction='DELETE'; EOF echo "deleting of those delete entry of date $(date +"%d-%m-%y") echo "all task done successfully" echo "----------------------------------------------" Run script in cron: 15 0 * * * /root/mnpdb/delentry.sh >> /root/mnpdb/delmnp.log
  14. 14. Logger Output root@mnpbd:~/mnpdb# tail -f delmnp.log ---------------------------------------------- DELETE_MNP_No 78 of date: 14-03-19 exporting number of date 14-03-19 at /tmp directory deleting of those delete entry of date 14-03-19 all task done successfully ---------------------------------------------- DELETE_MNP_No 84 of date: 15-03-19 exporting number of date 15-03-19 at /tmp directory deleting of those delete entry of date 15-03-19 all task done successfully ----------------------------------------------
  15. 15. Keeping MNP Database Up to Date for Ported Action=UPDATE SQL Query for all ported number portedAction=UPDATE Save update number value in an array Ported DB will be up to date and routed to the recent recipient operator as per successful Dipping For each value in array execute DELETE query to remove the previous ported INSERT Query CASE: Subscriber number like 017XXXXXXXX, ported to operator A: INSERT Action in MNP DB After 90 days later change the porting to another different operator (B): UPDATE Action in MNP DB To keep up to date the DB we should remove the previous INSERT Query and route the call to recent Recipient operator
  16. 16. Sample CODE for updating porting database for ported ACTION= “UPDATE” <?php $dbserver = "127.0.0.1"; $dbusername = "root"; $dbpassword = “test123"; $dbname = "mnpdb2"; $conn = new mysqli($dbserver, $dbusername, $dbpassword, $dbname); if ($conn->connect_error) { die("connection error"); } else { //echo "database connection successful."; } $sql = "SELECT number FROM mnpdb2tb where portedAction='UPDATE'"; $result = $conn->query($sql); $updno = array(); $i=0; if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { $updno[$i]= $row["number"]; $i++; } } else { echo "0 results"; } foreach ($updno as $value) { echo "$value n"; $sql2 = "DELETE FROM mnpdb2tb WHERE number=".$value." AND portedAction='INSERT'"; $result2 = $conn->query($sql2); } $conn->close(); ?> php /root/mnpdb/updatemnpnumber.php >>/root/mnpdb/updateno.log Connect To DB Query for all update entry And save it to an array DELETE previous INSERT Data for each value in UPDATE Array
  17. 17. AGI Script to GET RN CODE Against a Dialed Number #!/usr/bin/python import agi import MySQLdb import sys agi = agi.AGI() MYSQL_HOST=‘1.2.3.4' MYSQL_USER='root' MYSQL_PASS=‘test123' MYSQL_DB='mnpdb2' did=sys.argv[1] mysql = MySQLdb.connect(host=MYSQL_HOST , user=MYSQL_USER, passwd=MYSQL_PASS, db=MYSQL_DB) db = mysql.cursor() db.execute("""SELECT recipientRC, donorRC FROM mnpdb2tb WHERE number='%(did)s' """ %vars()) result = db.fetchall() db.close() reprn = int(result[0][0]) dnrrn= int(result[0][1]) agi.set_variable("RCRN", reprn) agi.set_variable("DNRN", dnrrn) User Dial to a number ,${CALLERID(dnid) Query to DB for ported validation If it finds match, it will return $recipientRC, $donorRC Script mnpdb.py will return this variable as $RCRN, $DNRN that is current recipient and donor respectively for that dialed pattern set $RCRN before the dialed number. CC+RN+Rest Subcriber Number =880811755518856 Billing Database > ICXSET AGI Variable SQL Query MySQL Connection
  18. 18. MNP Dipping Flow Soft-Switch / Billing DB Free-SBCSIP UAC Local MNP DB and Dipping Server (Master) Asterisk 302 SIP Redirect Return the recipient RN and Dialing SIP URI Media Gateway ICXSlave DB MySQL Asterisk Real Time Replication 1 2 3 4 5 6
  19. 19. Asterisk extension.conf Dial plan: exten => _88071X.,1,NoOp(${CALLERID(dnid)}) same => n,Set(CALLERID(dnid)=880${CALLERID(dnid):5:14}) same => n,NoOp(${CALLERID(dnid)}) same => n,AGI(mnpdb.py,${CALLERID(dnid)}) ;sending the dialed number to mnp db for query RN same => n,NoOp(${RCRN}) same => n,NoOp(${DNRN}) same => n,GotoIf($[${LEN(${RCRN})} == 0]?ln:yo) ;validating the length of recipient RN to determine number available in db or not same => n(ln),Set(CALLERID(dnid)=88071${CALLERID(dnid):3:12}) ;set the RN of the NRH if not found same => n,NoOp(${CALLERID(dnid)}) same => n,NoOp(${EXTEN}) same => n,NoOp(${CALLERID(num)}) same => n,Set(CALLERID(num)=9611${CALLERID(num):5:10}) same => n,GotoIf($[${LEN(${CALLERID(num)})} != 10]?not10digits) same => n,Dial(${MNHICXDT}/${CALLERID(dnid)},${DIAL_TIMEOUT},tT${DIAL_OPTIONS}) ;send the call to ICX if not found same => n,NoOp(${CHANNEL} DAN ${DIALSTATUS}) same => n,NoOp(${HANGUPCAUSE} DAN ${DIALSTATUS}) same => n,Hangup() same => n(yo),Set(CALLERID(dnid)=880${RCRN}${CALLERID(dnid):3:12}) ;set recipient RN as CC+RN if number is found in database same => n,NoOp(${CALLERID(dnid)}) same => n,Dial(${MNPSBCSIPT}/${CALLERID(dnid)},${DIAL_TIMEOUT},tT${DIAL_OPTIONS}) ;send the call to billing db and route to ICX same => n,NoOp(${CHANNEL} DAN ${DIALSTATUS}) same => n,NoOp(${HANGUPCAUSE} DAN ${DIALSTATUS}) same => n,Hangup() same => n(not10digits),Hangup() 1 2 3 4 5 6
  20. 20. AGI DEBUG FROM CLI: -- Executing [8807117XXXXXXXXX@default:1] NoOp("SIP/sipamber-00006bc8", "8807117XXXXXXXXX") in new stack -- Executing [8807117XXXXXXXXX@default:2] Set("SIP/sipamber-00006bc8", "CALLERID(dnid)=88017XXXXXXXXX") in new stack -- Executing [8807117XXXXXXXXX@default:3] NoOp("SIP/sipamber-00006bc8", "88017XXXXXXXXX") in new stack -- Executing [8807117XXXXXXXXX@default:4] AGI("SIP/sipswitch-00006bc8", "mnpdb.py,88017XXXXXXXXX") in new stack -- Launched AGI Script /var/lib/asterisk/agi-bin/mnpdb.py <SIP/sipamber-00006bc8>AGI Tx >> agi_request: mnpdb.py <SIP/sipamber-00006bc8>AGI Tx >> agi_channel: SIP/sipswitch-00006bc8 <SIP/sipamber-00006bc8>AGI Tx >> agi_language: en <SIP/sipamber-00006bc8>AGI Tx >> agi_type: SIP <SIP/sipamber-00006bc8>AGI Tx >> agi_uniqueid: 1552723981.54111 <SIP/sipamber-00006bc8>AGI Tx >> agi_version: 1.8.32.1 <SIP/sipamber-00006bc8>AGI Tx >> agi_callerid: 09611000038 <SIP/sipamber-00006bc8>AGI Tx >> agi_calleridname: 09611000038 <SIP/sipamber-00006bc8>AGI Tx >> agi_callingpres: 0 <SIP/sipamber-00006bc8>AGI Tx >> agi_callingani2: 0 <SIP/sipamber-00006bc8>AGI Tx >> agi_callington: 0 <SIP/sipamber-00006bc8>AGI Tx >> agi_callingtns: 0 <SIP/sipamber-00006bc8>AGI Tx >> agi_dnid: 88017XXXXXXXX <SIP/sipamber-00006bc8>AGI Tx >> agi_rdnis: unknown <SIP/sipamber-00006bc8>AGI Tx >> agi_context: mnpdbrt <SIP/sipamber-00006bc8>AGI Tx >> agi_extension: 8807117XXXXXXXXX <SIP/sipamber-00006bc8>AGI Tx >> agi_priority: 4 <SIP/sipamber-00006bc8>AGI Tx >> agi_enhanced: 0.0 <SIP/sipamber-00006bc8>AGI Tx >> agi_accountcode: <SIP/sipamber-00006bc8>AGI Tx >> agi_threadid: 139892327810816 <SIP/sipamber-00006bc8>AGI Tx >> agi_arg_1: 88017XXXXXXXXX <SIP/sipamber-00006bc8>AGI Tx >> <SIP/sipamber-00006bc8>AGI Rx << SET VARIABLE "RCRN" "81" <SIP/sipamber-00006bc8>AGI Tx >> 200 result=1 <SIP/sipamber-00006bc8>AGI Rx << SET VARIABLE "DNRN" "71" <SIP/sipamber-00006bc8>AGI Tx >> 200 result=1 -- <SIP/sipswitch-00006bc8>AGI Script mnpdb.py completed, returning 0 -- Executing [8807117XXXXXXXX@default:5] NoOp("SIP/sipswitch-00006bc8", "81") in new stack -- Executing [8807117XXXXXXXX@default:6] NoOp("SIP/sipswitch-00006bc8", "71") in new stack -- Executing [8807117XXXXXXXX@default:7] GotoIf("SIP/sipswitch-00006bc8", "0?ln:yo") in new stack -- Goto (default,88071XXXXXXXX,18) -- Executing [880711715008415@default:18] Set("SIP/sip-00006bc8", "CALLERID(dnid)=8808117XXXXXXXXX") in new stack -- Executing [880711715008415@default:19] NoOp("SIP/sipswitch-00006bc8", "8808117XXXXXXXXX") in new stack -- Executing [880711715008415@default:20] Dial("SIP/sipswitch-00006bc8", "SIP/sipsbc/8808117XXXXXXXXX,,tT") in new stack == Using SIP RTP TOS bits 184 == Using SIP RTP CoS mark 5 -- Called SIP/sipsbc/8808117XXXXXXXXX 1 2 3 4 5
  21. 21. Inbound Call from Telco to IPTSP Prefix A (Originator): CC+RN+S/N, i.e, 880711755518856, B (Destination): 09611XXXXXX or 16XXX Save the A party CLI with RN (88071) in billing database, then remap the A party CLI as per the original dialing number => 017555518856
  22. 22. SMS Dipping Flow SMS Application Local MNP Database Billing Database Routed to current recipient operator Dipping through API API will return the current recipient code against the dialed number SMS Dipping API: Section-1: API Key post input for authenticity validation Section-2: Connect to the remote MySQL database Section-3: Query to the database based on the dialed number (Post input variable). Bind parameter to Protect SQL Injection Section-4: fetch the query output set as array content Section-5: encode JSON/ XML format to read by the remote application Section-6: decode JSON/ XML and parse output variable as per the requirement 1 2 3
  23. 23. API Input and Output JSON Output If Number Found: { "statuscode":"200OK", "status":"successful", "message":"Number Found in MNP Database", "data":{ "recipientRC":"81", "donorRC":"91", "orgdialno":"8808119XXXXXXXX" } } Input: apikey: yourapikey dailednumber:8801955518856 API URL: https://lnp-dippingsms.amberit.com.bd JSON Output If Number Not Found: { "statuscode":"400Err", "status":"Failed", "message":"Number Not Found In MNP Database" }
  24. 24. POST API For SMS <?php $psapikey = "morshedmnpdbkey"; $apikey=$_POST['apikey']; if ($apikey==$psapikey) { $dbserver = "127.0.0.1"; $dbusername = "root"; $dbpassword = “test123"; $dbname = "mnpdb"; $conn = new mysqli($dbserver, $dbusername, $dbpassword, $dbname); if ($conn->connect_error) { die("connection error"); } else { //echo "database connection successful."; } $dialednumber = $_POST['dialednumber']; $mnpcliquery = $conn->prepare("select recipientRC,donorRC from mnpdb2tb where number=?;"); $mnpcliquery->bind_param("s",$dialednumber); $mnpcliquery->execute(); $mnpcliquery->store_result(); $mnpcliquery->bind_result($recipientRC,$donorRC); $dialedno = substr($dialednumber, 3); if ($mnpcliquery->num_rows > 0) { $mnpcliquery->fetch(); $orgdialno = "880".$recipientRC.$dialedno; $finalOutput = array( "statuscode" => "200OK", "status" => "successful", "message" => "Number Found in MNP Database", "data" => array( "recipientRC" => "$recipientRC", "donorRC" => "$donorRC", "orgdialno" => "$orgdialno" ) ); echo json_encode($finalOutput); } else { $finalOutput = array( "statuscode" => "400Err", "status" => "Failed", "message" => "Number Not Found In MNP Database" ); echo json_encode($finalOutput); } $mnpcliquery->close(); $conn->close(); } else { $finalOutput = array( "statuscode" => "400Err", "status" => "Failed", "message" => "Invalid API key" ); echo json_encode($finalOutput); } ?> API Key Validation Database Connection SQL Query Output If matches Output If not matches Output Wrong API key given
  25. 25. Call The POST API Using curl Command In Shell: # curl -d "apikey=yourapikey&dialednumber=8801839173377" -X POST http://1.2.3.4/mnpdipping-sms-api.php Output JSON: {"statuscode":"200OK","status":"successful","message":"Number Found in MNP Database","data":{"recipientRC":"91","donorRC":"81","orgdialno":"88091183 9173377"}}
  26. 26. POST API Call using Curl / Parsing JSON value that returned by API <?php $dialednumber=$_POST["dialednumber"]; $apikey=$_POST["apikey"]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://1.2.3.4/mnpdipping-sms-api.php"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, true); $data = array( 'apikey' => $apikey, 'dialednumber' => $dialednumber ); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $output = curl_exec($ch); $outputDecoded = json_decode($output); echo $outputDecoded->data->orgdialno; curl_close($ch); ?> In bash script: root@mnpbd# curl -d "apikey=yourapikey&dialednumber=8801839173377" -X POST http://1.2.3.4/postapi.php Output (CC+RN): 880911839173377
  27. 27. Postman test for API response validation: JSON Output: {"statuscode":"200OK","status":"successful","message":"Number Found in MNP Database","data":{"recipientRC":"81","donorRC":"91","orgdialno":"8808119XXXXXXXX"}}
  28. 28. Call A POST API in Asterisk Dial plan using Curl exten => _017X..,1,curl(http://1.2.3.4/postapi.php,apikey=yourapikey&dialednumber=${CALLERID(dnid)}) exten => _017X.,2,Wait(5) exten => _017X.,3,NoOp(CURL-RESPONSE: ${CURL}) If any match found in DB return will be: CC+RN+Subscirber Number=880711755518856
  29. 29. $Questions ?

×