Avtomatik təminat Yealink T19 + dinamik ünvan kitabçası

Mən bu şirkətdə işləməyə gələndə artıq məndə IP qurğuların bəzi verilənlər bazası, ulduz işarəsi olan bir neçə server və FreeBPX formasında yamaq var idi. Bundan əlavə, analoq PBX Samsung IDCS500 paralel işləyirdi və ümumiyyətlə şirkətdə əsas rabitə sistemi idi; IP telefoniya yalnız satış şöbəsi üçün işləyirdi. Və hər şey belə bişirməkdə davam edəcəkdi, amma gözəl günlərin birində hamının İP telefoniyaya keçməsi barədə fərman verildi, son tarixlər razılaşdırıldı, avadanlıq alındı ​​və müəssisəni 21-ci əsrə köçürmək planı həyata keçirilməyə başladı.
Belə bir vəziyyətdə narahat olmağa başlayan ilk şey, bir şəkildə idarə edilməli olan sürətlə artan telefon dəstləri, ikinci çox narahat edən şey telefon kitabçası idi. Əgər Endpoint Manager bizə birincisində (yeri gəlmişkən, FreePBX-in ən son versiyalarından çıxarılıb) kömək edə bilsəydi, kitabla bağlı bəzi suallar yarandı:

  • Birincisi, istifadəçilərin yeri/axıcılığı daim dəyişdikdə onun dəqiqliyini necə təmin etmək olar?
  • İkincisi, telefonları necə tamamilə şəxsiyyətsizləşdirmək olar. Və hər dəfə əlaqə adını doldurmursunuz?

Problem maraqlı idi, həlli çox çəkmədi. İndi tam siyahı verəcəyəm, sonra sıra ilə baxacağıq.

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')

Proqram istifadəçinin kompüterində işləyir və kompüterin telefon vasitəsilə şəbəkəyə qoşulması şərti ilə işləyir, çünki Yealink T19 şlüz kimi işləyə bilməz.

Birincisi, bunun bağlı olub olmadığını başa düşməliyik? və bizim telefonumuzda hansı mac və ip var.

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

Burada biz scapy çərçivəsinin sniff funksiyasından istifadə edirik, onun köməyi ilə əvvəlcədən müəyyən edilmiş udp paketini alırıq, 70 saniyə gözlədik və heç nə tutmasaq, çıxırıq.

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

Sonra, cihazın həqiqətən Yealink olduğundan əmin oluruq və lazımi dəyərləri (ip və mac) qaytarırıq.

Xüsusi sorğudan istifadə edərək, telefonda cari hesabı tapırıq. Bunun üçün cari konfiqurasiya telefondan endirilir və təhlil edilir.

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

Bu hesabın parolunu tapın. Bunun üçün asterisk.sip cədvəlinə və oradakı məlumat sahəsinə müraciət edirik.

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

Yaxşı, son mərhələ üçün biz ldap AD-yə qoşuluruq və funksiya vasitəsilə əldə edilən sAMAccountName-dən istifadə edirik. getpass.getuser() cari istifadəçinin cn kodunu götürün (adətən istifadəçinin tam adını ehtiva edir).

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

Verilənlər bazasında əvvəlcədən yaradılmış cədvələ qoşuluruq (onu orada yaratdım) və öyrəndiyimiz hər şeyi daxil edirik, yəni: ip, mac, istifadəçi adı.

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()

Biz burada dayana bilərik, çünki biz artıq dinamik ünvan kitabçası yaratmışıq, soruşa bilərsiniz, amma mən daha da irəli getdim və burada cihazların avtomatik təmin edilməsini əlavə etdim.

Bunun üçün əvvəlcədən konfiqurasiya edilmiş tftp serverindən şablon konfiqurasiyası endirilir, biz orada dəyişikliklərimizi edirik və onu mac.cfg olaraq saxlayırıq. Yəni, Yealink üçün iki növ konfiqurasiya var, biri qlobaldır, ikincisi isə konkret telefona aiddir və mac_phone.cfg formasında olmalıdır.

Fayldakı bütün dəyişikliklərdən və onu yenidən tftp serverinə saxladıqdan sonra biz telefona cihazı təmin etmək və yenidən yükləmək əmrini veririk.

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')

Cihazı yenidən işə saldıqdan sonra telefonun ekranında tam adımızı + verilənlər bazası şəklində həmişə düzgün doldurulmuş ünvan kitabçasını alırıq, sonra yalnız məzmunu dinamik şəkildə göstərmək üçün XML və bir az PHP əlavə etmək qalır. Belə misallar çoxdur, hətta YEALINK-in özündə belə nümunələr var.

PS: Daha geniş miqyaslılıq üçün əsas parametrləri (dəyişənləri) ayrıca fayla köçürə bilərsiniz.

Mənbə: www.habr.com

Добавить комментарий