Auto provisioning Yealink T19 + dinamikong address book

Sa akong pag-abot sa pagtrabaho niini nga kompanya, aduna na akoy database sa mga IP device, daghang mga server nga adunay asterisk ug usa ka patch sa porma sa FreeBPX. Dugang pa, ang usa ka analogue nga PBX Samsung IDCS500 nagtrabaho nga managsama ug, sa kinatibuk-an, mao ang panguna nga sistema sa komunikasyon sa kompanya; Ang IP telephony nagtrabaho lamang alang sa departamento sa pagpamaligya. Ug ang tanan magpadayon sa pagluto nga sama niini, apan usa ka maayong adlaw usa ka mando ang gihatag aron ibalhin ang tanan sa IP telephony, gikasabutan ang mga deadline, gipalit ang mga kagamitan, ug ang plano sa pagbalhin sa negosyo sa ika-21 nga siglo nagsugod nga gipatuman.
Ang una nga butang nga nagsugod sa pagkabalaka sa ingon nga kahimtang mao ang paspas nga nagtubo nga gidaghanon sa mga set sa telepono nga kinahanglan nga madumala sa usa ka paagi, ang ikaduha nga butang nga nakapabalaka kaayo mao ang libro sa telepono. Kung ang Endpoint Manager makatabang kanamo sa una (nga, sa tinuud, giputol gikan sa pinakabag-o nga bersyon sa FreePBX), unya pipila ka mga pangutana ang mitungha sa libro:

  • Una, giunsa pagsiguro ang katukma niini kung ang lokasyon / pagka-fluid sa mga tiggamit kanunay nga nagbag-o?
  • Ikaduha, kung giunsa ang hingpit nga pag-depersonalize sa mga telepono. Ug dili pun-an ang ngalan sa kontak matag higayon?

Ang problema mao ang makapaikag, ang solusyon wala magdugay sa pag-abot. Karon akong ihatag ang tibuok listahan, ug unya atong tan-awon kini sa han-ay.

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

Ang programa nagdagan sa kompyuter sa tiggamit ug nagtrabaho kung ang kompyuter konektado sa network pinaagi sa usa ka telepono, tungod kay ang Yealink T19 dili molihok ingon usa ka ganghaan.

Una, kinahanglan natong masabtan kung konektado ba kini? ug unsa mac ug ip atong phone.

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

Dinhi among gigamit ang sniff function gikan sa scapy framework, uban sa tabang niini makadawat kami usa ka gitino nang daan nga pakete sa udp, maghulat sa 70 segundos ug kung wala kami makakuha bisan unsa, mogawas kami.

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

Sunod, gisiguro namon nga ang aparato sa tinuud nga Yealink ug ibalik ang kinahanglan nga mga kantidad (ip ug mac).

Gamit ang usa ka espesyal nga hangyo, nahibal-an namon ang karon nga account sa telepono. Aron mahimo kini, ang kasamtangan nga pag-configure gi-download gikan sa telepono ug gi-parse.

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

Hibal-i ang password alang niini nga account. Sa pagbuhat niini, kita mobalik sa asterisk.sip lamesa ug ang data field niini.

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

Aw, alang sa katapusang yugto kita magkonektar sa ldap AD ug gamit ang sAMAccountName nga nakuha pinaagi sa function getpass.getuser() kuhaa ang cn sa kasamtangang user (nga kasagaran adunay tibuok nga ngalan sa user).

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

Nagkonektar kami sa usa ka pre-created nga lamesa sa database (gibuhat nako kini didto) ug gisulod ang tanan nga among nakat-unan, nga mao: 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()

Mahimo kaming mohunong dinhi, tungod kay nakahimo na kami usa ka dinamikong libro sa adres, mahimo ka mangutana, apan nagpadayon ako ug gidugang ang auto-provisioning sa mga aparato dinhi.

Aron mahimo kini, ang usa ka template configuration gi-download gikan sa usa ka pre-configured tftp server, diin atong himoon ang atong mga kausaban ug i-save kini isip mac.cfg. Sa ato pa, alang sa Yealink adunay duha ka matang sa pag-configure, ang usa global, ug ang ikaduha magamit sa usa ka piho nga telepono ug kinahanglan nga sa porma nga mac_phone.cfg

Pagkahuman sa tanan nga mga pagbag-o sa file ug i-save kini balik sa tftp server, gihatag namon ang mando sa telepono aron mahatagan ug i-reboot ang aparato.

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

Pagkahuman sa pag-reboot sa aparato, makuha namon ang among tibuuk nga ngalan sa screen sa telepono + usa ka kanunay nga husto nga napuno nga address book sa porma sa usa ka database, unya ang nahabilin mao ang pagdugang XML ug usa ka gamay nga PHP aron dinamikong ipakita ang sulud. Adunay daghang mga pananglitan, bisan ang YEALINK mismo adunay kanila.

PS: Alang sa mas dako nga scalability, mahimo nimong ibalhin ang mga nag-unang setting (mga variable) sa usa ka lahi nga file.

Source: www.habr.com

Idugang sa usa ka comment