Sigurimi automatik i Yealink T19 + libri dinamik i adresave

Kur erdha të punoja për këtë kompani, kisha tashmë një bazë të dhënash të pajisjeve IP, disa serverë me yll dhe një patch në formën e FreeBPX. Për më tepër, një PBX analoge Samsung IDCS500 funksionoi paralelisht dhe, në përgjithësi, ishte sistemi kryesor i komunikimit në kompani; telefonia IP funksiononte vetëm për departamentin e shitjeve. Dhe gjithçka do të kishte vazhduar të gatuhej kështu, por një ditë të bukur u dha një dekret për transferimin e të gjithëve në telefoninë IP, u ranë dakord për afatet, u blenë pajisjet dhe plani për transferimin e ndërmarrjes në shekullin e 21-të filloi të zbatohej.
Gjëja e parë që fillon të shqetësojë në një situatë të tillë është numri në rritje i shpejtë i aparateve telefonike që duhen menaxhuar disi, gjëja e dytë që ishte shumë shqetësuese ishte libri i telefonave. Nëse Menaxheri i Endpoint mund të na ndihmonte me të parën (i cili, meqë ra fjala, ishte shkëputur nga versionet më të fundit të FreePBX), atëherë lindën disa pyetje me librin:

  • Së pari, si të sigurohet saktësia e tij kur vendndodhja/fluiditeti i përdoruesve ndryshon vazhdimisht?
  • Së dyti, si të depersonalizohen plotësisht telefonat. Dhe të mos plotësoni emrin e kontaktit çdo herë?

Problemi ishte interesant, zgjidhja nuk vonoi të mbërrinte. Tani do të jap listën e plotë dhe më pas do ta shikojmë me radhë.

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

Programi funksionon në kompjuterin e përdoruesit dhe funksionon me kusht që kompjuteri të lidhet me rrjetin përmes një telefoni, pasi Yealink T19 nuk mund të funksionojë si një portë.

Së pari, duhet të kuptojmë nëse është e lidhur? dhe çfarë mac dhe ip ka telefoni ynë.

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

Këtu përdorim funksionin sniff nga korniza scapy, me ndihmën e tij marrim një paketë të paracaktuar udp, presim 70 sekonda dhe nëse nuk kapim asgjë, dalim.

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

Më pas, sigurohemi që pajisja të jetë vërtet Yealink dhe të kthejmë vlerat e nevojshme (ip dhe mac).

Duke përdorur një kërkesë të veçantë, ne zbulojmë llogarinë rrjedhëse në telefon. Për ta bërë këtë, konfigurimi aktual shkarkohet nga telefoni dhe analizohet.

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

Gjeni fjalëkalimin për këtë llogari. Për ta bërë këtë, ne i drejtohemi tabelës asterisk.sip dhe fushës së të dhënave në të.

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

Epo, për fazën përfundimtare ne lidhemi me ldap AD dhe duke përdorur sAMAccountName të marrë përmes funksionit getpass.getuser() merrni cn-në e përdoruesit aktual (i cili zakonisht përmban emrin e plotë të përdoruesit).

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

Ne lidhemi me një tabelë të krijuar paraprakisht në bazën e të dhënave (e kam krijuar atje) dhe futim gjithçka që kemi mësuar, përkatësisht: ip, mac, emrin e përdoruesit.

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

Mund të ndalemi këtu, sepse ne kemi krijuar tashmë një libër dinamik adresash, mund të pyesni, por unë shkova më tej dhe shtova sigurimin automatik të pajisjeve këtu.

Për ta bërë këtë, një konfigurim shabllon shkarkohet nga një server tftp i para-konfiguruar, në të cilin ne bëjmë ndryshimet tona dhe e ruajmë atë si mac.cfg. Kjo do të thotë, për Yealink ekzistojnë dy lloje konfigurimi, njëri është global dhe i dyti vlen për një telefon specifik dhe duhet të jetë i formës mac_phone.cfg

Pas të gjitha ndryshimeve në skedar dhe ruajtjes së tij në serverin tftp, ne i japim komandën telefonit për të siguruar dhe rindezur pajisjen.

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

Pas rindezjes së pajisjes, ne marrim emrin tonë të plotë në ekranin e telefonit + një libër adresash të plotësuar gjithmonë saktë në formën e një baze të dhënash, atëherë gjithçka që mbetet është të shtojmë XML dhe pak PHP për të shfaqur në mënyrë dinamike përmbajtjen. Shembuj të tillë ka plot, madje edhe vetë YEALINK i ka.

PS: Për një shkallëzim më të madh, mund të zhvendosni cilësimet kryesore (ndryshoret) në një skedar të veçantë.

Burimi: www.habr.com

Shto një koment