Darparu ceir Yealink T19 + llyfr cyfeiriadau deinamig

Pan ddes i weithio i'r cwmni hwn, roedd gen i gronfa ddata o ddyfeisiau IP eisoes, sawl gweinydd gyda seren a chlwt ar ffurf FreeBPX. Yn ogystal, roedd analog PBX Samsung IDCS500 yn gweithio ochr yn ochr ac, yn gyffredinol, oedd y brif system gyfathrebu yn y cwmni; roedd teleffoni IP yn gweithio i'r adran werthu yn unig. A byddai popeth wedi parhau i goginio fel hyn, ond un diwrnod braf rhoddwyd archddyfarniad i drosglwyddo pawb i teleffoni IP, cytunwyd ar derfynau amser, prynwyd offer, a dechreuwyd gweithredu'r cynllun i drosglwyddo'r fenter i'r 21ain ganrif.
Y peth cyntaf sy’n dechrau poeni mewn sefyllfa o’r fath yw’r nifer cynyddol gyflym o setiau ffΓ΄n sydd angen eu rheoli rhywsut, yr ail beth oedd yn peri pryder mawr oedd y llyfr ffΓ΄n. Pe gallai Endpoint Manager ein helpu gyda'r un cyntaf (a oedd, gyda llaw, wedi'i dorri allan o'r fersiynau diweddaraf o FreePBX), yna cododd rhai cwestiynau gyda'r llyfr:

  • Yn gyntaf, sut i sicrhau ei gywirdeb pan fo lleoliad / hylifedd defnyddwyr yn newid yn gyson?
  • Yn ail, sut i ddadbersonoli ffonau yn llwyr. A pheidio Γ’ llenwi'r enw cyswllt bob tro?

Roedd y broblem yn ddiddorol, ni chymerodd yr ateb yn hir i gyrraedd. Nawr byddaf yn rhoi'r rhestr lawn, ac yna byddwn yn edrych arno mewn trefn.

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

Mae'r rhaglen yn rhedeg ar gyfrifiadur y defnyddiwr ac yn gweithio ar yr amod bod y cyfrifiadur wedi'i gysylltu Γ’'r rhwydwaith trwy ffΓ΄n, gan na all Yealink T19 weithio fel porth.

Yn gyntaf, mae angen inni ddeall a yw'n gysylltiedig? a pha mac ac ip sydd gan ein ffΓ΄n.

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

Yma rydyn ni'n defnyddio'r swyddogaeth sniff o'r fframwaith gwag, gyda'i help rydyn ni'n derbyn pecyn udp a bennwyd ymlaen llaw, yn aros 70 eiliad ac os na fyddwn yn dal unrhyw beth, rydyn ni'n gadael.

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

Nesaf, rydym yn sicrhau bod y ddyfais yn wir yn Yealink ac yn dychwelyd y gwerthoedd angenrheidiol (ip a mac).

Gan ddefnyddio cais arbennig, rydym yn darganfod y cyfrif cyfredol ar y ffΓ΄n. I wneud hyn, mae'r ffurfweddiad presennol yn cael ei lawrlwytho o'r ffΓ΄n a'i ddosrannu.

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

Darganfyddwch y cyfrinair ar gyfer y cyfrif hwn. I wneud hyn, trown at y tabl asterisk.sip a'r maes data ynddo.

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, ar gyfer y cam olaf rydym yn cysylltu Γ’ ldap AD a defnyddio sAMAaccountName a gafwyd trwy'r swyddogaeth getpass.getuser() cymerwch CN y defnyddiwr presennol (sydd fel arfer yn cynnwys enw llawn y defnyddiwr).

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

Rydyn ni'n cysylltu Γ’ thabl wedi'i greu ymlaen llaw yn y gronfa ddata (fe wnes i ei greu yno) ac yn nodi popeth rydyn ni wedi'i ddysgu, sef: ip, mac, enw defnyddiwr.

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

Gallem roi'r gorau iddi yma, oherwydd ein bod eisoes wedi creu llyfr cyfeiriadau deinamig, efallai y byddwch yn gofyn, ond es ymhellach ac ychwanegu auto-ddarparu dyfeisiau yma.

I wneud hyn, mae ffurfweddiad templed yn cael ei lawrlwytho o weinydd tftp sydd wedi'i ffurfweddu ymlaen llaw, lle rydyn ni'n gwneud ein newidiadau ac yn ei gadw fel mac.cfg. Hynny yw, ar gyfer Yealink mae dau fath o ffurfweddiad, mae un yn fyd-eang, ac mae'r ail yn berthnasol i ffΓ΄n penodol a dylai fod o'r ffurf mac_phone.cfg

Ar Γ΄l yr holl newidiadau yn y ffeil a'i arbed yn Γ΄l i'r gweinydd tftp, rydyn ni'n rhoi'r gorchymyn i'r ffΓ΄n i ddarparu ac yn ailgychwyn y ddyfais.

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

Ar Γ΄l ailgychwyn y ddyfais, rydyn ni'n cael ein henw llawn ar sgrin y ffΓ΄n + llyfr cyfeiriadau sydd bob amser wedi'i lenwi'n gywir ar ffurf cronfa ddata, yna'r cyfan sy'n weddill yw ychwanegu XML ac ychydig o PHP i arddangos y cynnwys yn ddeinamig. Mae yna lawer o enghreifftiau o'r fath, mae gan YEALINK ei hun nhw hyd yn oed.

PS: I gael mwy o scalability, gallwch symud y prif osodiadau (newidynnau) i ffeil ar wahΓ’n.

Ffynhonnell: hab.com

Ychwanegu sylw