Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save wellington1993/9997dec4724048094d7daceb3ed52286 to your computer and use it in GitHub Desktop.
Save wellington1993/9997dec4724048094d7daceb3ed52286 to your computer and use it in GitHub Desktop.
#!/bin/bash
# -----------------------------------------------------------------------------
# Script: report-portas-mesclado-ipv4-final-adaptado.sh
# Descricao: Mapeia conexoes TCP internas IPv4, usando root se disponível.
# Prioriza ESTAB para outros hosts.
# Exibe ESTABLISHED entre hosts internos diferentes E LISTEN.
# Oculta TODAS as conexoes ESTAB puramente locais (incluindo loopback).
# Oculta conexoes para/de IPs externos publicos IPv4.
# Exibe apenas IPv4. Remove linhas duplicadas. Ordena por Categoria, Server, Servico.
# -----------------------------------------------------------------------------
# --- Configuracoes ---
INTERNAL_PREFIX="192.168"
LOCAL_HOSTNAME=$(hostname)
LOCAL_IP=$(hostname -I | awk '{print $1}')
# Defina larguras fixas para as colunas (ajuste conforme necessario)
w1=36 # Cliente
w2=36 # Server
w3=20 # Servico
# Abreviacao de hostnames: no maximo 13 caracteres (ex.: HS-SRV-APP-03)
HOST_MAX=13
# --- Verificar se é root ---
if [ "$(id -u)" -eq 0 ]; then
IS_ROOT=1
else
IS_ROOT=0
echo "Aviso: Executando sem root. O relatório pode estar incompleto (apenas conexões do usuário atual)."
fi
# --- Funcoes de Pre-processamento de Conexao ---
if [ "$IS_ROOT" -eq 1 ]; then
# Coleta dados brutos de lsof para conexoes ESTABLISHED e LISTEN
function get_raw_connections_lsof() {
lsof -iTCP -P -n 2>/dev/null | awk '
/TCP/ {
if ($9 ~ /->/ && $0 ~ /\(ESTABLISHED\)/) {
split($9, conn_parts, "->"); local_part_str = conn_parts[1]; remote_part_str = conn_parts[2];
gsub(/\*:/, "0.0.0.0:", local_part_str);
if (match(local_part_str, /^(.*):([^:]+)$/, arr)) { local_ip = arr[1]; local_port = arr[2]; gsub(/\[|\]/, "", local_ip); }
else { local_ip="err_lsof_li"; local_port="err_lsof_lp"; }
gsub(/\*:/, "0.0.0.0:", remote_part_str);
if (match(remote_part_str, /^(.*):([^:]+)$/, arr)) { remote_ip = arr[1]; remote_port = arr[2]; gsub(/\[|\]/, "", remote_ip); }
else { remote_ip="err_lsof_ri"; remote_port="err_lsof_rp"; }
print "ESTABLISHED", local_ip, local_port, remote_ip, remote_port;
} else if ($0 ~ /\(LISTEN\)/) {
listen_addr_port = $9;
gsub(/\*:/, "0.0.0.0:", listen_addr_port); gsub(/\[::\]:/, ":::", listen_addr_port);
if (match(listen_addr_port, /^(.*):([^:]+)$/, arr)) { listen_ip = arr[1]; listen_port = arr[2]; gsub(/\[|\]/, "", listen_ip); }
else { listen_ip="err_lsof_lni"; listen_port="err_lsof_lnp"; }
print "LISTEN", listen_ip, listen_port;
}
}'
}
# Coleta dados brutos de ss para conexoes ESTAB e LISTEN
function get_raw_connections_ss() {
ss -tna 2>/dev/null | awk '
NR == 1 { next } # Pula o cabecalho do ss
{
state = $1; local_addr_port = $4; peer_addr_port = $5;
if (match(local_addr_port, /^(.*):([^:]+)$/, arr_local)) { local_ip = arr_local[1]; local_port = arr_local[2]; gsub(/\[|\]/, "", local_ip); }
else { local_ip="err_ss_li"; local_port="err_ss_lp"; }
if (state == "LISTEN") {
print "LISTEN", local_ip, local_port;
} else if (state == "ESTAB") {
if (match(peer_addr_port, /^(.*):([^:]+)$/, arr_peer)) { peer_ip = arr_peer[1]; peer_port = arr_peer[2]; gsub(/\[|\]/, "", peer_ip); }
else { peer_ip="err_ss_pi"; peer_port="err_ss_pp"; }
print "ESTABLISHED", local_ip, local_port, peer_ip, peer_port;
}
}'
}
# --- Coleta de Dados Mesclados ---
RAW_CONNECTIONS=$( (get_raw_connections_lsof; get_raw_connections_ss) )
else
# Coleta dados brutos de /proc/net/tcp para conexoes ESTABLISHED e LISTEN
function get_raw_connections_proc() {
awk '
NR > 1 {
split($2, local_addr, ":")
split($3, remote_addr, ":")
local_ip = sprintf("%d.%d.%d.%d", strtonum("0x" substr(local_addr[1],1,2)), strtonum("0x" substr(local_addr[1],3,2)), strtonum("0x" substr(local_addr[1],5,2)), strtonum("0x" substr(local_addr[1],7,2)))
local_port = strtonum("0x" local_addr[2])
remote_ip = sprintf("%d.%d.%d.%d", strtonum("0x" substr(remote_addr[1],1,2)), strtonum("0x" substr(remote_addr[1],3,2)), strtonum("0x" substr(remote_addr[1],5,2)), strtonum("0x" substr(remote_addr[1],7,2)))
remote_port = strtonum("0x" remote_addr[2])
state = $4
if (state == "01") { # 01 = ESTABLISHED
print "ESTABLISHED", local_ip, local_port, remote_ip, remote_port
} else if (state == "0A") { # 0A = LISTEN
print "LISTEN", local_ip, local_port
}
}' /proc/net/tcp
}
# --- Coleta de Dados Mesclados ---
RAW_CONNECTIONS=$(get_raw_connections_proc)
fi
# --- Processamento AWK Principal, Filtragem, Categorizacao e Geracao de Saida ---
# AWK gera "Categoria|LinhaFormatada". Ordenacao no bash.
RESULT=$(echo "$RAW_CONNECTIONS" | awk -v prefix="$INTERNAL_PREFIX" \
-v local_hostname="$LOCAL_HOSTNAME" -v local_ip_main="$LOCAL_IP" \
-v w1="$w1" -v w2="$w2" -v w3="$w3" \
-v HOST_MAX="$HOST_MAX" '
BEGIN {
# Mapeamento de portas conhecidas (ajuste conforme sua necessidade)
svc["21"] = "ftp"; svc["22"] = "SSH"; svc["23"] = "telnet"; svc["25"] = "SMTP";
svc["53"] = "domain"; svc["80"] = "HTTP"; svc["110"] = "pop3"; svc["111"] = "rpcbind";
svc["137"] = "netbios-ns"; svc["138"] = "netbios-dgm"; svc["139"] = "netbios-ssn";
svc["143"] = "imap"; svc["443"] = "HTTPS"; svc["445"] = "microsoft-ds";
svc["514"] = "syslog"; svc["631"] = "ipp"; svc["993"] = "imaps"; svc["995"] = "pop3s";
svc["1716"] = "kdeconnect"; svc["2049"] = "nfs"; svc["2947"] = "gpsd"; svc["3050"] = "gds-db";
svc["3306"] = "MySQL"; svc["3389"] = "RDP"; svc["5432"] = "PostgreSQL";
svc["5900"] = "VNC"; svc["6379"] = "Redis"; svc["11211"] = "Memcached";
svc["5938"] = "TeamViewer"; svc["7071"] = "unknown_app"; svc["12501"]= "SSH";
svc["10808"]= "unknown"; svc["199"] = "smux"; svc["39115"]= "unknown";
svc["42957"]= "unknown"; svc["5201"] = "unknown"; svc["54165"]= "unknown";
svc["57621"]= "unknown"; svc["9050"] = "unknown";
}
# Funcao para encurtar APENAS NOMES DE HOST para exibicao
function shorten_hostname(hostname_str, max_len) {
max_len=HOST_MAX;
gsub(/\..*$/, "", hostname_str);
return (length(hostname_str)>max_len) ? substr(hostname_str,1,max_len)"..." : hostname_str;
}
# Funcao para verificar se um IP representa ESTA maquina especifica
function is_this_machine(ip_addr, main_local_ip) {
if (ip_addr == main_local_ip || ip_addr == "127.0.0.1" || ip_addr == "0.0.0.0") {
return 1;
}
return 0;
}
# Funcao para verificar se um IP esta dentro do escopo interno
function is_internal_scope(ip_chk, prefix, main_local_ip) {
if (is_this_machine(ip_chk, main_local_ip)) return 1;
if (ip_chk ~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) {
return (index(ip_chk,prefix)==1);
}
return 0;
}
# Funcao para resolver IP -> "hostname_curto (IP_COMPLETO)" ou "IP_COMPLETO"
function resolve_ip_display(ip_addr, main_local_ip, current_local_hostname) {
if (is_this_machine(ip_addr, main_local_ip)) {
display_ip_used = ip_addr;
if (ip_addr == "0.0.0.0") display_ip_used = main_local_ip;
return shorten_hostname(current_local_hostname) " (" display_ip_used ")";
} else {
cmd = "getent hosts " ip_addr " | awk \047{print $2; exit}\047";
resolved_hostname = "";
pipe_status = (cmd | getline resolved_hostname);
close(cmd);
if (pipe_status > 0 && resolved_hostname != "" && resolved_hostname != ip_addr) {
short_host = shorten_hostname(resolved_hostname);
return short_host " (" ip_addr ")";
} else {
return ip_addr;
}
}
}
# Funcao para resolver porta -> "porta (servico)"
function res_svc(p_str) {
if (p_str in svc) {
return p_str " (" svc[p_str] ")";
} else {
cmd = "getent services " p_str "/tcp 2>/dev/null";
svc_l = "";
if ((cmd | getline svc_l) > 0 && svc_l != "" && svc_l !~ /^#/) {
split(svc_l, svc_a, /[ \t]+/);
s_name = svc_a[1];
ret_val = p_str " (" s_name ")";
} else {
ret_val = p_str " (unknown)";
}
close(cmd);
return ret_val;
}
}
{
type=$1; lip=$2; lport=$3;
formatted_line = "";
category_prefix = "";
if (type == "ESTABLISHED") {
rip=$4; rport=$5;
if (index(lip, ":") > 0 || index(rip, ":") > 0) next;
is_lip_this_machine = is_this_machine(lip, local_ip_main);
is_rip_this_machine = is_this_machine(rip, local_ip_main);
if (is_lip_this_machine && is_rip_this_machine) next;
if (!is_internal_scope(lip, prefix, local_ip_main) || !is_internal_scope(rip, prefix, local_ip_main)) next;
c_ip = (lport+0 < rport+0) ? rip : lip;
s_ip = (lport+0 < rport+0) ? lip : rip;
s_pnum = (lport+0 < rport+0) ? lport : rport;
if (lport == rport) {
c_ip = (lip <= rip) ? lip : rip;
s_ip = (lip <= rip) ? rip : lip;
s_pnum = lport;
}
c_disp = resolve_ip_display(c_ip, local_ip_main, local_hostname);
s_disp = resolve_ip_display(s_ip, local_ip_main, local_hostname);
p_lab = res_svc(s_pnum);
formatted_line = sprintf("| %-*s | %-*s | %-*s |", w1, c_disp, w2, s_disp, w3, p_lab);
category_prefix = "1_ESTAB_OTHER|";
} else if (type == "LISTEN") {
if (index(lip, ":") > 0) next;
if (!is_internal_scope(lip, prefix, local_ip_main)) next;
p_lab = res_svc(lport);
h_disp = resolve_ip_display(lip, local_ip_main, local_hostname);
formatted_line = sprintf("| %-*s | %-*s | %-*s |", w1, h_disp, w2, h_disp, w3, p_lab);
category_prefix = "2_LISTEN_LOCAL|";
}
if (category_prefix != "") {
print category_prefix formatted_line;
}
}
')
# --- Geracao da Saida Markdown ---
printf "| %-*s | %-*s | %-*s |\n" "$w1" "Cliente" "$w2" "Server" "$w3" "Servico"
div1=$(printf '%*s' $((w1+2)) '' | tr ' ' '-')
div2=$(printf '%*s' $((w2+2)) '' | tr ' ' '-')
div3=$(printf '%*s' $((w3+2)) '' | tr ' ' '-')
printf "|%s|%s|%s|\n" "$div1" "$div2" "$div3"
if [[ -n "$RESULT" ]]; then
echo "$RESULT" | sort -s -t'|' -k1,1 -k3,3 -k4,4 | cut -d'|' -f2- | sort -u
else
printf "| %-*s | %-*s | %-*s |\n" "$w1" "Nenhuma conexao" "$w2" "relevante encontrada" "$w3" "."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment