آٹو پروویژننگ ییلنک T19 + ڈائنامک ایڈریس بک

جب میں اس کمپنی کے لیے کام کرنے آیا تھا، میرے پاس پہلے سے ہی IP ڈیوائسز کا کچھ ڈیٹا بیس، ستارے والے کئی سرورز اور FreeBPX کی شکل میں ایک پیچ تھا۔ اس کے علاوہ، ایک analogue PBX Samsung IDCS500 متوازی طور پر کام کرتا تھا اور، عام طور پر، کمپنی کا بنیادی مواصلاتی نظام تھا؛ IP ٹیلی فونی صرف سیلز ڈیپارٹمنٹ کے لیے کام کرتا تھا۔ اور سب کچھ اسی طرح پکتا رہتا، لیکن ایک ٹھیک دن سب کو آئی پی ٹیلی فونی پر منتقل کرنے کا حکم دیا گیا، ڈیڈ لائن پر اتفاق ہوا، آلات خریدے گئے، اور انٹرپرائز کو 21ویں صدی میں منتقل کرنے کے منصوبے پر عمل درآمد شروع ہو گیا۔
ایسی صورت حال میں پہلی چیز جو پریشان ہونے لگتی ہے وہ ہے تیزی سے بڑھتی ہوئی ٹیلی فون سیٹس کی تعداد جسے کسی نہ کسی طرح سنبھالنا ضروری ہے، دوسری چیز جو بہت پریشان کن تھی وہ تھی فون بک۔ اگر اینڈپوائنٹ مینیجر ہماری پہلی مدد کر سکتا ہے (جو ویسے بھی FreePBX کے تازہ ترین ورژنز سے کاٹا گیا تھا) تو کتاب کے ساتھ کچھ سوالات پیدا ہوئے:

  • سب سے پہلے، اس کی درستگی کو کیسے یقینی بنایا جائے جب صارفین کا محل وقوع/رولیت مسلسل تبدیل ہو رہی ہو؟
  • دوم، فون کو مکمل طور پر ذاتی نوعیت کا کیسے بنایا جائے۔ اور ہر بار رابطہ کا نام نہیں بھرتے؟

مسئلہ دلچسپ تھا، حل آنے میں دیر نہیں لگی۔ اب میں مکمل فہرست دوں گا، اور پھر ہم اسے ترتیب سے دیکھیں گے۔

from scapy.all import sniff
from scapy.layers.inet import IP
import mysql.connector
import ldap
import getpass
import tftpy
import requests
import os
import time
from string import replace

def conn_ldap(login):
    ad = ldap.initialize('ldap://***.local')
    ad.simple_bind_s('voip@***.local', 'password')
    basedn = 'OU=IT,DC=***,DC=LOCAL'
    basedn_user = 'OU=***,OU=***,DC=***,DC=LOCAL'
    scope = ldap.SCOPE_SUBTREE
    filterexp = "(&(sAMAccountName=" + login + ")(ObjectClass=person))"
    filterexp2 = "(&(ObjectClass=organizationUnit))"
    attrlist = ['cn']
    attrlist2 = ['OU']
    search = ad.search_s(basedn, scope, filterexp, attrlist)
    adname = search[0][1]['cn'][0].decode('utf-8')
    if adname == ' ':
        search = ad.search_s(basedn_user, scope, filterexp2, attrlist2)
        for i in range(1, len(search)+1):
            group = search[i][1]['ou'][0]
            basedn_user2 = 'OU='+group+','+basedn_user
            search = ad.search_s(basedn_user2, scope, filterexp, attrlist)
            adname = search[0][1]['cn'][0].decode('utf-8')
            if adname != ' ':
                return adname
        adname = search[0][1]['cn'][0].decode('utf-8')
    ad.unbind_s()
    return adname


