Penyediaan otomatis Yealink T19 + buku alamat dinamis

Ketika saya mulai bekerja di perusahaan ini, saya sudah memiliki beberapa database perangkat IP, beberapa server dengan tanda bintang dan patch berupa FreeBPX. Selain itu, PBX analog Samsung IDCS500 bekerja secara paralel dan, secara umum, merupakan sistem komunikasi utama di perusahaan; telepon IP hanya berfungsi untuk departemen penjualan. Dan semuanya akan terus berjalan seperti ini, tetapi suatu hari sebuah keputusan diberikan untuk memindahkan semua orang ke telepon IP, tenggat waktu disepakati, peralatan dibeli, dan rencana untuk mentransfer perusahaan ke abad ke-21 mulai dilaksanakan.
Hal pertama yang mulai dikhawatirkan dalam situasi seperti ini adalah pesatnya pertumbuhan jumlah perangkat telepon yang perlu dikelola, hal kedua yang sangat mengkhawatirkan adalah buku telepon. Jika Endpoint Manager dapat membantu kami dengan yang pertama (yang, omong-omong, dihilangkan dari FreePBX versi terbaru), maka beberapa pertanyaan muncul dengan buku ini:

  • Pertama, bagaimana memastikan keakuratannya ketika lokasi/fluiditas pengguna terus berubah?
  • Kedua, cara mendepersonalisasi ponsel sepenuhnya. Dan tidak mengisi nama kontak setiap saat?

Masalahnya menarik, solusinya tidak butuh waktu lama untuk tiba. Sekarang saya akan memberikan daftar lengkapnya, dan kemudian kita akan melihatnya secara berurutan.

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 di komputer pengguna dan berfungsi asalkan komputer terhubung ke jaringan melalui telepon, karena Yealink T19 tidak dapat berfungsi sebagai gateway.

Pertama, kita perlu memahami apakah itu terhubung? dan mac dan ip apa yang dimiliki ponsel 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 kita menggunakan fungsi sniff dari kerangka scapy, dengan bantuannya kita menerima paket udp yang telah ditentukan, tunggu 70 detik dan jika kita tidak menangkap apa pun, kita keluar.

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

Selanjutnya, kami memastikan bahwa perangkat tersebut memang Yealink dan mengembalikan nilai yang diperlukan (ip dan mac).

Menggunakan permintaan khusus, kami mengetahui akun saat ini di telepon. Untuk melakukan ini, konfigurasi saat ini diunduh dari telepon dan diurai.

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

Cari tahu kata sandi untuk akun ini. Untuk melakukan ini, kita beralih ke tabel asterisk.sip dan bidang 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 tahap terakhir kita sambungkan ke ldap AD dan menggunakan sAMAccountName yang diperoleh melalui fungsi tersebut getpass.getuser() ambil cn pengguna saat ini (yang biasanya berisi nama lengkap 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 terhubung ke tabel yang sudah dibuat sebelumnya di database (saya membuatnya di sana) dan memasukkan semua yang kami pelajari, yaitu: 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()

Kita bisa berhenti di sini, karena kita telah membuat buku alamat dinamis, Anda mungkin bertanya, tapi saya melangkah lebih jauh dan menambahkan penyediaan perangkat secara otomatis di sini.

Untuk melakukan ini, konfigurasi templat diunduh dari server tftp yang telah dikonfigurasi sebelumnya, tempat kami melakukan perubahan dan menyimpannya sebagai mac.cfg. Artinya, untuk Yealink ada dua jenis konfigurasi, yang satu global, dan yang kedua berlaku untuk ponsel tertentu dan harus dalam bentuk mac_phone.cfg

Setelah semua perubahan pada file dan menyimpannya kembali ke server tftp, kami memberikan perintah ke ponsel untuk menyediakan dan mem-boot ulang perangkat.

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

Setelah me-reboot perangkat, kami mendapatkan nama lengkap kami di layar ponsel + buku alamat yang selalu diisi dengan benar dalam bentuk database, lalu yang tersisa hanyalah menambahkan XML dan sedikit PHP untuk menampilkan konten secara dinamis. Contohnya banyak sekali, bahkan YEALINK sendiri pun punya.

PS: Untuk skalabilitas yang lebih besar, Anda dapat memindahkan pengaturan utama (variabel) ke dalam file terpisah.

Sumber: www.habr.com

Tambah komentar