Outomatiese voorsiening Yealink T19 + dinamiese adresboek

Toe ek by hierdie maatskappy kom werk het, het ek reeds 'n databasis van IP-toestelle gehad, verskeie bedieners met asterisk en 'n pleister in die vorm van FreeBPX. Daarbenewens het 'n analoog PBX Samsung IDCS500 parallel gewerk en was oor die algemeen die belangrikste kommunikasiestelsel in die maatskappy; IP-telefonie het net vir die verkoopsafdeling gewerk. En alles sou so aanhou kook het, maar op 'n mooi dag is 'n bevel gegee om almal na IP-telefonie oor te plaas, spertye is ooreengekom, toerusting is aangekoop en die plan om die onderneming na die 21ste eeu oor te dra, het begin geïmplementeer word.
Die eerste ding wat in so 'n situasie begin bekommer is die vinnig groeiende aantal telefoonstelle wat op een of ander manier bestuur moet word, die tweede ding wat baie kommerwekkend was, was die telefoonboek. As Endpoint Manager ons kon help met die eerste een (wat terloops uit die nuutste weergawes van FreePBX gesny is), dan het 'n paar vrae met die boek ontstaan:

  • Eerstens, hoe om die akkuraatheid daarvan te verseker wanneer die ligging/vloeibaarheid van gebruikers voortdurend verander?
  • Tweedens, hoe om fone heeltemal te depersonaliseer. En nie elke keer die kontaknaam invul nie?

Die probleem was interessant, die oplossing het nie lank geneem om te kom nie. Nou sal ek die volledige lys gee, en dan sal ons dit in volgorde kyk.

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

Die program loop op die gebruiker se rekenaar en werk mits die rekenaar via 'n foon aan die netwerk gekoppel is, aangesien Yealink T19 nie as 'n poort kan werk nie.

Eerstens moet ons verstaan ​​of dit verbind is? en watter mac en ip ons foon het.

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

Hier gebruik ons ​​die snuiffunksie van die scapy-raamwerk, met sy hulp ontvang ons 'n voorafbepaalde udp-pakkie, wag 70 sekondes en as ons niks vang nie, gaan ons uit.

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

Vervolgens maak ons ​​seker dat die toestel wel Yealink is en gee ons die nodige waardes terug (ip en mac).

Deur 'n spesiale versoek te gebruik, vind ons die huidige rekening op die telefoon uit. Om dit te doen, word die huidige konfigurasie van die telefoon afgelaai en ontleed.

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

Vind die wagwoord vir hierdie rekening uit. Om dit te doen, draai ons na die asterisk.sip-tabel en die dataveld daarin.

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

Wel, vir die laaste stadium koppel ons aan ldap AD en gebruik sAMAccountName verkry deur die funksie getpass.getuser() neem die cn van die huidige gebruiker (wat gewoonlik die gebruiker se volle naam bevat).

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

Ons koppel aan 'n voorafgeskepte tabel in die databasis (ek het dit daar geskep) en voer alles in wat ons geleer het, naamlik: ip, mac, gebruikersnaam.

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

Ons kan hier stop, want ons het reeds 'n dinamiese adresboek geskep, kan jy vra, maar ek het verder gegaan en outo-voorsiening van toestelle hier bygevoeg.

Om dit te doen, word 'n sjabloonkonfigurasie afgelaai vanaf 'n vooraf gekonfigureerde tftp-bediener, waarin ons ons veranderinge aanbring en dit stoor as mac.cfg. Dit wil sê, vir Yealink is daar twee tipes konfigurasie, een is wêreldwyd, en die tweede is van toepassing op 'n spesifieke foon en moet van die vorm wees mac_phone.cfg

Na al die veranderinge in die lêer en dit terug op die tftp-bediener gestoor het, gee ons die opdrag aan die telefoon om die toestel te voorsien en te herlaai.

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

Nadat ons die toestel herlaai het, kry ons ons volle naam op die telefoonskerm + 'n altyd korrek ingevulde adresboek in die vorm van 'n databasis, dan is al wat oorbly om XML en 'n bietjie PHP by te voeg om die inhoud dinamies te vertoon. Daar is baie sulke voorbeelde, selfs YEALINK self het dit.

NS: Vir groter skaalbaarheid, kan jy die hoofinstellings (veranderlikes) na 'n aparte lêer skuif.

Bron: will.com

Voeg 'n opmerking