Автопровизионинг Yealink T19 + динамичСская адрСсная ΠΊΠ½ΠΈΠ³Π°

Когда я ΠΏΡ€ΠΈΡˆΠ΅Π» Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² эту компанию, Ρƒ мСня ΡƒΠΆΠ΅ имСлась нСкоторая Π±Π°Π·Π° ΠΏΠΎ ip Π°ΠΏΠΏΠ°Ρ€Π°Ρ‚Π°ΠΌ, нСскольким сСрвСрам с asterisk ΠΈ нашлСпкой Π² Π²ΠΈΠ΄Π΅ FreeBPX. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π»Π° аналоговая АВБ 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, с помошью Π½Π΅Ρ‘ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π·Π°Ρ€Π°Π½Π΅Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΉ 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 ΠΈ Π² Π½Π΅ΠΉ ΠΊ полю data.

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 сСрвСра скачиваСтся template конфигурация, Π² ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ вносим свои измСнСния ΠΈ сохраняСм с ΠΊΠ°ΠΊ mac.cfg. Π’ΠΎΠ΅ΡΡ‚ΡŒ для Yealink ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ Π΄Π²Π° Π²ΠΈΠ΄Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ, ΠΎΠ΄Π½Π° глобальная, Π° вторая примСняСтся ΠΊ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌΡƒ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Ρƒ ΠΈ Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Π²ΠΈΠ΄Π° mac_Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Π°.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.

P.S.: Для ΠΏΡƒΡ‰Π΅ΠΉ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎΡΡ‚ΠΈ ΠΌΠΎΠΆΠ½ΠΎ вынСсти основныС настройки (ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅) Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ„Π°ΠΉΠ»ΠΈΠΊ.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