diff --git a/nmcli_configurator.py b/nmcli_configurator.py new file mode 100644 index 0000000..4c97687 --- /dev/null +++ b/nmcli_configurator.py @@ -0,0 +1,153 @@ +import subprocess + +def detect_rt_tables_path(): + return "/etc/iproute2/rt_tables" + +def list_connections(): + output = subprocess.check_output(["nmcli", "-t", "-f", "uuid,name,type,device", "connection", "show"]).decode() + print("\n[DEBUG] Surowe dane z nmcli:") + print(output) + + conns = [] + for line in output.strip().splitlines(): + parts = line.strip().split(":", 3) + if len(parts) < 4: + continue + uuid, name, typ, dev = parts + if typ.strip() in ["ethernet", "802-3-ethernet"]: + dev = dev.strip() if dev.strip() else "" + conns.append({"uuid": uuid, "name": name, "device": dev}) + return conns + +def prompt_config(conn): + default_iface = conn['device'] + if not default_iface: + default_iface = input(f"Podaj nazwę interfejsu dla połączenia '{conn['name']}' ({conn['uuid']}): ").strip() + + print(f"\n--- Konfiguracja dla interfejsu: {default_iface} ({conn['name']}) ---") + ip = input("Adres IP/maska (np. 10.87.2.121/24): ").strip() + + # domyślna brama z IP + ip_parts = ip.split(".") + default_gw = f"{ip_parts[0]}.{ip_parts[1]}.{ip_parts[2]}.1" if len(ip_parts) >= 4 else "" + + gw_input = input(f"Brama (enter = brak, d = {default_gw}): ").strip().lower() + if gw_input == "d": + gw = default_gw + elif gw_input == "": + gw = None + else: + gw = gw_input + + third_octet = ip_parts[2] if len(ip_parts) >= 3 else "100" + default_table = third_octet + default_prio = third_octet + + table = input(f"Numer tablicy routingu [domyślnie {default_table}]: ").strip() or default_table + prio = input(f"Priorytet dla rule [domyślnie {default_prio}]: ").strip() or default_prio + + return { + "uuid": conn["uuid"], + "iface": default_iface, + "ip": ip, + "gateway": gw, + "table": table, + "priority": prio + } + +def ask_disable_ipv6(devices): + choice = input("\nWyłączyć IPv6? (tak/wszystkie/nie/[lista interfejsów oddzielona spacją]): ").strip().lower() + if choice in ["tak", "yes", "y", "wszystkie"]: + return set(devices) + elif choice in ["nie", "no", "n"]: + return set() + else: + return set(choice.split()) + +def ask_main_gateway_iface(devices): + print("\nDostępne interfejsy: " + ", ".join(devices)) + main_iface = input("Podaj nazwę interfejsu, który ma mieć bramę główną (main), enter jeśli żaden: ").strip() + return main_iface if main_iface in devices else None + +def generate_commands(configs, disable_ipv6_ifaces, main_iface): + lines = [] + rt_tables = set() + + for c in configs: + uuid = c["uuid"] + iface = c["iface"] + ip = c["ip"] + gateway = c["gateway"] + table = c["table"] + priority = c["priority"] + + lines.append(f"# Konfiguracja: {iface} ({uuid}) → {ip} gw {gateway or '-'} table {table}") + + # Ustawienia podstawowe + lines.append(f"nmcli con modify {uuid} connection.interface-name {iface}") + lines.append(f"nmcli con modify {uuid} ipv4.addresses {ip} ipv4.method manual") + lines.append(f"nmcli con modify {uuid} ipv4.never-default yes") + + # IPv6 wyłączony jeśli wskazano + if iface in disable_ipv6_ifaces: + lines.append(f"nmcli con modify {uuid} ipv6.method ignore") + + # Parsowanie adresu IP bez maski + ip_only = ip.split("/")[0] + + # Obsługa tras i reguł tylko jeśli podano bramę + if gateway: + if iface == main_iface: + # tylko tu ustawiamy bramę domyślną + lines.append(f"nmcli con modify {uuid} ipv4.gateway {gateway}") + else: + # trasa i reguła do osobnej tablicy + lines.append(f"nmcli con modify {uuid} +ipv4.routes \"0.0.0.0/0 {gateway} table={table}\"") + lines.append(f"nmcli con modify {uuid} ipv4.routing-rules \"priority {priority} from {ip_only}/32 table {table}\"") + rt_tables.add(f"{table} rt{table}") + + lines.append("") # pusta linia dla czytelności + + # Restart połączeń + lines.append("# Restart połączeń") + for c in configs: + lines.append(f"nmcli con down {c['uuid']} || true") + lines.append(f"nmcli con up {c['uuid']}") + + # Dodaj wpisy do rt_tables tylko dla użytych tablic + rt_path = detect_rt_tables_path() + lines.append(f"\n# Wpisy do {rt_path}") + if "rt_tables.d" in rt_path: + lines.append("mkdir -p /etc/iproute2/rt_tables.d") + for rt in sorted(rt_tables): + lines.append(f"echo \"{rt}\" | sudo tee -a {rt_path} > /dev/null") + + return "\n".join(lines) + + +def main(): + connections = list_connections() + + print("\n[DEBUG] Wykryto połączenia:") + for c in connections: + print(f"- {c['name']} ({c['uuid']}) → {c['device']}") + + if len(connections) == 0: + print("Brak połączeń ethernet.") + return + + devices = [c["device"] for c in connections] + disable_ipv6_ifaces = ask_disable_ipv6(devices) + main_iface = ask_main_gateway_iface(devices) + configs = [prompt_config(c) for c in connections] + result = generate_commands(configs, disable_ipv6_ifaces, main_iface) + + print("\n=== Wygenerowane polecenia ===\n") + print(result) + + with open("nmcli_setup.sh", "w") as f: + f.write(result) + print("\nZapisano do pliku: nmcli_setup.sh") + +if __name__ == "__main__": + main()