Extensão snmpd personalizada para verificação de porta

Por mais estranho que pareça, recentemente eu tive uma tarefa para realizar verificações de porta sem acesso à LAN na qual os daemons escutam as conexões. Falando de uma solução de monitoramento, a escolha óbvia era o SNMP, que é o meio mais difundido de obter informações de saúde de dispositivos conectados à rede, de qualquer forma. Realizamos uma verificação de porta "indireta", o que significa que é suficiente sabermos que um processo está escutando em uma determinada porta sem tentar se comunicar com ela.

Eu encontrei três métodos alternativos para obter essa verificação de porta via SNMP. Eles têm uma coisa em comum: eles utilizam binários do servidor Net-SNMP e / ou do cliente.

  • O utilitário snmpnetsat.Uma resposta direta à nossa pergunta. Fornece uma listagem semelhante a netstat de conexões ativas no host remoto. Mas tem sua falha. Ele consulta os objetos MIB-II (RFC1213) mais antigos tcpConnectionTable e udpTable, que não suportam IPv6. Como resultado, os processos do servidor que atendem em todos os IPs em um sistema habilitado para IPv6 não são exibidos na lista.
  • objetos tcpListenerTable e udpEndpointTable.Estes dois foram definidos como parte do TCP-MIB (RFC4022) e UDP-MIB (RFC4113) respectivamente. Como seus nomes sugerem, essas estruturas mantêm todos os processos de ouvinte no sistema. Aparentemente, os índices não podem ser consultados diretamente, portanto, é necessário percorrer a tabela inteira para localizar uma porta específica. Pelo menos esse é o caso no Net-SNMP v5.5, mas eu não investiguei mais nada.
  • Extensão snmpd personalizada.É claro que não queremos desenvolver um novo módulo MIB para essa tarefa única. Existem várias outras maneiras de estender a funcionalidade snmpd - todas elas são descritas na man page do snmpd.conf. A idéia básica é coletar os dados do listener com um script e permitir que ele seja transferido para o cliente em um formato simples.

Então, temos duas opções viáveis ​​aqui. Uma é permitir que o cliente (sistema de monitoramento) extraia as informações necessárias de tcpListenerTable e udpEndpointTable. A outra é deixar a tomada de decisão para o servidor (host monitorado) e deixar que ela atenda à outra parte com um simples valor OK / NOT-OK. Escusado será dizer que o ex-vencedor da competição por causa do menor impacto nas configurações do host.

Mas, surpresa-surpresa, criei uma solução POC funcional para a outra também. Em memória…

Estendendo snmpd

Como já mencionei, minha ideia de uma extensão era executar um script externo a partir do daemon e fornecer ao cliente um único valor necessário. Uma solução que reconhece SNMP (denotada como um comando de extensão específico da MIB pela documentação) é o que se encaixa. Nesse cenário, o daemon age com preguiça e delega todo o trabalho ao comando externo: ele transfere o ID do objeto e o tipo de solicitação (GET, GETNEXT, SET) e espera um valor de objeto ou um relatório sobre o resultado.

Tudo o que temos a fazer é atribuir uma parte não usada da árvore MIB ao script com um passar diretiva e conceder direitos de exibição para o cliente ("systemview" é "public" por padrão).

 pass .1.3.6.1.4.1.2021.51 /path/to/script.sh
 view systemview included .1.3.6.1.4.1.2021.51

Portanto, agora cabe a nós, o que acontece quando um objeto nessa subárvore é solicitado. Nosso script serve objetos que possuem OIDs numéricos no formato “ROOT.PORT”, onde ROOT é a raiz relativa da subárvore e PORT pode ser qualquer número de porta válido. O valor do objeto retornado corresponde ao número de processos ligados a essa porta. Por exemplo, suponha que ROOT seja .1.3.6.1.4.1.2021.51, se uma requisição GET for recebida em .1.3.6.1.4.1.2021.51.22, então a resposta manterá o número de processos escutando na porta 22. Obviamente, o valor é 0, se não houver tal processo. Ao responder a solicitações GETNEXT, somente essas portas são levadas em consideração e são vinculadas a um processo.

 #!/bin/sh
 
 # Find ports bound to a single IP address. (Empty means ALL.)
 IP=
 
 # OID of the subtree root object assigned to this extension (with leading dot).
 ROOT=.1.3.6.1.4.1.2021.51
 
 # Paths to binaries
 LSOF=/usr/sbin/lsof
 GREP=/bin/grep
 SORT=/bin/sort
 SED=/bin/sed
 HEAD=/usr/bin/head
 WC=/usr/bin/wc
 
 OID=$  2
 
 # Check wether OID is valid (it's a direct descendant of ROOT or ROOT itself)
 echo $  OID | $  GREP -E ^$  ROOT.?[0-9]*$   > /dev/null || exit
 
 # Extracting the last portion of the OID
 [ "$  OID" != "$  ROOT" ] && port=`echo $  OID | $  GREP -o "[0-9]*$  "` || port=0
 
 [ "$  IP" != "" ] && IP="@$  IP"
 
 case $  1 in
 
 	"-g")
 
 		# Checking if port is in valid range
 		[ "$  port" -gt "65535" ] && exit
 
 		[ "$  port" = "0" ] && echo -e "$  OIDnstringn$  0" && exit
 	;;
 
 	"-n")
 
 		(( port = $  port + 1 ))
 
 		# Checking if port is in valid range
 		[ "$  port" -gt "65535" ] && exit
 
 		# Searching next listener port on the system
 		port=`($  LSOF -i$  IP:$  port-65535 -sTCP:LISTEN -Fnp -P; $  LSOF -iUDP$  IP:$  port-65535 -Fnp -P) | $  GREP "^n" | $  GREP -o "[0-9]*$  " | $  SORT -n | $  HEAD -1`
 		[ "$  port" == "" ] && exit
 		OID="$  ROOT.$  port"
 	;;
 
 	"-s")
 
 		# Refusing SET requests
 		echo not-writable; exit
 	;;
 
 	*)
 		exit
 	;;
 esac
 
 # Output for snmpd (number of processes)
 echo -e "$  OIDninteger"
 ($  LSOF -iTCP$  IP:$  port -sTCP:LISTEN -Fp; $  LSOF -iUDP$  IP:$  port -Fp) | $  SORT -u | $  WC -l

Apenas um exemplo de como isso pode ser usado do lado do cliente. Vamos adicionar um comando à configuração do Nagios.

 define command{
         command_name    check_snmp_port
         command_line    $  USER1$  /check_snmp -H $  HOSTADDRESS$   -C public -c 1: -o .1.3.6.1.4.1.2021.51.$  ARG1$  
 }

Onde $ USER1 $ é uma macro de usuário que contém o caminho para o diretório do plugin Nagios, onde check_snmp reside. Obviamente, o primeiro argumento ($ ARG1 $) é o número da porta, portanto a diretiva check_command em uma definição de serviço deve ser algo assim: check_snmp_port! 22.

 

Deixe um comentário

Este site usa o Akismet para reduzir o spam. Saiba como seus dados de comentário são processados.

GTranslate Your license is inactive or expired, please subscribe again!