Peruntukan automatik Yealink T19 + buku alamat dinamik

Apabila saya datang bekerja untuk syarikat ini, saya sudah mempunyai beberapa pangkalan data peranti IP, beberapa pelayan dengan asterisk dan tampalan dalam bentuk FreeBPX. Di samping itu, analog PBX Samsung IDCS500 berfungsi secara selari dan, secara amnya, merupakan sistem komunikasi utama dalam syarikat; Telefoni IP hanya berfungsi untuk jabatan jualan. Dan segala-galanya akan terus memasak seperti ini, tetapi pada suatu hari dekri telah diberikan untuk memindahkan semua orang ke telefon IP, tarikh akhir telah dipersetujui, peralatan telah dibeli, dan rancangan untuk memindahkan perusahaan ke abad ke-21 mula dilaksanakan.
Perkara pertama yang mula dibimbangkan dalam keadaan sedemikian ialah bilangan set telefon yang semakin meningkat yang perlu diuruskan entah bagaimana, perkara kedua yang sangat membimbangkan ialah buku telefon. Jika Pengurus Titik Akhir boleh membantu kami dengan yang pertama (yang, secara kebetulan, telah dipotong daripada versi terbaharu FreePBX), maka beberapa soalan timbul dengan buku itu:

  • Pertama, bagaimana untuk memastikan ketepatannya apabila lokasi/kecairan pengguna sentiasa berubah?
  • Kedua, cara menyahperibadi telefon sepenuhnya. Dan tidak mengisi nama kenalan setiap kali?

Masalahnya menarik, penyelesaian tidak mengambil masa yang lama untuk tiba. Sekarang saya akan memberikan senarai penuh, dan kemudian kita akan melihatnya mengikut urutan.

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

Program ini berjalan pada komputer pengguna dan berfungsi dengan syarat komputer disambungkan ke rangkaian melalui telefon, memandangkan Yealink T19 tidak boleh berfungsi sebagai pintu masuk.

Pertama, kita perlu memahami sama ada ia bersambung? dan apa mac dan ip telefon kita.

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

Di sini kami menggunakan fungsi sniff dari rangka kerja scapy, dengan bantuannya kami menerima paket udp yang telah ditetapkan, tunggu 70 saat dan jika kami tidak menangkap apa-apa, kami keluar.

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

Seterusnya, kami memastikan bahawa peranti itu memang Yealink dan mengembalikan nilai yang diperlukan (ip dan mac).

Menggunakan permintaan khas, kami mengetahui akaun semasa di telefon. Untuk melakukan ini, konfigurasi semasa dimuat turun dari telefon dan dihuraikan.

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

Ketahui kata laluan untuk akaun ini. Untuk melakukan ini, kami beralih ke jadual asterisk.sip dan medan data di dalamnya.

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

Nah, untuk peringkat akhir kami menyambung ke ldap AD dan menggunakan sAMAccountName yang diperoleh melalui fungsi getpass.getuser() ambil cn pengguna semasa (yang biasanya mengandungi nama penuh pengguna).

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

Kami menyambung ke jadual pra-dicipta dalam pangkalan data (saya menciptanya di sana) dan masukkan semua yang kami pelajari, iaitu: ip, mac, nama pengguna.

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

Kami boleh berhenti di sini, kerana kami telah mencipta buku alamat dinamik, anda mungkin bertanya, tetapi saya pergi lebih jauh dan menambahkan peruntukan automatik peranti di sini.

Untuk melakukan ini, konfigurasi templat dimuat turun dari pelayan tftp yang telah diprakonfigurasikan, di mana kami membuat perubahan dan menyimpannya sebagai mac.cfg. Iaitu, untuk Yealink terdapat dua jenis konfigurasi, satu adalah global, dan yang kedua digunakan untuk telefon tertentu dan hendaklah dalam bentuk mac_phone.cfg

Selepas semua perubahan dalam fail dan menyimpannya kembali ke pelayan tftp, kami memberi arahan kepada telefon untuk menyediakan dan but semula peranti.

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

Selepas but semula peranti, kami mendapat nama penuh kami pada skrin telefon + buku alamat yang sentiasa diisi dengan betul dalam bentuk pangkalan data, kemudian yang tinggal hanyalah menambah XML dan sedikit PHP untuk memaparkan kandungan secara dinamik. Terdapat banyak contoh sedemikian, malah YEALINK sendiri mempunyainya.

PS: Untuk kebolehskalaan yang lebih besar, anda boleh mengalihkan tetapan utama (pembolehubah) ke dalam fail yang berasingan.

Sumber: www.habr.com

Tambah komen