Gerenciamento de uma rede laboratorial via SNMP C. E. S. Tossato Pontifícia Universidade Católica de Campinas – Rod. D. Pedro I, km 136 – Campinas – SP – CEP 13086-900 Resumo Este relatório descreve os estudos realizados para elaboração de um sistema capaz de gerenciar um ambiente de uma rede laboratorial, o qual será usada para a realização de experimentos técnicos na área de redes. O sistema consistirá em um servidor o qual um administrador acessará e então poderá gerenciar a rede em questão. Em um servidor Linux estará uma aplicação Java responsável pelo monitoramento da rede. Até o presente momento, foi implementado o servidor Linux, o qual contém uma interface web, onde o administrador pode enviar uma mensagem, via SNMP, para consultar algum dado em um computador monitorado. mostra como poderia estar disposto o servidor, o computador do administrador e a rede monitorada. Web Rede para experimentos Servidor Palavras-chaves Gerenciamento, SNMP, Java, Web lab. I. INTRODUÇÃO Um dos principais objetivos da Internet é utilizá-la como fonte de conhecimento, isso é feito por meio de textos, imagens, vídeos etc. Porém, em algumas situações, ainda não havia um meio de dar ao aprendiz maior entendimento através de aplicações praticas. Como solução para esta limitação, foram disponibilizados, via Internet, laboratórios virtuais chamados de WEB LABs. Na PUC Campinas há um desenvolvimento para a disponibilização de um WEB lab, o qual irá virtualizar o laboratório da disciplina pratica que estuda o funcionamento de redes de computadores. Com a virtualização deste laboratório o aluno poderá ter maior contato com situações reais, que serve de suporte ao ensino teórico e o coloca diante de um método didático interativo, prendendo a atenção do aluno.[1] O ambiente virtual que os alunos acessarão se trata de um laboratório real, e é prudente que este ambiente em uso, seja gerenciado. Este projeto se dispõe a fazer este papel, identificando falhas, configurar e contabilizar os dados deste laboratório. Enfim, o gerenciamento feito aqui, tem o fim de obtermos controle e melhor aproveitamento dos recursos. Apesar de esta rede ter sentido através de acesso externo, por meio da Internet, o gerenciamento proposto aqui somente será feito através da rede interna, ou seja, a estação de gerenciamento de rede devera estar na mesma rede local dos computadores disponibilizados para os experimentos. O sistema consistirá em um servidor o qual um administrador acessará e então poderá gerenciar a rede em questão. No servidor estará instalado uma aplicação Java, responsável pelo monitoramento da rede, e um servidor Web, o qual será a interface de monitoramento para o administrador. O administrador acessará esta interface de qualquer computador na mesma rede do servidor, a Figura 1 Administrador Figura 1 - Sistema de monitoramento A aplicação Java existente no servidor, através do protocolo de gerenciamento SNMP, colherá e analisará dados da rede monitorada, para então o administrador acessá-los. Através da interface web, o administrador além de analisar os dados poderá configurar algum parâmetro em qualquer computador que esteja na rede monitorada. Portanto, para a compreensão do sistema, primeiro é apresentado um estudo teórico sobre o protocolo SNMP, como este protocolo é organizado, quais são as mensagens utilizadas e, no contexto, algumas nomenclaturas que são comumente utilizadas. Na próxima seção há uma breve descrição de como é instalado um agente SNMP no sistema operacional Microsoft Windows, e como acessar a configuração deste agente. No restante do material apresentamos os resultados obtidos neste primeiro passo para a consolidação do sistema. II. PROTOCOLO SNMP O protocolo SNMP (Simple Network Management Protocol), como o próprio nome diz, foi feito para ser um protocolo simples, porém funcional. Através do SNMP é possível monitorar e gerenciar equipamentos em uma rede[2]. O SNMP trabalha com uma relação de agente e servidor de manutenção, ou seja, um agente que se encontra em um equipamento o qual irá ser monitorado, responde as requisições do servidor ou manda alguma informação referente a eventos. Portanto, no esquema proposto para teste, o agente, ficará localizado nos computadores utilizados para realização de experimentos e o servidor localizado em um computador qualquer. O SNMP define basicamente quatro mensagens: get, getnext, set, trap. Nas versões 2 e 3 do protocolo, ainda encontramos mais alguns tipos de mensagens, como o getbulk, notification, Inform e Response. O get é utilizado pelo servidor para obter o valor de algum objeto gerenciável. O getnext é utilizado pelo servidor para obter valor do próximo objeto, referente à identificação do objeto gerenciável passado. Este comando é muito útil quando estamos consultando tabelas, as quais, não se sabe se há alguma entrada (linha) nela ou não. A mensagem set é utilizada pelo servidor para criar, modificar e deletar uma entrada em uma determinada tabela, e ainda modificar o valor de um objeto que não pertence a uma tabela, esse objeto é chamado de objeto escalar. Trap é uma mensagem enviada do agente para o servidor, com o objetivo de relatar que algum evento ocorreu. O principal uso desta mensagem é avisar sobre alarmes. Todos objetos gerenciáveis via SNMP, possuem um único identificador de objeto (OID), assim quando queremos consultar um determinado objeto fazemos referencia a seu OID. Os OIDs são definidos hierarquicamente, como uma árvore. Cada nó possui um OID, observe a Figura 1, onde é apresentada a hierarquia até a MIB-2. Dependendo da finalidade que fazemos o gerenciamento, é definido uma serie de objetos, os quais estão contidos em uma MIB. Alguns protocolos possuem sua própria MIB definida em suas normas. Para entendermos melhor cada objeto gerenciável de uma MIB podemos contar com a ajuda de algumas ferramentas, eles possibilitam melhor visualização de uma MIB, essas ferramentas são softwares livres capazes de sintetizar visualmente uma MIB em um formato hierárquico, semelhante a pastas e sub-pastas, comumente visto em alguns sistemas operacionais. Para isto podemos utilizar o software iReasoning MIB Browser, disponível em [3] III. Agente SNMP Após uma pesquisa entre os agentes SNMP, foi escolhido o agente padrão do Microsoft Windows, por ser um agente do próprio sistema operacional e de fácil configuração. A instalação é feita através do próprio instalador do sistema operacional (em Adicionar/Remover componentes do Windows > Ferramentas de gerenciamento e monitoramento > Simple Network Management Protocol). A configuração do agente também é simples e é feita através no Painel de Controle > Ferramentas Administrativas > Serviços, na lista de serviços procure por serviços SNMP e configure o agente. O agente pode ser facilmente configurado através das abas, observe a Figura 3. Figura 2 - Estrutura hierárquica dos dados [2] A MIB-2 é uma das MIBs (Management Information Base) mais utilizadas nos equipamentos de rede. A partir dela conseguimos gerenciar informações básicas de um equipamento para com a rede, e a maioria dos equipamentos a suportam. Uma MIB pode ser considerada como um banco de dados dos objetos que são gerenciáveis. Nela são definidas todas as informações que poderão ser acessadas via SNMP. Em cada MIB é definido qual tipo de dado que o objeto suporta, o tipo de acesso a esse objeto, como por exemplo acesso restrito a somente leitura, e outras informações. Figura 3: Configuração do Agente SNMP IV. O Servidor A escolha de qual servidor iria ser utilizado baseouse no fato de já existir trabalhos voltados para implementação do WEB lab, portanto utilizaremos um servidor onde possa ser utilizado para outras aplicações, o servidor utilizado possui então o sistema operacional Linux. Para monitorarmos a rede devemos rodar neste servidor uma aplicação capaz de mandar e receber mensagens SNMP, guardar certos valores e processa-los. Novamente, foi escolhido com base na infra-estrutura já adotada, a linguagem de programação Java, a qual também possui a vantagens de ser uma linguagem multiplataforma, ou seja, uma aplicação Java pode rodar na maioria dos sistemas operacionais. Para assegurarmos paginas dinâmicas, onde o administrador da rede poderá gerenciar a rede, necessitamos de um container Web, isto é, um servidor web onde são instaladas servlets para tratar as requisições que o servidor irá receber. Servlets são componentes que disponibilizam ao programador java uma interface para o servidor web.[4]. Enfim, o container escolhido foi o tomcat Apache, ele tem grande utilização, inclusive para fins comerciais, com vasta documentação e de simples instalação. Para o container conseguir executar aplicações java é necessário que o servidor tenha instalado a JVM (Java Virtual Machine), a qual será responsável por executar os arquivos java, e para compilação java também é necessário instalar o JDK (Java Development Kit). Com isso já temos o suficiente para rodarmos nosso sistema. As instalações dos itens acima podem ser feita em ordem aleatória, porém todos devem ser instalados. V. Desenvolvimento da Aplicação Para o desenvolvimento da aplicação foi necessário entender a estrutura de um container, no caso o tomcat apache. A instalação do container é feita pela simples descompactação do pacote de instalação, disponível no site http://tomcat.apache.org. A estrutura de diretórios que encontramos após o descompactação é observada e explicada pela Tabela 1. Diretórios Tomcat /bin /conf /lib /logs /temp /webapps Descrição Diretório que contém os binários executáveis. Importante par iniciar e parar o servidor Diretório que contém os arquivos de configuração do servidor. Diretório que contém classes disponíveis tanto para funcionamento do servidor quanto às aplicações web instaladas. Diretório que contém os arquivos de logs. Diretório de arquivos temporários utilizado pelo tomcat Diretório para a instalação de aplicações web no Tomcat. Diretório onde se encontrará nossa aplicação /work para o gerenciamento Diretório onde o Tomcat armazena o código da página JSP depois que este é convertido em um Servlet Tabela 1 - Estrutura de diretórios tomcat Os principais diretórios utilizados até o momento foram o bin, conf, lib e webapps. No diretório bin foi utilizado dois scripts para começar e terminar o serviço de servidor web, através dos arquivos startup.sh e shutdown.sh, respectivamente[4]; No diretório conf, foi configurado o arquivo server.xml, para apenas mudar a porta html padrão, assim quando queremos acessar o servidor web, apenas digitamos no browser o endereço IP do servidor, pois por padrão acessamos o tomcat através da porta 8080, por exemplo, http://192.168.0.1:8080/.[5] Dentro do diretório lib possui algumas bibliotecas Java importantes para o funcionamento do servidor, além disso há a biblioteca servlet-api.jar, esta biblioteca é utilizada para todos os servlets que compilamos. Já o diretório webapps é onde colocamos nossa aplicação, dentro dele costumamos a criar um diretório para cada aplicação, pois o mesmo servidor pode ter varias aplicações. Dentro do diretório especifico da aplicação devemos seguir uma estrutura para que o tomcat consiga executar nossa aplicação, essa estrutura é mostrada e descrita na tabela 2. Diretórios /DirApp/ Descrição Diretório raiz da aplicação web /DirApp/WEB-INF/ Diretório que contém os recursos relacionados à aplicação como o web aplication deployment, ou seja, como que o container irá implementar a aplicação. /DirApp/WEB-INF/web.xml Descritor de instalação 'web.xml'. /DirApp/WEB-INF/lib Diretório que contém arquivos JAR que a aplicação web tem dependência. /DirApp/WEB-INF/classes Diretório que contém Servlets e demais classes Java, todos compilados. Tabela 2 - Estrutura do diretório da aplicação Dentro do diretório da aplicação somos livres para colocarmos arquivos HTML e imagens, contidos ou não de mais pastas. Também é possível termos arquivos com a extensão jsp, que são as Java Server Pages, porém até o momento não a utilizamos. No diretório WEB-INF colocamos nossa aplicação e os servlets, como descrito anteriormente. Os arquivos devem estar na estrutura citada na Tabela 2 para que o tomcat consiga executar nossa aplicação. O arquivo web.xml pode ser usado para muitas finalidades, porém, até o momento, somente o usamos para citar que existe um servlet e mapea-lo para um caminho qualquer, este mapeamento é usado pelo container para traduzir um request URI para um servlet em particular, ou seja, para que o container saiba, através do endereço digitado no navegador, para qual servlet encaminhar o request. Até agora, foi desenvolvido uma aplicação capaz de mandar uma mensagem SNMP, o get, para qualquer IP, consultando qualquer objeto gerenciável que se queira. O administrador entra através de um navegador de internet na interface web, onde ele é capaz de enviar a requisição. A Figura 4 mostra todos diretórios e arquivos utilizados na aplicação até então, vemos que o diretório de nossa aplicação foi chamado de tcc, dentro deste há um arquivo chamado índex.html, esse será o arquivo que o administrador verá ao digitar, em um navegador, o endereço http://<ipservidor>/tcc/. Em nosso caso o IP do servidor utilizado para testes era o 192.168.88.128, então o endereço que devemos digitar no navegador é http://192.168.88.128/tcc/. Poderíamos melhorar o modo de acesso se colocássemos na rede um servidor DNS, então ao invés de digitarmos o IP digitaríamos um nome qualquer e o servidor DNS traduziria este nome para o IP correspondente, porém este não é o foco. servlet encaminha os dados para a instancia de objeto SnmpGet, este, trata as informações especificas da operação get e então encaminha para a instancia do objeto SnmpUtil, o qual tratará as operações genéricas relacionadas a mensagem SNMP, este fará a interface com a API (application program interface) SNMP. Dentre APIs SNMP disponíveis, foi conveniente escolhermos a API SNMP4J. Ela é uma API livre e de código aberto orientada a objeto para linguagem java, possui vasta documentação e ainda é considerada estável por estar a muito tempo sendo desenvolvida pela comunidade de software livre. Ela será a interface para enviarmos e receber as mensagens SNMP. A API disponibiliza várias classes para o suporte de operações necessárias para a implementação de um servidor de gerenciamento de rede (NMS). A API e toda sua documentação esta disponível no endereço http://www.snmp4j.org/. Toda codificação comentada se encontra no apêndice 1. Navegador Re qu isiç ão HT TP INDEX.HTML Re sp os tcc H ta P TT index.html MainSnmpGet.class img SnmpGet.class Puc.gif WEB-INF SnmpUtil.class Consulta SNMP web.xml SNMP4J.jar classes MainSnmpGet.class SnmpGet.class Rede WEBLAB SnmpUtil.class lib Figura 5 - Componentes e classes SNMP4J.jar Figura 4 - Arquivos utilizados A Figura 5 mostra como é a comunicação interna do software, a arquitetura que é mostrada aqui esta buscando reutilizar ao máximo os objetos, portanto, no passo que estamos, pode parecer não haver sentido, porém, com mais algum desenvolvimento, existiram vários tipos de requisições SNMP que devemos tratar. Neste próximo momento a arquitetura de comunicação fará sentido. Vamos analisar o software implementado até o momento. A pagina índex.html serve como interface para o administrador, nesta pagina o administrador preenche os campos e envia os dados para o servlet MainSnmpGet, o qual de posse dos dados, identifica a operação que deve ser realizada e encaminha os dados para o objeto designado a aquela operação, no caso como se trata de uma consulta get, o VI. Executando a Aplicação O Apêndice 2 e Apêndice 3 mostra a captura de uma tela, onde o servidor esta sendo executado em uma maquina virtual com o IP 192.168.88.128. Na maquina local, de onde a tela foi capturada, esta rodando o agente SNMP, e este computador possui o IP 192.168.88.1, a maquina virtual e o maquina local estão interconectadas por uma rede virtual. Neste exemplo, consultamos a quanto tempo que o sistema operacional computador esta sendo executado. Este tempo pode ser consultado pelo OID .1.3.6.1.2.1.1.3.0. V. CONCLUSÃO Neste trabalho foi concluido os primeiros estudos de como elaborar um sistema para o monitoramento de uma rede. Aplicando os fundamentos aprendidos na teoria de SNMP, em conjunto com conceitos de programação fomos capazes de gerar uma aplicação para a consulta de valores em computadores. Atualmente a aplicação exige certo trabalho para o operador, futuramente podemos otimizar a aplicação para realizar consultas com menos esforço, e desenvolver novas funcionalidades, como por exemplo, habilitar ou desabilitar interfaces de redes, entre outras funções. REFERÊNCIAS [1] BIANCHINI, David. et al. LABORATORIO VIRTUAL INTERATIVO NO ENSINO DE REDE DE COMPUTADORES. Campinas, Junho, 2007. Disponível em: [2] MAURO, D. e SCHMIDT, K. “Essential SNMP”, 2ed. .O'reilly Books. 2005. [3] http://www.ireasoning.com/mibbrowser.shtml Acessado em: 11 de junho de 2008 [4] Hungria, Edson Curso JSP (Java Server Pages) e Servlet, Centro de difusão de tecnologia e Conhecimento, disponibilizado em: www.cdtc.org.br [5] Marty Hall e Larry Brown, Core Servlets and JavaServer Pages™: Volume 1: Core Technologies, segunda edição, agosto de 2003. [6] K. McCloghrie e J. Schoenwaelder, Textual Conventions for SMIv2, Cisco Systems, RFC 2579, April 1999 [7] F. Kastenholz e K. McCloghrie, The Interfaces Group MIB, Cisco Systems, RFC 2863, June 2000 http://lantec.fae.unicamp.br/lantec/pt/tvdi_portugues/davi d.pdf Acessado em: 14 de março de 2008 APÊNDICE 1 – Código comentado Arquivo index.html <html> <head> //Configurando o titulo da pagina (Navegador) <title>Enviando uma mensagem SNMP</title> </head> <body> //Inserindo símbolo da PUC-Campinas <p align=center><img src="img/logo_home.gif" alt="logo_home"></p> //Título na página <h1>Gerenciamento de redes</h1> <h2>CEATEC - Centro de Ciências Exatas, Ambientais e de Tecnologias </h2> <p>Digite o OID a ser consultado: </p> //Iniciando formulário para envio de dados, no campo action devera ter o endereço do servlet correspondente mapeado no arquivo web.xml <form action=get.do method=post> <p><INPUT TYPE="text" NAME="valor"></p> <p>Digite o IP do host:</p> <p><INPUT TYPE="text" NAME="hostD"> <INPUT TYPE="submit" ACTION="get.do" METHOD="post"></p> </form> </body> </html> Arquivo web.xml // A partir daqui começam as descrições gerais da aplicação. A tag web-app é a raiz dos deployment descriptor para as aplicações web. <web-app> <servlet> <servlet-name>Exemplo1</servlet-name> // Tag usada para indicar o pacote (se houver) e a classe (qualificada) que representa o servlet definido <servlet-class>MainSnmpGet</servlet-class> </servlet> //Tag define o mapeamento que é usado pelo servlet container para traduzir um request URI para um servlet em particular <servlet-mapping> <servlet-name>Exemplo1</servlet-name> <url-pattern>/get.do</url-pattern> </servlet-mapping> </web-app> Classe Java MainSnmpGet //Importando classes java e dependências necessárias import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import org.snmp4j.*; import org.snmp4j.mp.*; import org.snmp4j.security.*; import org.snmp4j.smi.*; import org.snmp4j.transport.*; import org.snmp4j.util.*; //Criando classe principal MainSnmpGet e especificando que é um servlet public class MainSnmpGet extends HttpServlet{ //Método para tratar POST, método de envio escolhido através do formulário HTML public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException { //setando tipo de resposta response.setContentType("text/html"); //Criando objeto (out) como resposta a requisição PrintWriter out = response.getWriter(); //Lendo valores enviados pelo administrador String escolha = request.getParameter("valor"); String hostD = request.getParameter("hostD"); out.println("Fazendo Get SNMPv2"); //Criando novo objeto da classe SnmpGet.class e passando os dados como parâmetros SnmpGet _get = new SnmpGet(hostD,escolha); //Solicita o envio da mensagem e guarda a resposta na variavel responsePDU PDU responsePDU = _get.doGet(); //Colhendo somente o resultado e armazenando na variavel vb VariableBinding vb = responsePDU.get(0); //Exibindo resultado out.println("<br>"+vb.toString()); } } } Classe Java SnmpGet //Importando classes java e dependências necessárias import import import import import import org.snmp4j.*; org.snmp4j.mp.*; org.snmp4j.security.*; org.snmp4j.smi.*; org.snmp4j.transport.*; org.snmp4j.util.*; //Criando classe principal SnmpGet public class SnmpGet { //Setando uma constante (_GET) para identificar a operação, utilizado também pela classe SnmpUtil public static final int _GET = 2; //Criando objeto a partir da classe SnmpUtil private SnmpUtil _util = null; //Método SnmpGet, utiizado pela classe MainSnmpGet public SnmpGet(String host, String oid){ //Passando parametros para SnmpUtil _util = new SnmpUtil(host,oid,false); //Setando operação desejada, no caso a get _util.setOperation(_GET); } //Método para o envio da mensagem public PDU doGet() { //Envia requisição e recebe a resposta PDU response = _util.sendAndProcessResponse(); //Retorna resposta return response; } } Classe Java SnmpUtil //Importando classes java e dependências necessárias import java.io.IOException; import java.util.Vector; import org.apache.log4j.*; import org.snmp4j.*; import org.snmp4j.mp.*; import org.snmp4j.security.*; import org.snmp4j.smi.*; import org.snmp4j.transport.*; import org.snmp4j.util.*; import org.snmp4j.log.LogFactory; import org.snmp4j.log.Log4jLogFactory; import org.snmp4j.asn1.BER; import org.snmp4j.event.ResponseEvent; //Criando classe principal SnmpUtil public class SnmpUtil extends Thread implements PDUFactory, CommandResponder { //Setando uma constante (_GET) para identificar a operação public static final int _GET = 2; //Seta e Inicia algumas variáveis private Target _target; private Address _address; private OctetString _community = new OctetString("public"); private static Snmp _snmp = null; private int _port = 0; private TransportMapping _transport = null; private PDU nullresp; private int _version = 0; private int _retries = 1; private int _timeout = 1000; private int _pduType = 0; private Vector _vbs = new Vector(); protected int _operation = DEFAULT; //Inicia metodo para configuração de endereço e Objeto a ser consultado. Seta a versão SNMP e porta de destino public SnmpUtil(String host, String varbind){ _version = SnmpConstants.version2c; _port = 161; init(host,varbind); } //Setando operação desejada, no caso a get public void setOperation(int operation) { _operation = operation; if(_operation == _GET){ _pduType = PDU.GET; } } //Seta endereço de destino (UDP) e OID a ser consultado(Chama outro método para futuramente ser reutilizado) public void init(String host, String varbind){ _vbs = getVariableBinding(varbind); _address = new UdpAddress(host+"/"+_port); } //Cria sessão para o envio da mensagem private Snmp createSnmpSession() throws IOException { AbstractTransportMapping transport; transport = new DefaultUdpTransportMapping(); Snmp snmp = new Snmp(transport); return snmp; } //Define parametros da mensagem, como utilizamos a versão 2 a senha é simple community private Target createTarget() { CommunityTarget target = new CommunityTarget(); target.setCommunity(_community); return target; } //Monta PDU para envio public PDU send() throws IOException { _snmp = createSnmpSession(); this._target = createTarget(); _target.setVersion(_version); _target.setAddress(_address); _target.setRetries(_retries); _target.setTimeout(_timeout); _snmp.listen(); PDU request; request = new PDU(); request.setType(_pduType); //adiciona o objeto a ser consultado ao pacote request.add((VariableBinding)_vbs.get(0)); PDU response = null; //Chama função para o envio da mensagem response = do_get(_snmp, request, _target); _snmp.close(); return response; } //Obtem OID a ser consuldado private Vector getVariableBinding(String varbind) { Vector v = new Vector(varbind.length()); v.add(new VariableBinding(new OID(varbind))); return v; } //Realmente envia a mensagem private static PDU do_get(Snmp snmp, PDU request, Target target) throws IOException { request.setNonRepeaters(0); PDU response = null; ResponseEvent responseEvent = _snmp.send(request, target); response = responseEvent.getResponse(); return response; } //Envia requisição e recebe a resposta public PDU sendAndProcessResponse() { try { PDU response = this.send(); return response; } catch (IOException ex) { System.err.println("Error while trying to send request: " + ex.getMessage()); ex.printStackTrace(); return nullresp; } }APÊNDICE 2 – Captura do sistema em execução APÊNDICE 3 - Captura do sistema em execução