Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.5.0</Version>
<Version>1.0.0</Version>
<Authors>Manfred Heil Junior</Authors>
<Company>MT - Manfred Tecnologia</Company>
<Product>MapNet - MT</Product>
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MapNet - MT

Scanner de inventário de rede para Windows, da MT - Manfred Tecnologia. Roda na rede do cliente e mostra quais equipamentos estão ligados nela, com IP, MAC, fabricante e nome, num relatório HTML que abre em qualquer navegador.
Scanner de inventário de rede para Windows, da MT - Manfred Tecnologia. Roda na rede do cliente e mostra quais equipamentos estão ligados nela, com IP, MAC, fabricante, nome, tipo provável e, se você pedir, portas abertas e serviços, num relatório em HTML, CSV ou XML.

Página do programa: **https://mapnet.manfred.com.br**. Download da versão mais recente: [mapnet.exe](https://github.com/manfredjr/mapnet/releases/latest/download/mapnet.exe).

Expand All @@ -25,9 +25,9 @@ As regras do projeto estão no [`AGENTS.md`](AGENTS.md) e o desenho em [`docs/su
| 5 | Ações de manutenção com elevação sob demanda, na aba Manutenção do console (sai como v0.2.4) | `manutencao` | [#18](https://github.com/manfredjr/mapnet/pull/18) | Publicada na v0.2.5 |
| 6 | Painel de detalhe do host, com ping, tracert, navegador, área de trabalho remota e pasta compartilhada (sai como v0.2.5) | `detalhe-host` | [#19](https://github.com/manfredjr/mapnet/pull/19) | Publicada na v0.2.5 |
| 7 | Portas TCP comuns abertas, com lista configurável, desligadas por padrão e com confirmação por rede (sai como v0.3.0) | `portas` | Plano em [#26](https://github.com/manfredjr/mapnet/pull/26), código em [#31](https://github.com/manfredjr/mapnet/pull/31) | Publicada na v0.3.0 |
| 8 | Identificação leve dos serviços nas portas abertas: título da página, certificado HTTPS, banner SSH, FTP e SMTP, e UPnP (sai como v0.4.0) | `identificacao-servicos` | Plano em [#32](https://github.com/manfredjr/mapnet/pull/32), código em [#34](https://github.com/manfredjr/mapnet/pull/34) | Em revisão |
| 9 | Classificação por tipo de equipamento, com os motivos à vista (sai como v0.5.0) | `classificacao` | [#35](https://github.com/manfredjr/mapnet/pull/35) | Em revisão |
| 10 | Relatório também em XML e CSV (sai como v1.0.0) | a definir | - | A fazer |
| 8 | Identificação leve dos serviços nas portas abertas: título da página, certificado HTTPS, banner SSH, FTP e SMTP, e UPnP (sai como v0.4.0) | `identificacao-servicos` | Plano em [#32](https://github.com/manfredjr/mapnet/pull/32), código em [#34](https://github.com/manfredjr/mapnet/pull/34) | Publicada na v1.0.0 |
| 9 | Classificação por tipo de equipamento, com os motivos à vista (sai como v0.5.0) | `classificacao` | [#35](https://github.com/manfredjr/mapnet/pull/35) | Publicada na v1.0.0 |
| 10 | Relatório também em CSV e XML, pela janela e pela linha de comando (sai como v1.0.0) | `relatorios` | [#36](https://github.com/manfredjr/mapnet/pull/36) | Publicada na v1.0.0 |

A versão 0.2 segue o desenho em [`docs/superpowers/specs/2026-09-25-mapnet-0.2-painel-do-tecnico-design.md`](docs/superpowers/specs/2026-09-25-mapnet-0.2-painel-do-tecnico-design.md).

Expand All @@ -45,7 +45,7 @@ O programa é um arquivo só, `mapnet.exe`. Não precisa instalar nada no comput
4. Para saber também as portas abertas de cada equipamento, marque **Verificar portas** acima da tabela. A **Lista** vem com `padrão`, as 24 portas comuns (a dica do campo mostra quais são), ou aceita até 100 portas separadas por vírgula, como `80,443,9100`. Os aparelhos com MAC aleatório, quase sempre celulares e notebooks pessoais, ficam de fora, a não ser que você marque **Incluir aparelhos com MAC aleatório**. **Identificar serviços** vem marcado e preenche a coluna **Serviço** com o que o equipamento diz de si: modelo pelo UPnP, título da página, certificado ou banner. Na primeira varredura com portas em cada rede, o programa diz o que vai enviar e pede confirmação. Use só em rede que você tem autorização para verificar.
5. Clique em **Iniciar varredura**. Clicar numa linha da tabela abre, ao lado, o detalhe do host: MAC, fabricante, os nomes pelo DNS reverso, NetBIOS e mDNS, o grupo de trabalho, o ping com o TTL, uma pista do sistema pelo TTL e as portas abertas, com o serviço de cada uma. Os botões do detalhe fazem ping contínuo e tracert no console, abrem http e https no navegador (na 8080, 8000 ou 8443 quando só ela está aberta, e desligados quando as portas web foram verificadas e estão fechadas), a área de trabalho remota e a pasta compartilhada, e copiam os dados. Um novo clique na mesma linha, a tecla Esc ou o botão **Fechar** fecham o detalhe. A tabela vai se enchendo enquanto os hosts respondem, e o mesmo botão vira **Cancelar**. O campo **Filtrar** procura por IP, nome, MAC, fabricante, observação ou número de porta aberta (`9100` lista as impressoras), e cada coluna ordena com um clique no título.
6. O console embaixo registra o andamento e os avisos, e a barra de estado mostra o resumo. O console tem também uma aba para cada ferramenta: Ping (normal ou contínuo), Tracert, DNS com escolha do servidor, ARP, Conexões e Rotas. Os campos de host e de servidor DNS já vêm com o gateway e o DNS da interface. Enquanto a ferramenta roda, **Executar** vira **Parar**. **Copiar** e **Limpar** valem para a aba aberta.
7. No fim, clique em **Salvar relatório** e escolha onde gravar o arquivo HTML. A janela abre em `Documentos\MapNet - MT` com um nome pronto, e da segunda vez abre na pasta usada por último. O programa não grava sozinho: fechar a janela com a varredura sem salvar pergunta antes. O botão **Abrir** abre o relatório salvo no navegador ou a pasta dele.
7. No fim, clique em **Salvar relatório**, escolha onde gravar e o tipo: HTML, para abrir no navegador; CSV, para o Excel; ou XML, para outro programa ler. A janela abre em `Documentos\MapNet - MT` com um nome pronto, e da segunda vez abre na pasta usada por último. O programa não grava sozinho: fechar a janela com a varredura sem salvar pergunta antes. O botão **Abrir** abre o relatório salvo no navegador ou a pasta dele.
8. A aba **Manutenção** tem quatro botões, que rodam os comandos oficiais do Windows e mostram a saída ali mesmo: **Limpar cache DNS** (`ipconfig /flushdns`), **Liberar e renovar IP** (`ipconfig /release` e `/renew`), **Limpar tabela ARP** (`netsh interface ip delete arpcache`) e **Resetar Winsock e TCP/IP** (`netsh winsock reset` e `netsh int ip reset`). O programa continua abrindo como usuário comum. Quando a ação pede administrador, o Windows mostra a tela do UAC só para aquele comando. Renovar o IP e resetar o Winsock derrubam a rede por alguns segundos e pedem confirmação antes. O reset só vale depois de reiniciar o computador.

### Pela linha de comando
Expand All @@ -61,9 +61,10 @@ mapnet --ajuda
| Opção | Para que serve |
|---|---|
| `--interfaces` | Lista as interfaces ativas, numeradas |
| `--varrer` | Varre a sub-rede e grava o relatório HTML |
| `--varrer` | Varre a sub-rede e grava o relatório (HTML, ou o formato de `--formato`) |
| `--interface <n ou nome>` | Escolhe a interface pelo número de `--interfaces`, pelo nome ou pelo IP |
| `--saida <pasta ou arquivo.html>` | Onde gravar o relatório. Padrão: a pasta atual |
| `--saida <pasta ou arquivo>` | Onde gravar o relatório. Padrão: a pasta atual. Arquivo terminado em `.html`, `.csv` ou `.xml` define o formato |
| `--formato <f>` | `html`, `csv`, `xml` ou `todos`. Padrão: `html`. Com `todos`, grava os três na pasta de `--saida` |
| `--abrir` | Abre o relatório no navegador ao terminar |
| `--tempo-ping <ms>` | Espera de cada ping, de 100 a 10000. Padrão: 1000 |
| `--paralelo <n>` | Endereços sondados ao mesmo tempo, de 1 a 256. Padrão: 64 |
Expand Down Expand Up @@ -111,6 +112,7 @@ Se o valor bater com o do `.txt`, o executável é exatamente o que foi publicad
- **Fabricante:** pelos três primeiros bytes do MAC, na tabela OUI do IEEE embutida no programa (35.084 prefixos). MAC com o bit de administração local ligado aparece como "MAC aleatório (privativo)", que é o caso do celular com endereço privado.
- **Nome:** DNS reverso, NetBIOS (o mesmo do `nbtstat -A`, que traz também o grupo de trabalho ou domínio) e mDNS (nomes `.local` de celulares, Macs, impressoras e aparelhos Linux).
- **Relatório HTML:** arquivo único, com resumo da varredura, cartões de contagem, tabela filtrável e ordenável, detalhe de cada host ao clicar na linha e a lista de fabricantes.
- **CSV e XML (desde a v1.0.0):** o CSV tem uma linha por host, com ponto e vírgula e acentos certos no Excel, e protege contra texto que viraria fórmula. O XML traz tudo o que o HTML mostra, para outro programa ler.

- **Portas (desde a v0.3.0, desligadas por padrão):** para cada host encontrado, abre e fecha a conexão TCP em cada porta da lista, sem enviar nenhum dado, com até 128 conexões ao mesmo tempo, 8 por host e 800 ms de espera por porta. Porta que aceita a conexão aparece como aberta. Este computador e os aparelhos com MAC aleatório ficam de fora, e o motivo aparece no detalhe. O relatório ganha a coluna Portas e diz quais portas foram verificadas.
- **Tipo provável (desde a v0.5.0):** roteador, impressora, câmera ou gravador, NAS, computador Windows, Linux, access point, TV ou mídia, videogame, celular ou tablet, automação ou desconhecido. É um palpite pelo que as outras etapas levantaram (fabricante, nomes, TTL, portas e serviços), sem mandar nada para a rede, e o detalhe mostra os motivos.
Expand Down
7 changes: 7 additions & 0 deletions docs/superpowers/pendencias.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ Fechado em parte na fatia 3 (0.2.2). No tamanho padrão da janela, IP, Origem, M
| Tabela de sinais | Os fabricantes e as palavras que apontam cada tipo saíram do que é comum em escritório e do teste na rede do Manfred. Equipamento de marca que não está na lista cai em Desconhecido | Acrescentar fabricante ou palavra quando o técnico achar um caso errado no campo |
| Switch gerenciável | Switch quase não se mostra: não costuma ter nome, porta aberta diferente nem UPnP. A fatia não arrisca esse tipo | Rever se aparecer sinal confiável, como título de página de switch conhecido |

## Fatia 10: relatório em CSV e XML

| Item | Motivo | O que fecha |
|---|---|---|
| Esquema do XML | O XML tem o atributo `formato="1"` para mudar sem quebrar quem lê, mas não tem um XSD publicado | Publicar o esquema se alguém for integrar o XML a outro sistema |
| CSV no Excel com outro idioma | O ponto e vírgula é o separador do Excel em português. Num Excel em inglês, o arquivo abre numa coluna só | Importar pelo assistente de texto, ou oferecer vírgula como opção se fizer falta |

## Página de privacidade

| Item | Motivo | O que fecha |
Expand Down
18 changes: 17 additions & 1 deletion docs/superpowers/plans/2026-09-26-mapnet-1.0-plano-geral.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,20 @@ Sai como v0.5.0. Escrita junto com o código, porque o Manfred pediu em 26/09/20

### Testes

Cada tipo pelos seus sinais, o mínimo para arriscar, o sinal mais forte ganhando, a palavra inteira, este computador como Windows, e o tipo na tabela, no detalhe e no relatório.
Cada tipo pelos seus sinais, o mínimo para arriscar, o sinal mais forte ganhando, a palavra inteira, este computador como Windows, e o tipo na tabela, no detalhe e no relatório.

## Fatia 10: relatório em XML e CSV

Sai como v1.0.0 e fecha a versão 1.0. Escrita junto com o código, como a fatia 9.

### O que entra

- **CSV**, uma linha por host, para abrir no Excel: IP, nome e origem, MAC, fabricante, tipo provável e motivos, ping, TTL, portas, serviço, serviços, observação e grupo NetBIOS. Separador ponto e vírgula, que é o do Excel em português, e UTF-8 com BOM, para os acentos abrirem certos.
- **Proteção contra fórmula:** campo que começa com `=`, `+`, `-` ou `@` ganha um apóstrofo na frente. Nome de equipamento vem da rede e não pode virar fórmula na planilha do cliente.
- **XML**, com tudo o que o HTML mostra (varredura, Minha máquina, avisos e cada host com nomes, ping, ARP, tipo e motivos, portas e serviços), para outro programa ler. Caractere que o XML recusa é tirado antes.
- **Janela:** o botão **Salvar relatório** oferece os três tipos na lista da janela de salvar.
- **Linha de comando:** `--formato html|csv|xml|todos`. Arquivo com extensão em `--saida` define o formato; com `todos`, `--saida` é a pasta dos três.

### Testes

XML válido e completo, texto da rede codificado, caractere inválido tirado; CSV com cabeçalho, aspas, ponto e vírgula e a proteção contra fórmula; BOM no CSV e não no XML; formato pela extensão; caminhos da linha de comando e os erros de formato.
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ <h2>O que ele faz</h2>
<div><h3>Detalhe de cada equipamento</h3><p>Nomes, TTL, portas abertas, serviços e atalhos para ping, navegador e área de trabalho remota.</p></div>
<div><h3>Ferramentas de rede</h3><p>Ping, tracert, DNS, ARP, conexões e rotas, com a saída em português.</p></div>
<div><h3>Manutenção</h3><p>Limpar o cache DNS, renovar o IP, limpar o ARP e resetar o Winsock.</p></div>
<div><h3>Relatório em HTML</h3><p>Arquivo único para guardar com a documentação do cliente.</p></div>
<div><h3>Relatório em HTML, CSV e XML</h3><p>Para guardar com a documentação do cliente, abrir no Excel ou levar a outro programa.</p></div>
<div><h3>Sem instalar nada</h3><p>Um arquivo só, sem administrador e sem precisar de internet.</p></div>
</div>
</section>
Expand Down
61 changes: 58 additions & 3 deletions src/mapnet.nucleo/linha-de-comando/argumentos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ mapnet abre a janela
Opções de --varrer:
--interface <n ou nome> interface pelo número de --interfaces ou por parte do nome
(padrão: a primeira da lista, que é a que tem gateway)
--saida <pasta ou .html> onde gravar o relatório (padrão: pasta atual)
--saida <pasta ou arquivo> onde gravar o relatório (padrão: pasta atual). Arquivo
terminado em .html, .csv ou .xml define o formato
--formato <f> html, csv, xml ou todos (padrão: html). Com todos,
grava os três na pasta de --saida
--abrir abre o relatório no navegador ao terminar
--tempo-ping <ms> espera de cada ping, de 100 a 10000 (padrão: 1000)
--paralelo <n> endereços sondados ao mesmo tempo, de 1 a 256 (padrão: 64)
Expand Down Expand Up @@ -58,6 +61,9 @@ Use a verificação de portas só em rede que você tem autorização para verif

public bool Abrir { get; private set; }

/// <summary>Formatos a gravar. Padrão: só o HTML.</summary>
public IReadOnlyList<FormatoRelatorio> Formatos { get; private set; } = [FormatoRelatorio.Html];

public OpcoesVarredura Opcoes { get; } = new();

public List<string> Erros { get; } = [];
Expand All @@ -69,6 +75,7 @@ public static ArgumentosCli Interpretar(IReadOnlyList<string> args)
var a = new ArgumentosCli();
var comandos = 0;
var semIdentificar = false;
var formatoDado = false;

for (var i = 0; i < args.Count; i++)
{
Expand Down Expand Up @@ -101,6 +108,25 @@ public static ArgumentosCli Interpretar(IReadOnlyList<string> args)
case "--abrir":
a.Abrir = true;
break;
case "--formato":
var formato = Valor(args, ref i, arg, a.Erros)?.Trim().ToLowerInvariant();
IReadOnlyList<FormatoRelatorio>? escolhidos = formato switch
{
null => null,
"html" => [FormatoRelatorio.Html],
"csv" => [FormatoRelatorio.Csv],
"xml" => [FormatoRelatorio.Xml],
"todos" => [FormatoRelatorio.Html, FormatoRelatorio.Csv, FormatoRelatorio.Xml],
_ => null,
};
if (escolhidos is null && formato != null)
{
a.Erros.Add($"Formato desconhecido: {formato}. Use html, csv, xml ou todos.");
}

a.Formatos = escolhidos ?? a.Formatos;
formatoDado = true;
break;
case "--sem-arp":
a.Opcoes.UsarArp = false;
break;
Expand Down Expand Up @@ -149,10 +175,23 @@ public static ArgumentosCli Interpretar(IReadOnlyList<string> args)
a.Erros.Add("Use só um comando por vez: --varrer, --interfaces, --ajuda ou --versao.");
}

var opcoesDeVarredura = a.Interface != null || a.Saida != null || a.Abrir || a.Opcoes.OlharPortas;
var opcoesDeVarredura = a.Interface != null || a.Saida != null || a.Abrir || a.Opcoes.OlharPortas || formatoDado;
if (opcoesDeVarredura && a.Comando == ComandoCli.Janela)
{
a.Erros.Add("As opções --interface, --saida, --abrir e --portas pedem o comando --varrer.");
a.Erros.Add("As opções --interface, --saida, --formato, --abrir e --portas pedem o comando --varrer.");
}

// Arquivo com extensão conhecida em --saida define o formato. Com mais de um formato, --saida tem que ser pasta.
if (a.Saida is { } saida && Path.HasExtension(saida) && Path.GetExtension(saida).ToLowerInvariant() is ".html" or ".htm" or ".csv" or ".xml")
{
if (a.Formatos.Count > 1)
{
a.Erros.Add("Com --formato todos, --saida tem que ser uma pasta.");
}
else
{
a.Formatos = [Relatorios.FormatoDe(saida)];
}
}

if (a.Opcoes.PortasEmMacAleatorio && !a.Opcoes.OlharPortas)
Expand All @@ -168,6 +207,22 @@ public static ArgumentosCli Interpretar(IReadOnlyList<string> args)
return a;
}

/// <summary>
/// Arquivos a gravar, um por formato. Sem --saida, vão para a pasta atual; com uma pasta, para
/// ela; com um arquivo de extensão conhecida, é ele mesmo.
/// </summary>
public IReadOnlyList<string> Caminhos(ResultadoVarredura resultado, string pastaAtual)
{
if (Saida is { } saida && Formatos.Count == 1
&& Path.GetExtension(saida).ToLowerInvariant() is ".html" or ".htm" or ".csv" or ".xml")
{
return [saida];
}

var pasta = string.IsNullOrWhiteSpace(Saida) ? pastaAtual : Saida;
return Formatos.Select(f => Path.Combine(pasta, Relatorios.NomeArquivo(resultado, f))).ToList();
}

/// <summary>
/// Escolhe a interface pelo número (a partir de 1, na ordem de --interfaces) ou por parte
/// do nome ou da descrição. Sem seletor, fica a primeira da lista.
Expand Down
2 changes: 1 addition & 1 deletion src/mapnet.nucleo/painel/demonstracao.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public static DependenciasPainel Dependencias()
Opcoes = opcoes,
ListarInterfaces = () => [wifi, cabo],
Varrer = (i, p, c) => VarrerAsync(i, opcoes, p, c),
SalvarEm = (r, caminho) => RelatorioHtml.SalvarAsync(r, caminho),
SalvarEm = (r, caminho) => Relatorios.SalvarAsync(r, caminho),
// Documentos Públicos: o caminho não traz o nome do usuário, que apareceria nas imagens.
PastaRelatorios = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments), "MapNet - MT", "demonstracao"),
LerMaquina = i => Task.FromResult(LeitorMaquina.Ler(i, Fontes(), new OpcoesVarredura().PrefixoMinimo)),
Expand Down
2 changes: 1 addition & 1 deletion src/mapnet.nucleo/painel/painel-varredura.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public static DependenciasPainel Padrao()
Opcoes = opcoes,
ListarInterfaces = LeitorInterfaces.Listar,
Varrer = (i, p, c) => new Varredor(opcoes).VarrerAsync(i, p, c),
SalvarEm = (r, caminho) => RelatorioHtml.SalvarAsync(r, caminho),
SalvarEm = (r, caminho) => Relatorios.SalvarAsync(r, caminho),
LerMaquina = i => Task.Run(() => LeitorMaquina.Ler(i, FontesMaquina.Padrao(), prefixo)),
IpPublico = new IpPublicoCloudflare(),
Ferramentas = FerramentasPadrao,
Expand Down
Loading
Loading