def tftp_file_change(config,place,adname,current_account,current_account_password):

    client = tftpy.TftpClient("192.168.0.3", 69)
    client.download('template.cfg', place)
    fileread = open(place, 'r')
    line = fileread.readlines()
    fileread.close()
    line[5] = (('account.1.label = ').encode('utf-8') + adname.encode('utf-8') + 'n')
    line[2] = (('account.1.auth_name = ').encode('utf-8') + current_account.encode('utf-8') + 'n')
    line[3] = (('account.1.display_name = ').encode('utf-8') + current_account.encode('utf-8') + 'n')
    line[6] = (('account.1.password = ').encode('utf-8') + current_account_password[0][0] + 'n')
    filewrite = open(place, 'w')
    for i in line:
      filewrite.write(i)
    filewrite.close()
    print place
    print config
    client.upload(config,place)


def get_phone_inform(ipaddr):
    fileconf = requests.get('http://admin:admin@'+ipaddr+'/servlet?phonecfg=get[&accounts=1]')
    conf = fileconf.text.split('|')
    current_account = conf[2]
    return current_account


def sniff_frame():
    pcapf = sniff(count=1, timeout=70, filter="dst host 192.168.0.3 and port 5060")
    if len(pcapf) == 0:
        exit()
    frame = pcapf[0]
    macaddr = frame.src
    print macaddr[:8]
    if macaddr[:8] != '80:5e:c0':
        exit()
    ipaddr = frame[0][IP].src
    return macaddr, ipaddr


def conn_mysql(query,fquery,macaddr,qwery2):
    connect = mysql.connector.connect(host='192.168.0.3', database='voip', user='voip_wr', password='***')
    cursor = connect.cursor()
    cursor.execute(fquery)
    state = cursor.fetchall()
    state = bool(state[0][0])
    if state == True:
        cursor.execute(qwery2)
        connect.commit()
        connect.close()
    else:
        cursor.execute(query)
        connect.commit()
        connect.close()


def check_account(current_account):
    connect = mysql.connector.connect(host='192.168.0.3', database='asterisk', user='voip_wr', password='***')
    cursor = connect.cursor()
    qwery = 'select data from sip where id=' + current_account + ' and keyword="secret";'
    cursor.execute(qwery)
    password = cursor.fetchall()
    if password == ' ':
        exit()
    else:
        return password


if __name__ == '__main__':
    macaddr, ipaddr = sniff_frame()
    current_account = get_phone_inform(ipaddr)
    current_account_password = check_account(current_account)
    macaddr = macaddr.replace(':', '')
    ipaddr = ipaddr.decode('utf-8')
    adname = conn_ldap(getpass.getuser())
    query = 'INSERT INTO station (mac, ip, name, number) VALUES (' + '"' + macaddr + '",' + '"' + ipaddr + '",' + '"' + adname + '",' + '"' + get_phone_inform(ipaddr) + '"' + ')'
    qwery2 = 'UPDATE station SET ip=' + '"' + ipaddr + '"' + ', name=' + '"' + adname + '"' + ', number=' + '"' + get_phone_inform(ipaddr) + '"' + ' WHERE mac=' + '"' + macaddr + '"'
    fquery = 'SELECT EXISTS(SELECT mac FROM voip.station WHERE mac=' + '"' + macaddr + '")'
    query = query.encode('utf-8')
    fquery = fquery.encode('utf-8')
    config = macaddr + '.cfg'
    place = os.path.expanduser("~") + "" + "AppDataLocal" + config
    conn_mysql(query,fquery,macaddr,qwery2)
    tftp_file_change(config,place,adname,current_account,current_account_password)
    requests.get('http://admin:admin@'+ipaddr+'/cgi-bin/ConfigManApp.com?key=AutoP')
    requests.get('http://admin:admin@'+ipaddr+'/cgi-bin/ConfigManApp.com?key=Reboot')

یہ پروگرام صارف کے کمپیوٹر پر چلتا ہے اور کام کرتا ہے بشرطیکہ کمپیوٹر فون کے ذریعے نیٹ ورک سے منسلک ہو، کیونکہ Yealink T19 گیٹ وے کے طور پر کام نہیں کر سکتا۔

