Ավտոմատ տրամադրում Yealink T19 + դինամիկ հասցեագիրք

Երբ ես եկա այս ընկերությունում աշխատելու, ես արդեն ունեի IP սարքերի տվյալների բազա, աստղանիշով մի քանի սերվեր և FreeBPX-ի տեսքով կարկատել: Բացի այդ, զուգահեռ աշխատում էր անալոգային PBX Samsung IDCS500-ը և, ընդհանուր առմամբ, ընկերության հիմնական կապի համակարգն էր, IP հեռախոսակապն աշխատում էր միայն վաճառքի բաժնի համար: Եվ ամեն ինչ կշարունակեր այսպես եփվել, բայց մի գեղեցիկ օր հրաման տրվեց բոլորին տեղափոխել IP հեռախոսակապ, պայմանավորվեցին ժամկետները, գնվեցին սարքավորումներ և սկսեց իրագործվել ձեռնարկությունը 21-րդ դար տեղափոխելու ծրագիրը։
Առաջին բանը, որ սկսում է անհանգստացնել նման իրավիճակում, արագ աճող հեռախոսային սարքերի քանակն է, որոնք պետք է ինչ-որ կերպ կառավարել, երկրորդը, որ շատ մտահոգիչ էր, հեռախոսագիրքն էր։ Եթե ​​Endpoint Manager-ը կարողանար օգնել մեզ առաջինի հարցում (որը, ի դեպ, կտրված էր FreePBX-ի վերջին տարբերակներից), ապա գրքի հետ կապված որոշ հարցեր ծագեցին.

  • Նախ, ինչպե՞ս ապահովել դրա ճշգրտությունը, երբ օգտատերերի գտնվելու վայրը/հեղուկությունը անընդհատ փոխվում է:
  • Երկրորդ, ինչպես ամբողջությամբ ապանձնացնել հեռախոսները: Եվ ամեն անգամ կոնտակտային անուն չե՞ք լրացնում։

Խնդիրը հետաքրքիր էր, լուծումը չուշացավ։ Հիմա ես կտամ ամբողջական ցուցակը, իսկ հետո կդիտարկենք ըստ հերթականության։

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

Ծրագիրն աշխատում է օգտատիրոջ համակարգչում և աշխատում է այն պայմանով, որ համակարգիչը միացված է ցանցին հեռախոսի միջոցով, քանի որ Yealink T19-ը չի կարող աշխատել որպես դարպաս:

Նախ, մենք պետք է հասկանանք, արդյոք դա կապված է: և ինչ mac և ip ունի մեր հեռախոսը:

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

Այստեղ մենք օգտագործում ենք sniff ֆունկցիան scapy frame-ից, որի օգնությամբ մենք ստանում ենք կանխորոշված ​​udp փաթեթ, սպասում ենք 70 վայրկյան և եթե ոչինչ չենք բռնում, դուրս ենք գալիս։

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

Հաջորդը, մենք համոզվում ենք, որ սարքը իսկապես Yealink է և վերադարձնում է անհրաժեշտ արժեքները (ip և mac):

Օգտագործելով հատուկ հարցում, մենք պարզում ենք ընթացիկ հաշիվը հեռախոսով: Դա անելու համար ընթացիկ կոնֆիգուրացիան ներբեռնվում է հեռախոսից և վերլուծվում:

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

Պարզեք այս հաշվի գաղտնաբառը: Դա անելու համար մենք դիմում ենք asterisk.sip աղյուսակին և դրա տվյալների դաշտին:

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

Դե, վերջնական փուլի համար մենք միանում ենք ldap AD-ին և օգտագործելով ֆունկցիայի միջոցով ստացված sAMAccountName-ը: getpass.getuser() վերցրեք ընթացիկ օգտատիրոջ cn-ը (որը սովորաբար պարունակում է օգտագործողի լրիվ անունը):

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

Մենք միանում ենք տվյալների բազայում նախապես ստեղծված աղյուսակին (ես այն ստեղծել եմ այնտեղ) և մուտքագրում ենք այն ամենը, ինչ սովորել ենք, այն է՝ ip, mac, օգտանուն:

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

Մենք կարող էինք կանգ առնել այստեղ, քանի որ մենք արդեն ստեղծել ենք դինամիկ հասցեագիրք, կարող եք հարցնել, բայց ես ավելի հեռուն գնացի և այստեղ ավելացրի սարքերի ավտոմատ տրամադրումը:

Դա անելու համար կաղապարի կոնֆիգուրացիան ներբեռնվում է նախապես կազմաձևված tftp սերվերից, որում մենք կատարում ենք մեր փոփոխությունները և պահում այն ​​որպես mac.cfg: Այսինքն, Yealink-ի համար գոյություն ունի երկու տեսակի կոնֆիգուրացիա, մեկը գլոբալ է, իսկ երկրորդը վերաբերում է կոնկրետ հեռախոսին և պետք է լինի mac_phone.cfg ձևի:

Ֆայլում կատարված բոլոր փոփոխություններից և այն tftp սերվերին հետ պահելուց հետո մենք հրահանգ ենք տալիս հեռախոսին տրամադրել և վերագործարկել սարքը:

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

Սարքը վերագործարկելուց հետո հեռախոսի էկրանին ստանում ենք մեր լրիվ անունը + միշտ ճիշտ լրացված հասցեագիրք տվյալների բազայի տեսքով, այնուհետև մնում է ավելացնել XML և մի փոքր PHP՝ բովանդակությունը դինամիկ ցուցադրելու համար: Նման օրինակները շատ են, նույնիսկ ինքը՝ YEALINK-ն ունի:

Հ.Գ. Ավելի լայնածավալության համար կարող եք հիմնական կարգավորումները (փոփոխականները) տեղափոխել առանձին ֆայլ:

Source: www.habr.com

Добавить комментарий