Sjálfvirk útvegun Yealink T19 + kraftmikil heimilisfangaskrá

Þegar ég kom til starfa hjá þessu fyrirtæki var ég þegar með einhvern gagnagrunn yfir IP tæki, nokkra netþjóna með stjörnu og plástur í formi FreeBPX. Auk þess virkaði hliðræn PBX Samsung IDCS500 samhliða og var almennt helsta samskiptakerfið í fyrirtækinu, IP sími virkaði eingöngu fyrir söludeildina. Og allt hefði haldið áfram að elda svona, en einn góðan veðurdag var gefin tilskipun um að færa alla yfir í IP-síma, samið um tímamörk, keypt búnaður og farið að hrinda í framkvæmd áætluninni um að flytja fyrirtækið inn á 21. öldina.
Það fyrsta sem fer að valda áhyggjum í slíkum aðstæðum er ört vaxandi fjöldi símatækja sem þarf að stjórna einhvern veginn, annað sem vakti miklar áhyggjur var símaskráin. Ef Endpoint Manager gæti hjálpað okkur með þann fyrsta (sem, við the vegur, var klippt út úr nýjustu útgáfum FreePBX), þá vöknuðu nokkrar spurningar við bókina:

  • Í fyrsta lagi, hvernig á að tryggja nákvæmni þess þegar staðsetning/flæði notenda er stöðugt að breytast?
  • Í öðru lagi, hvernig á að afpersonalisera síma algjörlega. Og ekki fylla út nafn tengiliðarins í hvert skipti?

Vandamálið var áhugavert, lausnin var ekki lengi að koma. Nú mun ég gefa upp skráninguna í heild sinni, og þá munum við skoða hana í röð.

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

Forritið keyrir á tölvu notandans og virkar að því gefnu að tölvan sé tengd við netið í gegnum síma þar sem Yealink T19 getur ekki virkað sem gátt.

Í fyrsta lagi þurfum við að skilja hvort það er tengt? og hvaða mac og ip síminn okkar hefur.

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

Hér notum við sniff aðgerðina frá scapy ramma, með hjálp þess fáum við fyrirfram ákveðinn udp pakka, bíðum í 70 sekúndur og ef við náum ekki neinu förum við út.

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

Næst tryggjum við að tækið sé örugglega Yealink og skilum nauðsynlegum gildum (ip og mac).

Með því að nota sérstaka beiðni finnum við núverandi reikning í símanum. Til að gera þetta er núverandi stillingar hlaðið niður úr símanum og flokkað.

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

Finndu út lykilorðið fyrir þennan reikning. Til að gera þetta snúum við okkur að asterisk.sip töflunni og gagnareitnum í henni.

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

Jæja, fyrir lokastigið tengjumst við ldap AD og notum sAMAccountName sem fæst með aðgerðinni getpass.getuser() taktu cn núverandi notanda (sem venjulega inniheldur fullt nafn notandans).

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

Við tengjumst fyrirfram gerða töflu í gagnagrunninum (ég bjó hana til þar) og sláum inn allt sem við lærðum, nefnilega: ip, mac, notendanafn.

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

Við gætum hætt hér, vegna þess að við höfum þegar búið til kraftmikla heimilisfangaskrá, þú gætir spurt, en ég gekk lengra og bætti við sjálfvirkri útvegun tækja hér.

Til að gera þetta er sniðmátsstillingu hlaðið niður af fyrirfram stilltum tftp netþjóni, sem við gerum breytingar á og vistum sem mac.cfg. Það er, fyrir Yealink eru tvær gerðir af stillingum, önnur er alþjóðleg og sú síðari á við tiltekinn síma og ætti að vera af formi mac_phone.cfg

Eftir allar breytingar á skránni og vistun hennar aftur á tftp þjóninum gefum við skipuninni til símans að útvega og endurræsa tækið.

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

Eftir að hafa endurræst tækið fáum við fullt nafn á símaskjáinn + alltaf rétt útfyllta heimilisfangaskrá í formi gagnagrunns, þá er bara eftir að bæta við XML og smá PHP til að birta efnið á kraftmikinn hátt. Það eru til fullt af slíkum dæmum, jafnvel YEALINK sjálft hefur þau.

PS: Fyrir meiri sveigjanleika geturðu fært helstu stillingar (breytur) í sérstaka skrá.

Heimild: www.habr.com

Bæta við athugasemd