Otomatik temel hazırlık Yealink T19 + dinamik adres defteri

Bu şirkette çalışmaya geldiğimde, zaten IP aygıtlarından oluşan bir veri tabanım, yıldız işaretli birkaç sunucum ve FreeBPX biçiminde bir yamam vardı. Ek olarak, Samsung IDCS500 analog PBX paralel olarak çalıştı ve genel olarak şirketteki ana iletişim sistemiydi; IP telefonu yalnızca satış departmanı için çalışıyordu. Ve her şey böyle gelişmeye devam edecekti, ancak güzel bir gün herkesin IP telefona aktarılmasına ilişkin bir karar verildi, son tarihler üzerinde anlaşmaya varıldı, ekipman satın alındı ​​ve işletmeyi 21. yüzyıla aktarma planı uygulanmaya başlandı.
Böyle bir durumda endişe etmeye başlayan ilk şey, bir şekilde yönetilmesi gereken telefon setlerinin sayısının hızla artması, ikinci olarak ise telefon rehberi oldu. Eğer Endpoint Manager bize ilkinde yardımcı olabilirse (ki bu da FreePBX'in en son sürümlerinden çıkarılmıştı), o zaman kitapla ilgili bazı sorular ortaya çıktı:

  • Öncelikle kullanıcıların konumu/akışkanlığı sürekli değişirken doğruluğu nasıl sağlanacak?
  • İkincisi, telefonların nasıl tamamen kişiliksizleştirileceği. Ve her seferinde kişi adını girmiyor musunuz?

Sorun ilginçti, çözümün gelmesi uzun sürmedi. Şimdi tam listeyi vereceğim, sonra sırasıyla bakacağız.

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 kullanıcının bilgisayarında çalışır ve Yealink T19 ağ geçidi olarak çalışamadığı için bilgisayarın ağa telefon aracılığıyla bağlanması şartıyla çalışır.

Öncelikle bağlantılı olup olmadığını anlamamız gerekiyor. ve telefonumuzun hangi mac ve ip'ye sahip olduğu.

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 scapy çerçevesinden sniff fonksiyonunu kullanıyoruz, onun yardımıyla önceden belirlenmiş bir udp paketi alıyoruz, 70 saniye bekliyoruz ve hiçbir şey yakalayamazsak çıkıyoruz.

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

Daha sonra cihazın gerçekten Yealink olduğundan emin oluyoruz ve gerekli değerleri (ip ve mac) döndürüyoruz.

Özel bir istek kullanarak telefondaki mevcut hesabı buluyoruz. Bunu yapmak için mevcut yapılandırma telefondan indirilir ve ayrıştırılır.

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 şifresini bulun. Bunu yapmak için asterisk.sip tablosuna ve içindeki veri alanına dönüyoruz.

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

Son aşamada ldap AD'ye bağlanıyoruz ve fonksiyon aracılığıyla elde edilen sAMAccountName'i kullanıyoruz. getpass.getuser() Geçerli kullanıcının cn'sini alın (genellikle kullanıcının tam adını içerir).

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

Veritabanındaki önceden oluşturulmuş bir tabloya bağlanıyoruz (onu orada oluşturdum) ve öğrendiğimiz her şeyi giriyoruz: ip, mac, kullanıcı 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()

Burada durabiliriz, çünkü zaten dinamik bir adres defteri oluşturduğumuzu sorabilirsiniz, ancak daha da ileri giderek buraya cihazların otomatik provizyonunu ekledim.

Bunu yapmak için, önceden yapılandırılmış bir tftp sunucusundan bir şablon yapılandırması indirilir, burada değişikliklerimizi yaparız ve onu mac.cfg olarak kaydederiz. Yani, Yealink için iki tür yapılandırma vardır; biri genel, ikincisi ise belirli bir telefona uygulanır ve mac_phone.cfg biçiminde olmalıdır.

Dosyadaki tüm değişiklikleri yapıp tekrar tftp sunucusuna kaydettikten sonra telefona provizyon yapıp cihazı yeniden başlatma komutunu veriyoruz.

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ı yeniden başlattıktan sonra, telefon ekranında tam adımızı + veritabanı biçiminde her zaman doğru doldurulmuş bir adres defterini görüyoruz, ardından geriye kalan tek şey içeriği dinamik olarak görüntülemek için XML ve biraz PHP eklemek. Bunun gibi pek çok örnek var, hatta YEALINK'in kendisinde bile var.

Not: Daha fazla ölçeklenebilirlik için ana ayarları (değişkenleri) ayrı bir dosyaya yerleştirebilirsiniz.

Kaynak: habr.com

Yorum ekle