diff --git a/download.py b/download.py index ec07d42..79dbce4 100755 --- a/download.py +++ b/download.py @@ -6,6 +6,7 @@ import sys import ast import requests from include import net_tree +from collections import defaultdict from include.http_header import get_headers # компилируем регулярку поиска ipv4 адреса @@ -47,6 +48,44 @@ def ipv6_find(strip:str, size:int): """ return dict() +# метод группировки словаря +def get_dict_groups(input:dict): + """ + Метод получения сгрупированных данных + community и ip адресов + возвращает словарь сгрупированных данных + данные встречающиеся один раз, не попадают в вывод + """ + # строим битовые маски + name_to_bit = {name: 1 << i for i, name in enumerate(ipv4_dict.keys())} + line_communities = defaultdict(set) + line_mask = defaultdict(int) + + # походим по строкам и назначаем маску + for name, (communities, lines) in ipv4_dict.items(): + bit = name_to_bit[name] + for line in lines: + line_mask[line] |= bit + # добавляем комьюнити этого списка к конкретной строке + line_communities[line].update(communities) + + # группируем строки по маске + groups = defaultdict(list) + groups_communities = defaultdict(set) + for line, mask in line_mask.items(): + groups[mask].append(line) + groups_communities[mask].update(line_communities[line]) + + # конвертируем маску в имена + bit_to_names = {} + for mask in groups.keys(): + names = [name for name, bit in name_to_bit.items() if mask & bit] + list_name = "__".join(names) + bit_to_names[mask] = list_name + + # возвращаем словарь сгрупированных данных + return { bit_to_names[mask]: [ groups_communities[mask], set(groups[mask]) ] for mask in groups if "__" in bit_to_names[mask] } + # метод получения списка ip адресов def list_ip(c_dict: dict = []): """ @@ -158,6 +197,9 @@ if __name__ == "__main__": print(f"Список выгрузки пустой", file=sys.stderr) sys.exit(1) + # cловари для группировки + ipv4_dict=dict() + ipv6_dict=dict() # создаем дерриктори. для сохранения outdir=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'unloading') if not os.path.exists(outdir): @@ -165,11 +207,15 @@ if __name__ == "__main__": # создаём временный файл экспортируемой конфигурации, перед выгрузкой open(ipv4_bird2_m4 := f"{outdir}/bird2_v4.m4.tmp", "w").close() open(ipv6_bird2_m4 := f"{outdir}/bird2_v6.m4.tmp", "w").close() + # удаляем старые файлы группировок + [os.remove(path) for f in os.listdir(outdir) if "__" in f and os.path.isfile(path := os.path.join(outdir, f))] # обходим массив списков для выкрузки for clist in ip_list: # имена выходых файлов ipv4_out_file=f"{outdir}/{clist.lower()}_v4.txt" ipv6_out_file=f"{outdir}/{clist.lower()}_v6.txt" + # преобразуем запись комьюнити в список + ip_list[clist]['community']=list(ip_list[clist]['community'].split(",")) # если передан аргумент(ы) запуска, # значит пытаемся обновить только указанные списки if len(sys.argv)==1 or clist in sys.argv[1:]: @@ -192,16 +238,58 @@ if __name__ == "__main__": with open(ipv6_out_file, "w") as file: file.write(ipv6_list) print(f"Файл выгрузки {ipv6_out_file} сохранён") - # собираем комьюнити маршрутов - bgp_community=str() - for c in str(ip_list[clist]['community']).split(","): - bgp_community+=f"bgp_community.add(({str(c).replace(':',',')})); " - # обновляем временный файл конфигурации ipv4 - with open(ipv4_bird2_m4, "a") as file: - file.write(f"protocol static static_{clist.lower()} {{\n\tipv4 {{ import filter {{ {bgp_community}accept; }}; }};\n\tinclude \"{ipv4_out_file}\";\n}}\n") - # обновляем временный файл конфигурации ipv6 - with open(ipv6_bird2_m4, "a") as file: - file.write(f"protocol static static_{clist.lower()} {{\n\tipv6 {{ import filter {{ {bgp_community}accept; }}; }};\n\tinclude \"{ipv6_out_file}\";\n}}\n") + # открываем файл выгрузки и пополняем словарь для группировки ipv4 + if os.path.exists(ipv4_out_file): + with open(ipv4_out_file, "r") as file: + ipv4_dict[clist] = [ip_list[clist]['community'],list(file.readlines())] + # открываем файл выгрузки и пополняем словарь для группировки ipv6 + if os.path.exists(ipv6_out_file): + with open(ipv6_out_file, "r") as file: + ipv6_dict[clist] = [ip_list[clist]['community'],list(file.readlines())] + + # обновляем временный файл конфигурации ipv4 + # из группировок + if ipv4_dict: + for k,v in get_dict_groups(ipv4_dict).items(): + # имена выходых файлов + ipv4_out_file=f"{outdir}/{k.lower()}_v4.txt" + # сохраняем в файл + with open(ipv4_out_file, "w") as file: + file.write("".join(v[1])) + print(f"Файл группировки {ipv4_out_file} сохранён") + # список комьюнити маршрутов + bgp_community=" ".join([f"bgp_community.add(({str(c).replace(':',',')}));" for c in sorted(v[0])]) + with open(ipv4_bird2_m4, "a") as file: + file.write(f"protocol static static_{k.lower()}_v4 {{\n\tipv4 {{ import filter {{ {bgp_community} accept; }}; }};\n\tinclude \"{ipv4_out_file}\";\n}}\n") + # обновляем временный файл конфигурации ipv6 + # из группировок + if ipv6_dict: + for k,v in get_dict_groups(ipv6_dict).items(): + # имена выходых файлов + ipv6_out_file=f"{outdir}/{k.lower()}_v6.txt" + # сохраняем в файл + with open(ipv6_out_file, "w") as file: + file.write("".join(v[1])) + print(f"Файл группировки {ipv6_out_file} сохранён") + # список комьюнити маршрутов + bgp_community=" ".join([f"bgp_community.add(({str(c).replace(':',',')}));" for c in sorted(v[0])]) + with open(ipv6_bird2_m4, "a") as file: + file.write(f"protocol static static_{k.lower()}_v6 {{\n\tipv6 {{ import filter {{ {bgp_community} accept; }}; }};\n\tinclude \"{ipv6_out_file}\";\n}}\n") + + # дополняем временный файл конфигурации всей выгрузкой ipv4 и ipv6 + for clist in ip_list: + # имена выходых файлов + ipv4_out_file=f"{outdir}/{clist.lower()}_v4.txt" + ipv6_out_file=f"{outdir}/{clist.lower()}_v6.txt" + # список комьюнити маршрутов + bgp_community=" ".join([f"bgp_community.add(({str(c).replace(':',',')}));" for c in sorted(ip_list[clist]['community'])]) + if os.path.exists(ipv4_out_file): + with open(ipv4_bird2_m4, "a") as file: + file.write(f"protocol static static_{clist.lower()}_v4 {{\n\tipv4 {{ import filter {{ {bgp_community} accept; }}; }};\n\tinclude \"{ipv4_out_file}\";\n}}\n") + if os.path.exists(ipv6_out_file): + with open(ipv6_bird2_m4, "a") as file: + file.write(f"protocol static static_{clist.lower()}_v6 {{\n\tipv4 {{ import filter {{ {bgp_community} accept; }}; }};\n\tinclude \"{ipv6_out_file}\";\n}}\n") + # проверяем, что временный файл конфигурации ipv4 не пустой, сохраняем в постоянный if os.path.exists(ipv4_bird2_m4) and os.path.getsize(ipv4_bird2_m4) != 0: os.replace(ipv4_bird2_m4, ipv4_bird2_m4.removesuffix(".tmp"))