Dabînkirina otomatîkî Yealink T19 + pirtûka navnîşana dînamîkî

Dema ku ez hatim vê pargîdaniyê bixebitim, berê min hin databasên cîhazên IP-yê, çend serverên bi stêrk û patchek di forma FreeBPX de hebûn. Digel vê yekê, PBX analog Samsung IDCS500 paralel xebitî û, bi gelemperî, pergala ragihandinê ya sereke di pargîdaniyê de bû; têlefoniya IP tenê ji bo beşa firotanê dixebitî. Û dê her tişt bi vî rengî berdewam bikira, lê rojek xweş biryarek hat dayîn ku her kes bi têlefoniya IP-ê veguhezîne, li ser muhletê li hev kirin, amûr hatin kirîn, û plansaziya veguheztina pargîdaniyê di sedsala 21-an de dest pê kir.
Yekem tiştê ku di rewşek wusa de dest bi fikaran dike, hejmara ku bi lez zêde dibe ya setên têlefonê ye ku divê bi rengekî were rêvebirin, ya duyemîn ku pir xemgîn bû pirtûka têlefonê bû. Ger Gerînendeyê Endpoint-ê dikaribû bi ya yekem re ji me re bibe alîkar (ya ku, bi awayê, ji guhertoyên herî dawî yên FreePBX-ê qut bû), wê hingê hin pirs bi pirtûkê re derketin:

  • Ya yekem, dema ku cîh / herikbariya bikarhêneran bi domdarî diguhere, meriv çawa rastbûna wê piştrast dike?
  • Ya duyemîn, meriv çawa têlefonan bi tevahî bêpersonalîze dike. Û her carê navê têkiliyê tije nakin?

Pirsgirêk balkêş bû, çareserî pir dem derbas nebû. Naha ez ê navnîşa tevahî bidim, û paşê em ê bi rêz lê binihêrin.

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

Bername li ser komputera bikarhêner dimeşe û bi şertê ku komputer bi têlefonê bi torê ve girêdayî be dixebite, ji ber ku Yealink T19 nikare wekî dergehek bixebite.

Pêşîn, divê em fêm bikin ka ew girêdayî ye? û çi mac û ip têlefona me heye.

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

Li vir em fonksiyona bîhnfirehiyê ji çarçoweya scapy bikar tînin, bi alîkariya wê em pakêtek udp-ya pêşwextkirî distînin, 70 çirkeyan li bendê dimînin û heke em tiştek negirin, em derdikevin.

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

Dûv re, em piştrast dikin ku cîhaz bi rastî Yealink e û nirxên pêwîst (ip û mac) vedigerînin.

Bi karanîna daxwazek taybetî, em hesabê heyî li ser têlefonê fêr dibin. Ji bo vê yekê, veavakirina heyî ji têlefonê tê dakêşandin û tê pars kirin.

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

Şîfreya vê hesabê bibînin. Ji bo vê yekê, em vedigerin tabloya asterisk.sip û qada daneya tê de.

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ê, ji bo qonaxa dawîn em bi ldap AD-ê ve girêdidin û bi karûbarê sAMAccountName-yê ku bi fonksiyonê hatî wergirtin bikar tînin getpass.getuser() cn-ya bikarhênerê heyî bigirin (ku bi gelemperî navê tevahî bikarhêner dihewîne).

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

Em di databasê de bi tabloyek pêş-afirandî ve girêdidin (min ew li wir afirandiye) û her tiştê ku em fêr bûne têkevin, ango: ip, mac, navê bikarhêner.

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

Em dikarin li vir rawestin, ji ber ku me berê pirtûkek navnîşanek dînamîkî çêkiriye, dibe ku hûn bipirsin, lê ez hê bêtir çûm û li vir dabînkirina otomatîkî ya cîhazan zêde kir.

Ji bo vê yekê, mîhengek şablonê ji serverek tftp-ya ku ji berê ve hatî mîheng kirin tê dakêşandin, ku em tê de guheztinên xwe çêdikin û wê wekî mac.cfg hilînin. Ango, ji bo Yealink du celeb veavakirin hene, yek gerdûnî ye, û ya duyemîn ji têlefonek taybetî re derbas dibe û divê di forma mac_phone.cfg de be.

Piştî hemî guhertinên di pelê de û hilanîna wê li servera tftp-ê, em fermanê didin têlefonê da ku amûrê peyda bike û ji nû ve saz bike.

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

Piştî nûvekirina cîhazê, em navê xweya tam li ser ekrana têlefonê digirin + pirtûkek navnîşê ya ku her gav bi rengek rast dagirtî di forma databasê de, wê hingê ya ku dimîne ev e ku em XML û piçek PHP-ê lê zêde bikin da ku naverokê dînamîk nîşan bidin. Mînakên weha pir in, YEALINK bixwe jî hene.

PS: Ji bo berbelavbûnek mezintir, hûn dikarin mîhengên sereke (guhêrbar) li pelek cûda biguhezînin.

Source: www.habr.com

Add a comment