سب سے پہلے، ہمیں یہ سمجھنے کی ضرورت ہے کہ آیا یہ منسلک ہے؟ اور ہمارے فون میں کیا میک اور آئی پی ہے۔

def sniff_frame():
    pcapf = sniff(count=1, timeout=70, filter="dst host 192.168.0.3 and port 5060")
    if len(pcapf) == 0:
        exit()
    frame = pcapf[0]
    macaddr = frame.src
    print macaddr[:8]
    if macaddr[:8] != '80:5e:c0':
        exit()
    ipaddr = frame[0][IP].src
    return macaddr, ipaddr

یہاں ہم scapy فریم ورک سے sniff فنکشن استعمال کرتے ہیں، اس کی مدد سے ہمیں پہلے سے طے شدہ udp پیکٹ ملتا ہے، 70 سیکنڈ انتظار کریں اور اگر ہمیں کچھ نہیں پکڑا تو ہم باہر نکل جاتے ہیں۔

count=1, timeout=70, filter="dst host 192.168.0.3 and port 5060"

اگلا، ہم اس بات کو یقینی بناتے ہیں کہ آلہ واقعی ییلنک ہے اور ضروری اقدار (ip اور mac) کو واپس کرتا ہے۔

ایک خصوصی درخواست کا استعمال کرتے ہوئے، ہم فون پر کرنٹ اکاؤنٹ کا پتہ لگاتے ہیں۔ ایسا کرنے کے لیے، موجودہ کنفیگریشن کو فون سے ڈاؤن لوڈ کرکے پارس کیا جاتا ہے۔

def get_phone_inform(ipaddr):
    fileconf = requests.get('http://admin:admin@'+ipaddr+'/servlet?phonecfg=get[&accounts=1]')
    conf = fileconf.text.split('|')
    current_account = conf[2]
    return current_account

اس اکاؤنٹ کا پاس ورڈ معلوم کریں۔ ایسا کرنے کے لیے، ہم asterisk.sip ٹیبل اور اس میں موجود ڈیٹا فیلڈ کا رخ کرتے ہیں۔

def check_account(current_account):
    connect = mysql.connector.connect(host='192.168.0.3', database='asterisk', user='voip_wr', password='***')
    cursor = connect.cursor()
    qwery = 'select data from sip where id=' + current_account + ' and keyword="secret";'
    cursor.execute(qwery)
    password = cursor.fetchall()
    if password == ' ':
        exit()
    else:
        return password

ٹھیک ہے، آخری مرحلے کے لیے ہم ldap AD سے جڑتے ہیں اور فنکشن کے ذریعے حاصل کردہ sAMAccountName کا استعمال کرتے ہیں۔ getpass.getuser() موجودہ صارف کا cn لیں (جس میں عام طور پر صارف کا پورا نام ہوتا ہے)۔

def conn_ldap(login):
    ad = ldap.initialize('ldap://***.local')
    ad.simple_bind_s('voip@***.local', 'password')
    basedn = 'OU=***,DC=***,DC=LOCAL'
    basedn_user = 'OU=***,OU=***,DC=***,DC=LOCAL'
    scope = ldap.SCOPE_SUBTREE
    filterexp = "(&(sAMAccountName=" + login + ")(ObjectClass=person))"
    filterexp2 = "(&(ObjectClass=organizationUnit))"
    attrlist = ['cn']
    attrlist2 = ['OU']
    search = ad.search_s(basedn, scope, filterexp, attrlist)
    adname = search[0][1]['cn'][0].decode('utf-8')
    if adname == ' ':
        search = ad.search_s(basedn_user, scope, filterexp2, attrlist2)
        for i in range(1, len(search)+1):
            group = search[i][1]['ou'][0]
            basedn_user2 = 'OU='+group+','+basedn_user
            search = ad.search_s(basedn_user2, scope, filterexp, attrlist)
            adname = search[0][1]['cn'][0].decode('utf-8')
            if adname != ' ':
                return adname
        adname = search[0][1]['cn'][0].decode('utf-8')
    ad.unbind_s()
    return adname

