ස්වයංක්‍රීය ප්‍රතිපාදන 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

මෙන්න අපි scapy රාමුවෙන් sniff ශ්‍රිතය භාවිතා කරමු, එහි ආධාරයෙන් අපට කලින් තීරණය කළ 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 හි පවා ඒවා තිබේ.

PS: වැඩි පරිමාණයක් සඳහා, ඔබට ප්‍රධාන සැකසුම් (විචල්‍ය) වෙනම ගොනුවකට ගෙන යා හැක.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න