Horniketa automatikoa Yealink T19 + helbide-liburu dinamikoa

Enpresa honetara lanera etorri nintzenean, dagoeneko banuen IP gailuen datu-base batzuk, izartxoa zuten hainbat zerbitzari eta FreeBPX moduko adabaki bat. Gainera, Samsung IDCS500 PBX analogiko batek paraleloan funtzionatzen zuen eta, oro har, enpresaren komunikazio sistema nagusia zen; IP telefonia salmenta sailerako bakarrik funtzionatzen zuen. Eta dena horrela egosten jarraituko zuen, baina egun eder batean dekretua eman zen denak IP telefoniara pasatzeko, epeak adostu, ekipoak erosi eta enpresa XXI. mendera eramateko plana ezartzen hasi zen.
Horrelako egoera batean kezkatzen hasten den lehenengo gauza nolabait kudeatu behar diren telefono-gailuen kopurua azkar hazten ari dena da, bigarrena oso kezkagarria zen telefono-liburua. Endpoint Manager-ek lehenengoarekin (bide batez, FreePBX-en azken bertsioetatik moztuta zegoen) lagundu badiguke, orduan galdera batzuk sortu ziren liburuarekin:

  • Lehenik eta behin, nola ziurtatu bere zehaztasuna erabiltzaileen kokapena/jariakortasuna etengabe aldatzen ari denean?
  • Bigarrenik, telefonoak guztiz despertsonalizatzeko. Eta kontaktuaren izena ez bete aldi bakoitzean?

Arazoa interesgarria zen, konponbidea ez zen luze behar izan. Orain zerrenda osoa emango dut, eta gero ordenan ikusiko dugu.

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

Programa erabiltzailearen ordenagailuan exekutatzen da eta funtzionatzen du, baldin eta ordenagailua sarera telefono bidez konektatuta badago, Yealink T19 ezin baita atebide gisa funtzionatu.

Lehenik eta behin, ulertu behar dugu konektatuta dagoen ala ez? eta zer mac eta ip dauka gure telefonoak.

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

Hemen scapy framework-tik sniff funtzioa erabiltzen dugu, bere laguntzarekin aurrez zehaztutako udp pakete bat jasotzen dugu, 70 segundo itxaron eta ezer harrapatzen ez badugu, irteten gara.

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

Ondoren, ziurtatzen dugu gailua Yealink dela eta beharrezko balioak itzultzen ditugu (ip eta mac).

Eskaera berezi bat erabiliz, kontu korrontearen berri dugu telefonoan. Horretarako, uneko konfigurazioa telefonotik deskargatu eta analizatu egiten da.

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

Ezagutu kontu honen pasahitza. Horretarako, asterisk.sip taulara eta bertan dagoen datu-eremura jotzen dugu.

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

Beno, azken faserako ldap AD-ra konektatzen gara eta funtzioaren bidez lortutako sAMAccountName erabiliz getpass.getuser() hartu uneko erabiltzailearen cn (normalean erabiltzailearen izen osoa dauka).

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

Datu-basean aurrez sortutako taula batera konektatzen gara (bertan sortu dut) eta ikasitako guztia sartzen dugu, hau da: 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()

Hemen gelditu gintezke, dagoeneko helbide-liburu dinamiko bat sortu dugulako, galdetuko duzu, baina harago joan naiz eta hemen gailuen horniketa automatikoa gehitu dut.

Horretarako, aurrez konfiguratutako tftp zerbitzari batetik txantiloi-konfigurazio bat deskargatzen da, eta bertan gure aldaketak egin eta mac.cfg gisa gordetzen ditugu. Hau da, Yealink-entzat bi konfigurazio mota daude, bata globala da, eta bigarrena telefono zehatz bati aplikatzen zaio eta mac_phone.cfg formakoa izan behar du.

Fitxategian aldaketa guztiak egin ondoren eta tftp zerbitzarian gorde ondoren, telefonoari komandoa ematen diogu gailua hornitzeko eta berrabiarazteko.

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

Gailua berrabiarazi ondoren, gure izen osoa telefonoaren pantailan + datu-base moduan beti behar bezala betetako helbide-liburua jasoko dugu, gero XML eta PHP apur bat gehitzea besterik ez da geratzen edukia dinamikoki bistaratzeko. Horrelako adibide asko daude, YEALINKek berak ere baditu.

PS: eskalagarritasun handiagoa lortzeko, ezarpen nagusiak (aldagaiak) fitxategi bereizi batera eraman ditzakezu.

Iturria: www.habr.com

Gehitu iruzkin berria