Bu şirkette çalışmaya geldiğimde, zaten IP aygıtlarından oluşan bir veri tabanım, yıldız işaretli birkaç sunucum ve FreeBPX biçiminde bir yamam vardı. Ek olarak, Samsung IDCS500 analog PBX paralel olarak çalıştı ve genel olarak şirketteki ana iletişim sistemiydi; IP telefonu yalnızca satış departmanı için çalışıyordu. Ve her şey böyle gelişmeye devam edecekti, ancak güzel bir gün herkesin IP telefona aktarılmasına ilişkin bir karar verildi, son tarihler üzerinde anlaşmaya varıldı, ekipman satın alındı ve işletmeyi 21. yüzyıla aktarma planı uygulanmaya başlandı.
Böyle bir durumda endişe etmeye başlayan ilk şey, bir şekilde yönetilmesi gereken telefon setlerinin sayısının hızla artması, ikinci olarak ise telefon rehberi oldu. Eğer Endpoint Manager bize ilkinde yardımcı olabilirse (ki bu da FreePBX'in en son sürümlerinden çıkarılmıştı), o zaman kitapla ilgili bazı sorular ortaya çıktı:
- Öncelikle kullanıcıların konumu/akışkanlığı sürekli değişirken doğruluğu nasıl sağlanacak?
- İkincisi, telefonların nasıl tamamen kişiliksizleştirileceği. Ve her seferinde kişi adını girmiyor musunuz?
Sorun ilginçti, çözümün gelmesi uzun sürmedi. Şimdi tam listeyi vereceğim, sonra sırasıyla bakacağız.
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')
Program kullanıcının bilgisayarında çalışır ve Yealink T19 ağ geçidi olarak çalışamadığı için bilgisayarın ağa telefon aracılığıyla bağlanması şartıyla çalışır.
Öncelikle bağlantılı olup olmadığını anlamamız gerekiyor. ve telefonumuzun hangi mac ve ip'ye sahip olduğu.
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
Burada scapy çerçevesinden sniff fonksiyonunu kullanıyoruz, onun yardımıyla önceden belirlenmiş bir udp paketi alıyoruz, 70 saniye bekliyoruz ve hiçbir şey yakalayamazsak çıkıyoruz.
count=1, timeout=70, filter="dst host 192.168.0.3 and port 5060"
Daha sonra cihazın gerçekten Yealink olduğundan emin oluyoruz ve gerekli değerleri (ip ve mac) döndürüyoruz.
Özel bir istek kullanarak telefondaki mevcut hesabı buluyoruz. Bunu yapmak için mevcut yapılandırma telefondan indirilir ve ayrıştırılır.
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
Bu hesabın şifresini bulun. Bunu yapmak için asterisk.sip tablosuna ve içindeki veri alanına dönüyoruz.
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
Son aşamada ldap AD'ye bağlanıyoruz ve fonksiyon aracılığıyla elde edilen sAMAccountName'i kullanıyoruz. getpass.getuser() Geçerli kullanıcının cn'sini alın (genellikle kullanıcının tam adını içerir).
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
Veritabanındaki önceden oluşturulmuş bir tabloya bağlanıyoruz (onu orada oluşturdum) ve öğrendiğimiz her şeyi giriyoruz: ip, mac, kullanıcı adı.
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()
Burada durabiliriz, çünkü zaten dinamik bir adres defteri oluşturduğumuzu sorabilirsiniz, ancak daha da ileri giderek buraya cihazların otomatik provizyonunu ekledim.
Bunu yapmak için, önceden yapılandırılmış bir tftp sunucusundan bir şablon yapılandırması indirilir, burada değişikliklerimizi yaparız ve onu mac.cfg olarak kaydederiz. Yani, Yealink için iki tür yapılandırma vardır; biri genel, ikincisi ise belirli bir telefona uygulanır ve mac_phone.cfg biçiminde olmalıdır.
Dosyadaki tüm değişiklikleri yapıp tekrar tftp sunucusuna kaydettikten sonra telefona provizyon yapıp cihazı yeniden başlatma komutunu veriyoruz.
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')
Cihazı yeniden başlattıktan sonra, telefon ekranında tam adımızı + veritabanı biçiminde her zaman doğru doldurulmuş bir adres defterini görüyoruz, ardından geriye kalan tek şey içeriği dinamik olarak görüntülemek için XML ve biraz PHP eklemek. Bunun gibi pek çok örnek var, hatta YEALINK'in kendisinde bile var.
Not: Daha fazla ölçeklenebilirlik için ana ayarları (değişkenleri) ayrı bir dosyaya yerleştirebilirsiniz.
Kaynak: habr.com