ہم ڈیٹا بیس میں پہلے سے تیار کردہ ٹیبل سے جڑتے ہیں (میں نے اسے وہاں بنایا تھا) اور ہر وہ چیز درج کرتے ہیں جو ہم نے سیکھا، یعنی: ip, mac, username۔

def conn_mysql(query,fquery,macaddr,qwery2):
    connect = mysql.connector.connect(host='192.168.0.3', database='voip', user='voip_wr', password='***')
    cursor = connect.cursor()
    cursor.execute(fquery)
    state = cursor.fetchall()
    state = bool(state[0][0])
    if state == True:
        cursor.execute(qwery2)
        connect.commit()
        connect.close()
    else:
        cursor.execute(query)
        connect.commit()
        connect.close()

ہم یہاں رک سکتے ہیں، کیونکہ ہم پہلے ہی ایک متحرک ایڈریس بک بنا چکے ہیں، آپ پوچھ سکتے ہیں، لیکن میں نے مزید آگے بڑھ کر یہاں آلات کی خودکار فراہمی شامل کی۔

ایسا کرنے کے لیے، پہلے سے تشکیل شدہ tftp سرور سے ایک ٹیمپلیٹ کنفیگریشن ڈاؤن لوڈ کی جاتی ہے، جس میں ہم اپنی تبدیلیاں کرتے ہیں اور اسے mac.cfg کے بطور محفوظ کرتے ہیں۔ یعنی، ییلنک کے لیے دو قسم کی کنفیگریشن ہیں، ایک عالمی ہے، اور دوسری ایک مخصوص فون پر لاگو ہوتی ہے اور mac_phone.cfg کی شکل میں ہونی چاہیے۔

فائل میں تمام تبدیلیوں اور اسے واپس tftp سرور میں محفوظ کرنے کے بعد، ہم فون کو ڈیوائس کو پروویژن اور ریبوٹ کرنے کا حکم دیتے ہیں۔

def tftp_file_change(config,place,adname,current_account,current_account_password):

    client = tftpy.TftpClient("192.168.0.3", 69)
    client.download('template.cfg', place)
    fileread = open(place, 'r')
    line = fileread.readlines()
    fileread.close()
    line[5] = (('account.1.label = ').encode('utf-8') + adname.encode('utf-8') + 'n')
    line[2] = (('account.1.auth_name = ').encode('utf-8') + current_account.encode('utf-8') + 'n')
    line[3] = (('account.1.display_name = ').encode('utf-8') + current_account.encode('utf-8') + 'n')
    line[6] = (('account.1.password = ').encode('utf-8') + current_account_password[0][0] + 'n')
    filewrite = open(place, 'w')
    for i in line:
      filewrite.write(i)
    filewrite.close()
    print place
    print config
    client.upload(config,place)

requests.get('http://admin:admin@'+ipaddr+'/cgi-bin/ConfigManApp.com?key=AutoP')
requests.get('http://admin:admin@'+ipaddr+'/cgi-bin/ConfigManApp.com?key=Reboot')

ڈیوائس کو ریبوٹ کرنے کے بعد، ہمیں فون کی اسکرین پر اپنا پورا نام ملتا ہے + ایک ڈیٹا بیس کی شکل میں ہمیشہ درست طریقے سے بھری ہوئی ایڈریس بک، پھر باقی رہ جاتا ہے کہ XML اور تھوڑا پی ایچ پی شامل کریں تاکہ مواد کو متحرک طور پر ظاہر کیا جا سکے۔ ایسی بہت سی مثالیں ہیں، یہاں تک کہ خود YEALINK بھی ان کے پاس ہے۔

PS: زیادہ اسکیل ایبلٹی کے لیے، آپ مین سیٹنگز (متغیرات) کو الگ فائل میں منتقل کر سکتے ہیں۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں