Estivemos com um problema em um projeto que precisava verificar se o serviço xdmcp estava aberto, porém ele não é um processo independente, ele fica interligado ao X, kdm, gdm, xdm, para tanto a solução mais cabível era procurar saber se a porta estava aberta na máquina.
Sim, talvez pudesse existir outras maneiras de resolver isso, mas esta se fez mais interessante. A clássica solução que me veio a cabeça foi usar o netstat, mas pensei em porque não ir mais a fundo e como resultado venho por este artigo mostrar algumas coisas que aprendi.
As formas que executei este processo foram:
- Geek hacker ninja style form - procura no proc pelas conexões abertas (mais interessante e a que mais aprendi);
- Status network - usa o comando de status de rede para listar;
- Open Files - Procura baseado nos arquivos abertos o que está ligado a porta.
Geek hacker ninja style form
A forma mais baixo nível e estilosa =], vamos aos arquivos de kernel analisar suas saídas, está é a base utilizada por programas como o netstat, o qual converte os dados deste e mostra com uma saída personalizada. Foi publicado um artigo antes explicando sobre a conversão de bases, então não vou abordar este assunto aqui.
O arquivo em questão utilizado é o
/proc/net/tcp.
Exemplo de /proc/net/tcp:
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 9E00A8C0:D3FD E1D7BCCD:1F4A 01 00000000:0003163C 00:00000000 00000000 1000 0 383991 1 cb042500 102 12 4 2 100
1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 626508 1 c299db80 750 0 0 2 -1
Onde:
- sl: O número de identificador da linha.
- local_address: O endereço local e o número da porta do socket. O endereço local está codificado em little-endian em quatro seqüências de números em hexadecimal, isso significa que o byte mais importante é listado primeiro e você necessita fazer a inversão da ordem dos bytes para converter para o endereço de IP. O número da porta é um hexadecimal simples utilizado pelo programa.
- rem_address - O endereço remoto e o número da porta do socket. O endereço local está codificado em little-endian em quatro seqüências de números em hexadecimal, isso significa que o byte mais importante é listado primeiro e você necessita fazer a inversão da ordem dos bytes para converter para o endereço de IP. O número da porta é um hexadecimal simples.
- st: Status do socket (depois de muita busca encontrei onde estava o padrão de código daqui e o porque do valor ficar com 0A - segue tabela de referência no final).
- tx_queue rx_queue: O tamanho de transmissão e recebimento das filas de pacotes.
-
- tr tm->when: tr é o campo que indica se o medidor de tempo está ativo para este socket. Um valor zero indica que o medidor de tempo não está ativo. O tm->when indica tempo que o sock está sendo utilizado em jiffies (usado basicamente para debug).
- retrnsmt: Campo de informação interna do socket do kernel (usado basicamente para debug).
- uid: O uid do usuário dono da conexão.
- time-out: Campo de informação interna do socket do kernel (usado basicamente para debug).
- inode: Um número encriptado de identificação do socket para o sistema de arquivos do Linux (não encontrei qual é a criptografia utilizada aqui).
Achei a representação padrão do cat do arquivo /proc/net/tcp muito extensa, então refiz ela na horizontal para melhor explanar o exemplo acima e traduzi alguns dados:
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 9E00A8C0:D3FD E1D7BCCD:1F4A 01 00000000:0003163C 00:00000000 00000000 1000 0 383991 1 cb042500 102 12 4 2 100
1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 626508 1 c299db80 750 0 0 2 -1
sl : 0 - linha indicadora da primeira conexão
local_address: 9E00A8C0:D3FD - convertendo fica 192.168.0.158:151775
rem_address: E1D7BCCD:1F4A - convertendo fica 205.188.215.225:8010
st: 01 - TCP ESTABELISHED - conexão estabelecida
tx_queue rx_queue: 00000000:0003163C - fila de dados transmitidos
tm->when retrnsmt: 00:00000000 00000000 - dados utilizados para debug
uid: 1000 - id do usuário dono da conexão
timeout: 0 - dado utilizado para debug
inode: 383991 1 cb042500 102 12 4 2 100 - identificador criptografado
sl : 1 - linha indicadora da primeira conexão
local_address: 00000000:0016 - convertendo fica localhost:22
rem_address: 00000000:0000 - não tem ninguém conectado
st: 0A - TCP_LISTEN - escutando conexão
tx_queue rx_queue: 00000000:0003163C - fila de dados transmitida
tm->when retrnsmt: 00:00000000 00000000 - dados utilizados para debug
uid: 1000 - id do usuário dono da conexão
timeout: 0 - dado utilizado para debug
inode: 383991 1 cb042500 102 12 4 2 100 - identificador criptografado
Status network
Podemos ver as conexões abertas através do comando
netstat. O mesmo é um programa de estatísticas de rede utilizado amplamente para este fim. Não tem muitos segredos e as informações que ele mostra são muito legíveis. Alguém percebeu a similaridade com um outro arquivo no modo que as informações aparecem? :)
# netstat -tl - lista as conexões abertas de tcp em modo de escuta
# netstat -t - lista as conexões tcp estabelecidas
# netstat -p - lista os programas que estão usando a conexão
# netstat --numeric-ports - não converte o número da porta para ser listado
# netstat --numeric-hosts - não converte o número de ip para nome do host
Comando que resolveu meu problema:
# netstat -t -l -p --numeric-ports
Open Files
Vendo as conexões abertas através do comando
lsof. O comando lsof lista os arquivos abertos, através disto vamos procurar o arquivo aberto relacionado às portas tcp.
Obs.: Ele pode pegar muitas informações interessantes sobre os arquivos abertos, mas não é escopo deste artigo. :)
Sintaxe:
lsof -i protocolo
Exemplo:
# lsof -i tcp
Tabela de dados para o status do socket - versão do kernel 2.6.21.5 Slackware Linux 12
st status socket values |
significado |
valor |
TCP_ESTABLISHED | 01 |
TCP_SYN_SENT | 02 |
TCP_SYN_RECV | 03 |
TCP_FIN_WAIT1 | 04 |
TCP_FIN_WAIT2 | 05 |
TCP_TIME_WAIT | 06 |
TCP_CLOSE | 07 |
TCP_CLOSE_WAIT | 08 |
TCP_LAST_ACK | 09 |
TCP_LISTEN | 0A |
TCP_CLOSING | 0B |
TCP_MAX_STATES | 0C |
Ambiente de teste
- Slackware 12.0
- kernel 2.6.21.5
Conclusão
Estas foram apenas algumas maneiras, devem ter mais. Espero que tenham gostado e que algum dia isto seja útil a alguém =], bom para mim foi um grande aprendizado.
(Desculpe qualquer erro de português :X)
Definições
jiffy - medida utilizada para representar o uso de uma tarefa em chamadas de interrupção no processador (medida em um Linux com kernel 2.6.13 em um Intel 386 é de 4 ms ou 1/250th de um segundo)
Referências