From 2b8fdf15c0455bcbb34e0ecc2c7251ef134992fd Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:21:28 -0300 Subject: [PATCH 1/9] Harden scans and fix DNS lookup --- README.md | 3 +-- info_analysis.py | 2 +- main.py | 1 + network_scanner.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 - 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9783a3b..a531e18 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,6 @@ O arquivo `requirements.txt` contém: ``` scapy python-nmap -requests whois colorama ``` @@ -134,5 +133,5 @@ sudo python3 main.py sniff -t 30 * **Privilégios de Root (sudo):** As funcionalidades de baixo nível de rede, como **ARP Scan** e **Sniffer de Rede**, exigem privilégios de root (`sudo`) para acessar a interface de rede e enviar/receber pacotes brutos. * **Uso Ético:** Esta ferramenta é destinada a fins educacionais e testes de penetração **autorizados**. O uso indevido contra sistemas sem permissão expressa é ilegal e antiético. O desenvolvedor não se responsabiliza por qualquer uso indevido desta ferramenta. +* **Validação de entradas:** Os módulos de varredura validam alvo e faixa de portas para reduzir erros e evitar entradas inválidas. Garanta que os alvos estejam corretos antes de executar os scans. * **Interface:** A aplicação utiliza a biblioteca `colorama` para uma melhor experiência visual no terminal. - diff --git a/info_analysis.py b/info_analysis.py index b283816..57a2c2b 100644 --- a/info_analysis.py +++ b/info_analysis.py @@ -1,7 +1,7 @@ import hashlib import os +import socket import whois -import requests from colorama import Fore, Style def calculate_file_hash(file_path, algorithm='sha256'): diff --git a/main.py b/main.py index bc1aae8..e83129e 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,7 @@ import argparse import sys import os +import whois from colorama import Fore, Style, init # Inicializa colorama para funcionar em diferentes terminais diff --git a/network_scanner.py b/network_scanner.py index 9e7496d..56b6c33 100644 --- a/network_scanner.py +++ b/network_scanner.py @@ -1,13 +1,55 @@ +import ipaddress import nmap +import re import socket from scapy.all import ARP, Ether, srp from colorama import Fore, Style +PORTS_PATTERN = re.compile(r"^\d{1,5}(-\d{1,5})?(,\d{1,5}(-\d{1,5})?)*$") + +def _is_valid_ports(ports): + if not ports or not PORTS_PATTERN.match(ports): + return False + for part in ports.split(","): + if "-" in part: + start, end = part.split("-", 1) + if not (start.isdigit() and end.isdigit()): + return False + start_i, end_i = int(start), int(end) + if start_i < 1 or end_i > 65535 or start_i > end_i: + return False + else: + if not part.isdigit(): + return False + value = int(part) + if value < 1 or value > 65535: + return False + return True + +def _is_valid_target(target): + if not target or any(char.isspace() for char in target): + return False + try: + ipaddress.ip_address(target) + return True + except ValueError: + pass + if len(target) > 253: + return False + label_regex = re.compile(r"^[A-Za-z0-9-]{1,63}$") + parts = target.rstrip(".").split(".") + return all(part and label_regex.match(part) and not part.startswith("-") and not part.endswith("-") for part in parts) + def arp_scan(ip_range): """ Realiza um ARP Scan para descobrir hosts ativos na rede local. Requer privilégios de root (sudo) para funcionar corretamente. """ + try: + ipaddress.ip_network(ip_range, strict=False) + except ValueError: + print(f"{Fore.RED}Erro: Faixa de IP inválida para ARP Scan (ex: 192.168.1.0/24).{Style.RESET_ALL}") + return [] print(f"{Fore.CYAN}Iniciando ARP Scan em {ip_range}...{Style.RESET_ALL}") try: # Cria o pacote ARP @@ -38,6 +80,12 @@ def port_scan(target_ip, ports='1-1024'): """ Realiza um Port Scan TCP usando nmap. """ + if not _is_valid_target(target_ip): + print(f"{Fore.RED}Erro: Alvo inválido para o Port Scan. Use um IP ou domínio válido.{Style.RESET_ALL}") + return {} + if not _is_valid_ports(ports): + print(f"{Fore.RED}Erro: Faixa de portas inválida. Use números de 1-65535 separados por vírgulas ou intervalos (ex: 22,80,443 ou 1-100).{Style.RESET_ALL}") + return {} print(f"{Fore.CYAN}Iniciando Port Scan em {target_ip} (Portas: {ports})...{Style.RESET_ALL}") try: nm = nmap.PortScanner() diff --git a/requirements.txt b/requirements.txt index d196799..200fcce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ scapy python-nmap -requests whois colorama From 430cb80e5b587610b2ec9dbb6b4f1007ffe66f55 Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:25:18 -0300 Subject: [PATCH 2/9] Use documentation-safe IP examples --- README.md | 2 +- network_scanner.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a531e18..6ffa900 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ O toolkit é executado através do arquivo principal `main.py` com subcomandos. ```bash sudo python3 main.py net arp # Exemplo: -sudo python3 main.py net arp 192.168.1.1/24 +sudo python3 main.py net arp 192.0.2.0/24 ``` #### Port Scan (Varredura de Portas) diff --git a/network_scanner.py b/network_scanner.py index 56b6c33..b3ad3d2 100644 --- a/network_scanner.py +++ b/network_scanner.py @@ -48,7 +48,7 @@ def arp_scan(ip_range): try: ipaddress.ip_network(ip_range, strict=False) except ValueError: - print(f"{Fore.RED}Erro: Faixa de IP inválida para ARP Scan (ex: 192.168.1.0/24).{Style.RESET_ALL}") + print(f"{Fore.RED}Erro: Faixa de IP inválida para ARP Scan (ex: 192.0.2.0/24).{Style.RESET_ALL}") return [] print(f"{Fore.CYAN}Iniciando ARP Scan em {ip_range}...{Style.RESET_ALL}") try: @@ -122,7 +122,7 @@ def port_scan(target_ip, ports='1-1024'): if __name__ == '__main__': # Exemplo de uso (requer sudo para arp_scan) - # hosts = arp_scan("192.168.1.1/24") + # hosts = arp_scan("192.0.2.0/24") # print(hosts) # Exemplo de uso (não requer sudo) From 5c9ddeb790ae1e3565bc8cef8469aa8fb9e768e4 Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:39:31 -0300 Subject: [PATCH 3/9] Add interactive terminal UI mode --- README.md | 8 +++++++ main.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/README.md b/README.md index 6ffa900..3741b91 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,14 @@ colorama O toolkit é executado através do arquivo principal `main.py` com subcomandos. +### ✅ Modo Interativo (UI no Terminal) + +Se preferir uma experiência guiada, use o modo interativo com menu no terminal: + +```bash +python3 main.py ui +``` + ### 1. Análise de Rede (`net`) #### ARP Scan (Descoberta de Hosts) diff --git a/main.py b/main.py index e83129e..8e68c1e 100644 --- a/main.py +++ b/main.py @@ -77,6 +77,68 @@ def display_results(title, data): print(f"{Fore.YELLOW}A operação não retornou dados ou falhou.{Style.RESET_ALL}") +def _prompt_non_empty(prompt_text): + while True: + value = input(prompt_text).strip() + if value: + return value + print(f"{Fore.YELLOW}Entrada vazia. Tente novamente.{Style.RESET_ALL}") + + +def run_interactive_menu(): + """Executa um menu interativo para uso guiado do toolkit.""" + print(f"{Fore.GREEN}Modo interativo iniciado. Selecione uma opção:{Style.RESET_ALL}") + while True: + print( + f""" +{Fore.BLUE}1){Style.RESET_ALL} ARP Scan +{Fore.BLUE}2){Style.RESET_ALL} Port Scan +{Fore.BLUE}3){Style.RESET_ALL} Calcular Hash de Arquivo +{Fore.BLUE}4){Style.RESET_ALL} Whois Lookup +{Fore.BLUE}5){Style.RESET_ALL} DNS Lookup +{Fore.BLUE}6){Style.RESET_ALL} Sniffer de Pacotes +{Fore.BLUE}0){Style.RESET_ALL} Sair +""" + ) + choice = input("Opção: ").strip() + + if choice == "1": + ip_range = _prompt_non_empty("Faixa de IP (ex: 192.0.2.0/24): ") + results = arp_scan(ip_range) + display_results(f"Resultados do ARP Scan em {ip_range}", results) + elif choice == "2": + target = _prompt_non_empty("Alvo (IP ou domínio): ") + ports = input("Portas (ex: 22,80,443 ou 1-100) [1-1024]: ").strip() or "1-1024" + results = port_scan(target, ports) + display_results(f"Resultados do Port Scan em {target}", results) + elif choice == "3": + file_path = _prompt_non_empty("Caminho para o arquivo: ") + algorithm = input("Algoritmo [sha256]: ").strip() or "sha256" + file_hash = calculate_file_hash(file_path, algorithm) + display_results(f"Hash {algorithm.upper()} do Arquivo", file_hash) + elif choice == "4": + domain = _prompt_non_empty("Domínio (ex: example.com): ") + whois_info = whois_lookup(domain) + display_results(f"Whois Lookup para {domain}", whois_info) + elif choice == "5": + domain = _prompt_non_empty("Domínio (ex: example.com): ") + ip = dns_lookup(domain) + display_results(f"DNS Lookup para {domain}", ip) + elif choice == "6": + print(f"{Fore.YELLOW}Atenção: O Sniffer de Pacotes requer privilégios de root (sudo).{Style.RESET_ALL}") + interface = input("Interface (opcional): ").strip() or None + count_input = input("Número de pacotes (0 para ilimitado) [0]: ").strip() + timeout_input = input("Tempo limite em segundos (opcional): ").strip() + count = int(count_input) if count_input.isdigit() else 0 + timeout = int(timeout_input) if timeout_input.isdigit() else None + start_sniffer(interface, count, timeout) + elif choice == "0": + print(f"{Fore.GREEN}Encerrando modo interativo.{Style.RESET_ALL}") + break + else: + print(f"{Fore.YELLOW}Opção inválida. Escolha novamente.{Style.RESET_ALL}") + + def main(): print_banner() @@ -119,6 +181,9 @@ def main(): sniff_parser.add_argument('-c', '--count', type=int, default=0, help='Número de pacotes a capturar (0 para ilimitado)') sniff_parser.add_argument('-t', '--timeout', type=int, default=None, help='Tempo máximo de captura em segundos') + # --- Subparser para Interface --- + subparsers.add_parser('ui', help='Inicia o modo interativo com menu guiado') + args = parser.parse_args() @@ -145,6 +210,9 @@ def main(): print(f"{Fore.YELLOW}Atenção: O Sniffer de Pacotes requer privilégios de root (sudo) para funcionar corretamente.{Style.RESET_ALL}") start_sniffer(args.interface, args.count, args.timeout) + elif args.command == 'ui': + run_interactive_menu() + elif args.command is None: parser.print_help() From e3fbcb31e3ba312732d6eaece160abacb7c4015c Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:43:47 -0300 Subject: [PATCH 4/9] Remove requirements file and inline install --- README.md | 13 +++---------- requirements.txt | 4 ---- 2 files changed, 3 insertions(+), 14 deletions(-) delete mode 100644 requirements.txt diff --git a/README.md b/README.md index 3741b91..04b54a8 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,8 @@ pkg install nmap python libpcap -y #### 🐍 Instalação das Bibliotecas Python (Comum a todos) ```bash -# Instalar as bibliotecas Python -pip3 install -r requirements.txt +# Instalar as bibliotecas Python em um único comando +pip3 install scapy python-nmap whois colorama ``` #### 🐧 Debian/Ubuntu @@ -59,14 +59,7 @@ sudo apt update sudo apt install -y nmap python3-scapy ``` -O arquivo `requirements.txt` contém: - -``` -scapy -python-nmap -whois -colorama -``` +As dependências Python são: `scapy`, `python-nmap`, `whois`, `colorama`. ## ⚙️ Como Usar diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 200fcce..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -scapy -python-nmap -whois -colorama From beb08546d68d4d0d9588fc2d3c07e2a823c084f5 Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:46:41 -0300 Subject: [PATCH 5/9] Harden input handling and examples --- info_analysis.py | 3 +++ main.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/info_analysis.py b/info_analysis.py index 57a2c2b..56cecbd 100644 --- a/info_analysis.py +++ b/info_analysis.py @@ -13,6 +13,9 @@ def calculate_file_hash(file_path, algorithm='sha256'): if not os.path.exists(file_path): print(f"{Fore.RED}Erro: Arquivo não encontrado em {file_path}{Style.RESET_ALL}") return None + if not os.path.isfile(file_path): + print(f"{Fore.RED}Erro: O caminho informado não é um arquivo válido.{Style.RESET_ALL}") + return None hash_func = hashlib.new(algorithm) with open(file_path, 'rb') as f: diff --git a/main.py b/main.py index 8e68c1e..5a083d5 100644 --- a/main.py +++ b/main.py @@ -151,7 +151,7 @@ def main(): # ARP Scan arp_parser = net_subparsers.add_parser('arp', help='Realiza um ARP Scan para descoberta de hosts (Requer sudo)') - arp_parser.add_argument('ip_range', help='Faixa de IP (ex: 192.168.1.1/24)') + arp_parser.add_argument('ip_range', help='Faixa de IP (ex: 192.0.2.0/24)') # Port Scan port_parser = net_subparsers.add_parser('port', help='Realiza um Port Scan TCP (usando nmap)') From 3d688798639a2c994ca2afd2ac465f6fad97d391 Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:06:55 -0300 Subject: [PATCH 6/9] Document troubleshooting steps --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 04b54a8..4d49b21 100644 --- a/README.md +++ b/README.md @@ -136,3 +136,11 @@ sudo python3 main.py sniff -t 30 * **Uso Ético:** Esta ferramenta é destinada a fins educacionais e testes de penetração **autorizados**. O uso indevido contra sistemas sem permissão expressa é ilegal e antiético. O desenvolvedor não se responsabiliza por qualquer uso indevido desta ferramenta. * **Validação de entradas:** Os módulos de varredura validam alvo e faixa de portas para reduzir erros e evitar entradas inválidas. Garanta que os alvos estejam corretos antes de executar os scans. * **Interface:** A aplicação utiliza a biblioteca `colorama` para uma melhor experiência visual no terminal. + +## 🧰 Solução de Problemas (Troubleshooting) + +Se você encontrar falhas na execução, revise os pontos abaixo: + +* **Erro ao usar `scapy` ou `nmap`:** instale as dependências de sistema (`nmap` e `python3-scapy` ou equivalentes) conforme as instruções de Fedora/Ubuntu/Termux acima. +* **PermissionError em `net arp` ou `sniff`:** execute com `sudo`, pois essas operações precisam de acesso à interface de rede. +* **Ambiente virtual (venv):** se estiver usando venv, pode ser necessário executar o Python do venv com `sudo` para que o `scapy` tenha acesso às interfaces de rede. From 20a35d3be7b4a849fc9ee6c606edcca634ec1142 Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:07:01 -0300 Subject: [PATCH 7/9] Pin dependencies and add license --- LICENSE | 21 +++++++++++++++++++++ README.md | 22 ++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c13f991 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 4d49b21..ec629cd 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ pkg install nmap python libpcap -y ```bash # Instalar as bibliotecas Python em um único comando -pip3 install scapy python-nmap whois colorama +pip3 install scapy==2.5.0 python-nmap==0.7.1 whois==0.9.27 colorama==0.4.6 ``` #### 🐧 Debian/Ubuntu @@ -59,7 +59,21 @@ sudo apt update sudo apt install -y nmap python3-scapy ``` -As dependências Python são: `scapy`, `python-nmap`, `whois`, `colorama`. +As dependências Python são: `scapy==2.5.0`, `python-nmap==0.7.1`, `whois==0.9.27`, `colorama==0.4.6`. + +### ✅ Instalação Rápida (Passo a Passo) + +```bash +# 1) Instalar dependências de sistema (exemplo Debian/Ubuntu) +sudo apt update +sudo apt install -y nmap python3-scapy + +# 2) Instalar dependências Python (com versões fixas) +pip3 install scapy==2.5.0 python-nmap==0.7.1 whois==0.9.27 colorama==0.4.6 + +# 3) Executar a ferramenta +python3 main.py --help +``` ## ⚙️ Como Usar @@ -144,3 +158,7 @@ Se você encontrar falhas na execução, revise os pontos abaixo: * **Erro ao usar `scapy` ou `nmap`:** instale as dependências de sistema (`nmap` e `python3-scapy` ou equivalentes) conforme as instruções de Fedora/Ubuntu/Termux acima. * **PermissionError em `net arp` ou `sniff`:** execute com `sudo`, pois essas operações precisam de acesso à interface de rede. * **Ambiente virtual (venv):** se estiver usando venv, pode ser necessário executar o Python do venv com `sudo` para que o `scapy` tenha acesso às interfaces de rede. + +## 📄 Licença + +Este projeto é distribuído sob a licença MIT. Consulte o arquivo `LICENSE` para detalhes. From cef996d787669d375e651370db04882c7c43792a Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:15:24 -0300 Subject: [PATCH 8/9] Add security and engineering notes --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index ec629cd..95d8953 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,15 @@ Se você encontrar falhas na execução, revise os pontos abaixo: * **PermissionError em `net arp` ou `sniff`:** execute com `sudo`, pois essas operações precisam de acesso à interface de rede. * **Ambiente virtual (venv):** se estiver usando venv, pode ser necessário executar o Python do venv com `sudo` para que o `scapy` tenha acesso às interfaces de rede. +## 🔒 Considerações de Segurança e Engenharia + +Para transparência e auditoria: + +* **Execução de comandos:** o toolkit não utiliza `eval`, `exec` ou `os.system`, evitando superfícies clássicas de injeção de comandos. +* **Validação de entrada:** há validações de alvo, faixa de portas, rede e caminhos de arquivo, reduzindo erros de execução e entradas malformadas. +* **Concorrência:** as varreduras atuais usam fluxo sequencial; para ambientes grandes, recomenda-se evoluir para `asyncio`/`threading` conforme o caso. +* **Logs e auditoria:** se você precisa de rastreabilidade, considere adicionar logging estruturado (ex.: módulo `logging`) com níveis apropriados e sem dados sensíveis. + ## 📄 Licença Este projeto é distribuído sob a licença MIT. Consulte o arquivo `LICENSE` para detalhes. From ea3c8041154f8362f6fb51aa51688c22cd8ad846 Mon Sep 17 00:00:00 2001 From: Paulo Ricardo <51494117+PaulMass@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:19:29 -0300 Subject: [PATCH 9/9] Validate domains and safer hash paths --- info_analysis.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/info_analysis.py b/info_analysis.py index 56cecbd..12e9c24 100644 --- a/info_analysis.py +++ b/info_analysis.py @@ -1,9 +1,26 @@ import hashlib import os import socket +import re import whois from colorama import Fore, Style +DOMAIN_LABEL_PATTERN = re.compile(r"^[A-Za-z0-9-]{1,63}$") + +def _is_valid_domain(domain): + if not domain or any(char.isspace() for char in domain): + return False + if len(domain) > 253: + return False + parts = domain.rstrip(".").split(".") + return all( + part + and DOMAIN_LABEL_PATTERN.match(part) + and not part.startswith("-") + and not part.endswith("-") + for part in parts + ) + def calculate_file_hash(file_path, algorithm='sha256'): """ Calcula o hash de um arquivo usando o algoritmo especificado. @@ -16,6 +33,9 @@ def calculate_file_hash(file_path, algorithm='sha256'): if not os.path.isfile(file_path): print(f"{Fore.RED}Erro: O caminho informado não é um arquivo válido.{Style.RESET_ALL}") return None + if os.path.islink(file_path): + print(f"{Fore.RED}Erro: Links simbólicos não são permitidos para cálculo de hash.{Style.RESET_ALL}") + return None hash_func = hashlib.new(algorithm) with open(file_path, 'rb') as f: @@ -39,6 +59,9 @@ def whois_lookup(domain): """ Realiza uma consulta Whois para um domínio. """ + if not _is_valid_domain(domain): + print(f"{Fore.RED}Erro: Domínio inválido para consulta Whois.{Style.RESET_ALL}") + return None print(f"{Fore.CYAN}Realizando consulta Whois para {domain}...{Style.RESET_ALL}") try: w = whois.whois(domain) @@ -53,6 +76,9 @@ def dns_lookup(domain): """ Realiza uma consulta DNS básica para obter o endereço IP. """ + if not _is_valid_domain(domain): + print(f"{Fore.RED}Erro: Domínio inválido para consulta DNS.{Style.RESET_ALL}") + return None print(f"{Fore.CYAN}Realizando consulta DNS para {domain}...{Style.RESET_ALL}") try: ip_address = socket.gethostbyname(domain)