Automaattinen valmistelu Yealink T19 + dynaaminen osoitekirja

Kun tulin töihin tähän yritykseen, minulla oli jo tietokanta IP-laitteista, useita tähdellä merkittyjä palvelimia ja korjaustiedosto FreeBPX:n muodossa. Lisäksi analoginen PBX Samsung IDCS500 toimi rinnakkain ja oli yleisesti ottaen yrityksen pääviestintäjärjestelmä, IP-puhelut toimi vain myyntiosastolla. Ja kaikki olisi jatkossakin kypsennetty tällä tavalla, mutta eräänä kauniina päivänä annettiin asetus siirtää kaikki IP-puheluihin, sovittiin määräajoista, ostettiin laitteet ja suunnitelmaa yrityksen siirtämisestä 21-luvulle alettiin toteuttaa.
Ensimmäinen asia, joka tällaisessa tilanteessa alkaa huolestumaan, on nopeasti kasvava määrä puhelimia, joita pitäisi jotenkin hallita, toiseksi erittäin huolestuttava asia oli puhelinluettelo. Jos Endpoint Manager saattoi auttaa meitä ensimmäisessä (joka muuten leikattiin pois FreePBX:n uusimmista versioista), kirjan kanssa heräsi kysymyksiä:

  • Ensinnäkin, kuinka varmistaa sen tarkkuus, kun käyttäjien sijainti/sujuvuus muuttuu jatkuvasti?
  • Toiseksi, kuinka puhelimia voidaan depersonalisoida kokonaan. Etkö täytä yhteyshenkilön nimeä joka kerta?

Ongelma oli mielenkiintoinen, ratkaisun saapuminen ei kestänyt kauan. Nyt annan täydellisen luettelon, ja sitten katsomme sitä järjestyksessä.

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

Ohjelma toimii käyttäjän tietokoneella ja toimii edellyttäen, että tietokone on kytketty verkkoon puhelimen kautta, koska Yealink T19 ei voi toimia yhdyskäytävänä.

Ensinnäkin meidän on ymmärrettävä, onko se yhteydessä? ja mikä mac ja ip puhelimellamme on.

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

Täällä käytämme scapy-kehyksen sniff-toimintoa, jonka avulla vastaanotamme ennalta määrätyn udp-paketin, odotamme 70 sekuntia ja jos emme saa mitään, poistumme.

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

Seuraavaksi varmistamme, että laite on todella Yealink ja palautamme tarvittavat arvot (ip ja mac).

Erikoispyynnön avulla selvitämme nykyisen tilin puhelimessa. Tätä varten nykyinen kokoonpano ladataan puhelimesta ja jäsennetään.

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

Selvitä tämän tilin salasana. Tätä varten siirrymme asterisk.sip-taulukkoon ja siinä olevaan tietokenttään.

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

Viimeistä vaihetta varten muodostamme yhteyden ldap AD:hen ja käytämme funktion kautta saatua sAMAccountNamea getpass.getuser() ota nykyisen käyttäjän cn (joka yleensä sisältää käyttäjän koko nimen).

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

Yhdistämme tietokannassa valmiiksi luotuun taulukkoon (loin sen siellä) ja kirjoitamme kaiken, mitä opimme, nimittäin: ip, mac, käyttäjätunnus.

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

Voisimme lopettaa tähän, koska olemme jo luoneet dynaamisen osoitekirjan, voit kysyä, mutta menin pidemmälle ja lisäsin laitteiden automaattisen hallinnan tähän.

Tätä varten esikonfiguroidulta tftp-palvelimelta ladataan mallikokoonpano, johon teemme muutokset ja tallennamme sen nimellä mac.cfg. Toisin sanoen Yealinkille on olemassa kahdenlaisia ​​määrityksiä, joista toinen on yleinen ja toinen koskee tiettyä puhelinta, ja sen tulee olla muotoa mac_phone.cfg

Kaikkien tiedostoon tehtyjen muutosten ja sen takaisin tftp-palvelimelle tallentamisen jälkeen annamme puhelimelle komennon varustaa ja käynnistää laite uudelleen.

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

Laitteen uudelleenkäynnistyksen jälkeen saamme puhelimen näytölle koko nimemme + aina oikein täytetty osoitekirja tietokannan muodossa, sitten ei enää tarvitse kuin lisätä XML ja pieni PHP sisällön näyttämiseksi dynaamisesti. Tällaisia ​​esimerkkejä on paljon, jopa YEALINKillä itsellään.

PS: Skaalautuvuuden lisäämiseksi voit siirtää pääasetukset (muuttujat) erilliseen tiedostoon.

Lähde: will.com

Lisää kommentti