Em trânsito: ferramentas de captura de rede para desenvolvedores de API

Lane LiaBraaten, equipe de APIs de dados do Google
junho de 2007

Introdução

O desenvolvimento de aplicativos que interagem com serviços da Web representa um conjunto exclusivo de problemas. Uma fonte comum de frustração é não saber exatamente qual mensagem foi enviada ao servidor ou qual resposta foi recebida. Alguns dos bugs mais difíceis de rastrear são causados por uma desconexão entre o que achamos que estamos enviando para o servidor e o que está acontecendo na rede.

Este artigo apresenta várias ferramentas para ajudar a tornar os dados em trânsito mais visíveis e úteis. Essas ferramentas são geralmente chamadas de "drawables" do pacote e capturam todos os pacotes de rede que se movem pela interface de rede. Examinar o conteúdo desses pacotes e a ordem em que foram enviados e recebidos pode ser uma técnica útil de depuração.

Exemplo: recuperação de um feed público

Estou montando uma equipe de ciclismo para uma viagem beneficente e criei uma agenda para eventos como sessões de informações, Campanhas de Arrecadação para equipes e passeios de treinamento. Tornei essa agenda pública para que os membros da equipe e outros passageiros possam ver a agenda e participar dos eventos. Também quero enviar uma newsletter com os próximos eventos. Assim, em vez de copiar as informações do site do Google Agenda, posso usar a API Data Calendar para consultar a agenda e ver os eventos.

A documentação da API Google Calendar contém informações sobre como usar a API RESTful de dados do Google para interagir com minha agenda de maneira programática. Observação para os editores:a partir da v3, a API Google Calendar não usa mais o formato de dados do Google. A primeira coisa a fazer é acessar o URL do feed de eventos da agenda clicando no botão na página de configurações da agenda:

http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic

Usando a documentação do Google Agenda como referência, posso recuperar e exibir eventos da agenda como este, em que PUBLIC_FEED_URL contém o URL do feed de eventos.

CalendarService myService = new CalendarService("exampleCo-fiddlerExample-1");
final String PUBLIC_FEED_URL = "http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic";
URL feedUrl = new URL(PUBLIC_FEED_URL);
CalendarEventFeed resultFeed = myService.getFeed(feedUrl, CalendarEventFeed.class);

System.out.println("All events on your calendar:");
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
  CalendarEventEntry entry = resultFeed.getEntries().get(i);
  System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();

Isso produz uma lista básica dos eventos na minha agenda:

All events on your calendar:
    MS150 Training ride
    Meeting with Nicole
    MS150 Information session

O snippet de código acima exibe os títulos dos eventos da agenda, mas e quanto aos demais dados que recebemos do servidor? A biblioteca de cliente Java não facilita a saída de um feed ou entrada como XML e, mesmo que seja, o XML não é a história toda. E os cabeçalhos HTTP que acompanham a solicitação? A consulta foi colocada em proxy ou redirecionada? Com operações mais complexas, essas perguntas tornam-se cada vez mais importantes, especialmente quando acontece algo errado e ocorre um erro. O software de detecção de pacotes pode responder a essas perguntas revelando o tráfego da rede.

tcpdump

O tcpdump é uma ferramenta de linha de comando que funciona em plataformas semelhantes ao Unix, mas também há uma porta do Windows chamada WinDump. Como a maioria dos drawables de pacote, o tcpdump coloca seu cartão de rede no modo promíscuo, o que exige privilégios de superusuário. Para usar o tcpdump, basta especificar a interface de rede a ser detectada e o tráfego de rede será enviado para a stdout:

sudo tcpdump -i eth0

Se você executar esse comando, vai ser bombardeado por todos os tipos de tráfego de rede, alguns dos quais você não vai reconhecer. Você pode apenas encaminhar a saída para um arquivo e usar grep posteriormente, mas isso pode gerar arquivos muito grandes. A maioria dos softwares de captura de pacotes tem alguns mecanismos de filtragem integrados para que você capture apenas o necessário.

O tcpdump oferece suporte à filtragem com base em várias características do tráfego de rede. Por exemplo, é possível dizer ao tcpdump para capturar somente o tráfego de entrada ou saída do servidor na porta 80 (mensagens HTTP), inserindo o nome do host do servidor na seguinte expressão:

dst or src host <hostname> and port 80

Para cada pacote que corresponde à expressão do filtro, o tcpdump mostra um carimbo de data/hora, a origem e o destino do pacote e várias sinalizações TCP. Essas informações podem ser valiosas porque mostra a ordem em que os pacotes foram enviados e recebidos.

Muitas vezes, é útil ver o conteúdo dos pacotes. A sinalização "-A" diz ao tcpdump para imprimir cada pacote em ASCII, expondo os cabeçalhos HTTP e o corpo da mensagem. A sinalização "-s" é usada para especificar quantos bytes serão exibidos (quando "-s 0" significa não truncar o corpo da mensagem).

Juntando tudo, temos o seguinte comando:

sudo tcpdump -A -s 0 -i eth0 dst or src host <hostname> and port 80

Se você executar este comando e, em seguida, o breve exemplo de .Java acima, verá a comunicação de rede envolvida nessa operação. Entre o tráfego, você verá a solicitação HTTP GET:

22:22:30.870771 IP dellalicious.mshome.net.4520 > po-in-f99.google.com.80: P 1:360(359) ack 1 win 65535
E.....@....\...eH..c...P.=.....zP......GET /calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic HTTP/1.1
User-Agent: exampleCo-fiddlerExample-1 GCalendar-Java/1.0.6 GData-Java/1.0.10(gzip)
Accept-Encoding: gzip
Cache-Control: no-cache
Pragma: no-cache
Host: www.google.com
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive

Você também verá a mensagem de resposta 200 OK, que contém o feed de dados do Google. O feed é dividido entre quatro pacotes:

22:22:31.148789 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 1:1431(1430) ack 360 win 6432
E...1 ..2.I.H..c...e.P.....z.=.:P..M...HTTP/1.1 200 OK
Content-Type: application/atom+xml; charset=UTF-8
Cache-Control: max-age=0, must-revalidate, private
Last-Modified: Mon, 11 Jun 2007 15:11:40 GMT
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2007 02:22:10 GMT
Server: GFE/1.3

13da
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gCal='http://sc
hemas.google.com/gCal/2005' xmlns:gd='http://schemas.google.com/g/2005'><id>http
://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.goo
gle.com/public/basic</id><updated>2007-06-11T15:11:40.000Z</updated><category sc
heme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2
005#event'></category><title type='text'>MS150 Training Schedule</title><subtitl
e type='text'>This calendar is public</subtitle><link rel='http://schemas.google
.com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calend
ar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic'></
link><link rel='self' type='application/atom+xml' href='http://www.google.com/ca
lendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic
?max-results=25'></link><author><name>Lane LiaBraaten</name><email>api.lliabraa@
gmail.com</email></author><generator version='1.0' uri='http://www.google.com/ca
lendar'>Google Calendar</generator><openSearch:totalRe


22:22:31.151501 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 1431:2861(1430) ack 360 win 6432
E...1!..2.I.H..c...e.P.......=.:P.. 2...sults>3</openSearch:totalResults><openSe
arch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch
:itemsPerPage><gd:where valueString=''></gd:where><gCal:timezone value='America/
Los_Angeles'></gCal:timezone><entry><id>http://www.google.com/calendar/feeds/24v
j3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/dgt40022cui2k3j
740hnj46744</id><published>2007-06-11T15:11:05.000Z</published><updated>2007-06-
11T15:11:05.000Z</updated><category scheme='http://schemas.google.com/g/2005#kin
d' term='http://schemas.google.com/g/2005#event'></category><title type='text'>M
S150 Training ride</title><summary type='html'>When: Sat Jun 9, 2007 7am to 10am

&amp;nbsp; PDT&lt;br&gt;   &lt;br&gt;Event Status:     confirmed</summary><conte
nt type='text'>When: Sat Jun 9, 2007 7am to 10am&amp;nbsp; PDT&lt;br&gt;   &lt;b
r&gt;Event Status:     confirmed</content><link rel='alternate' type='text/html'
 href='http://www.google.com/calendar/event?eid=ZGd0NDAwMjJjdWkyazNqNzQwaG5qNDY3
NDQgMjR2ajNtNXBsMTI1YmgyaWpiYm5laDk1M3NAZw' title='alternate'></link><link rel='
self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/24v
j3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/dgt40022cui2k3j
740hnj46744'></link><author><name>MS150 Training Schedule</name></author><gCal:s
endEventNotifications value='false'></gCal:sendEventNotifications></entry><entry

><id>http://www.google.com/cal

22:22:31.153097 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 2861:4291(1430) ack 360 win 6432
E...1#..2.I.H..c...e.P.......=.:P.. ....endar/feeds/24vj3m5pl125bh2ijbbneh953s%4
0group.calendar.google.com/public/basic/51d8kh4s3bplqnbf1lp6p0kjp8</id><publishe
d>2007-06-11T15:08:23.000Z</published><updated>2007-06-11T15:10:39.000Z</updated
><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.g
oogle.com/g/2005#event'></category><title type='text'>Meeting with Nicole</title

><summary type='html'>When: Mon Jun 4, 2007 10am to 11am&amp;nbsp; PDT&lt;br&gt;
  &lt;br&gt;Where: Conference Room B &lt;br&gt;Event Status:     confirmed</summ
ary><content type='text'>When: Mon Jun 4, 2007 10am to 11am&amp;nbsp; PDT&lt;br&
gt;  &lt;br&gt;Where: Conference Room B &lt;br&gt;Event Status:     confirmed

&lt;br&gt;Event Description: Discuss building cycling team for MS150</content><l
ink rel='alternate' type='text/html' href='http://www.google.com/calendar/event?
eid=NTFkOGtoNHMzYnBscW5iZjFscDZwMGtqcDggMjR2ajNtNXBsMTI1YmgyaWpiYm5laDk1M3NAZw'
title='alternate'></link><link rel='self' type='application/atom+xml' href='http
://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.goo
gle.com/public/basic/51d8kh4s3bplqnbf1lp6p0kjp8'></link><author><name>MS150 Trai
ning Schedule</name></author><gCal:sendEventNotifications value='false'></gCal:s
endEventNotifications></entry><entry><id>http://www.google.com/calendar/feeds/24
vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/va41amq3r08dhh
kpm3lc1abs2o</id><published>20


22:22:31.190244 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: P 4291:5346(1055) ack 360 win 6432
E..G1$..2.K.H..c...e.P.....<.=.:P.. ....07-06-11T15:10:08.000Z</published><updat
ed>2007-06-11T15:10:08.000Z</updated><category scheme='http://schemas.google.com
/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title ty
pe='text'>MS150 Information session</title><summary type='html'>When: Wed Jun 6,
 2007 4pm to Wed Jun 6, 2007 5pm&amp;nbsp; PDT&lt;br&gt;   &lt;br&gt;Event Statu
s:     confirmed</summary><content type='text'>When: Wed Jun 6, 2007 4pm to Wed
Jun 6, 2007 5pm&amp;nbsp; PDT&lt;br&gt;   &lt;br&gt;Event Status:     confirmed<

/content><link rel='alternate' type='text/html' href='http://www.google.com/cale
ndar/event?eid=dmE0MWFtcTNyMDhkaGhrcG0zbGMxYWJzMm8gMjR2ajNtNXBsMTI1YmgyaWpiYm5la
Dk1M3NAZw' title='alternate'></link><link rel='self' type='application/atom+xml'
 href='http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.c
alendar.google.com/public/basic/va41amq3r08dhhkpm3lc1abs2o'></link><author><name
>MS150 Training Schedule</name></author><gCal:sendEventNotifications value='fals
e'></gCal:sendEventNotifications></entry></feed>

A saída inclui todos os cabeçalhos e conteúdo HTTP, além de várias sinalizações TCP criptográficas. Todos os dados estão presentes aqui, mas são um pouco difíceis de ler e entender. Há várias ferramentas gráficas que facilitam a visualização desses dados.

WireShark (antigo Ethereal)

Captura de tela do Wireshark
O WireShark mostra o tráfego de rede de várias maneiras.

O WireShark é uma ferramenta gráfica criada com libpcap, a mesma biblioteca em que o tcpdump foi criado, disponível no Linux, Mac OS X e Windows. A GUI do WireShark oferece várias novas maneiras de interpretar e interagir com os dados de captura de pacotes. Por exemplo, quando os pacotes são capturados na interface de rede, eles são exibidos em cores diferentes com base no protocolo que estão usando. Também é possível classificar o tráfego por carimbo de data/hora, origem, destino e protocolo.

Se você selecionar uma linha na lista de pacotes, o Wireshark exibirá IPs, TCP e outras informações específicas do protocolo nos cabeçalhos dos pacotes em uma árvore legível. Os dados também são exibidos em HEX e ASCII na parte inferior da tela.

A natureza visual do WireShark facilita a compreensão do tráfego de rede, mas você ainda precisará filtrar o tráfego de rede na maioria dos casos. O WireShark tem recursos avançados de filtragem, incluindo suporte a centenas de protocolos.

DICA: para ver os protocolos disponíveis e criar filtros complexos, clique no botão próximo à parte superior da janela do WireShark.

Para recriar o filtro usado no exemplo do tcpdump acima, insira a seguinte expressão na caixa de filtro de WireShark:

ip.addr==<your IP address> && tcp.port==80

Ou use os conhecimentos de HTTP da WireShark:

ip.addr==<your IP address> && http

Isso filtrará os resultados da captura apenas para os pacotes envolvidos na interação com o servidor do Google Agenda. Clique em cada pacote para ver o conteúdo e realizar a transação.

DICA: você pode clicar com o botão direito do mouse em um dos pacotes e escolher "Follow TCP Stream" para exibir as solicitações e as respostas sequencialmente em uma única janela.

O WireShark oferece várias maneiras de salvar suas informações de captura. É possível salvar um, alguns ou todos os pacotes. Se estiver visualizando um stream TCP, clique no botão "Save As" para salvar apenas os pacotes relevantes. Você também pode importar a saída de uma captura tcpdump e vê-la no WireShark.

Problema: SSL e criptografia

Uma limitação comum das ferramentas de captura de pacotes é a impossibilidade de visualizar dados criptografados por uma conexão SSL. O exemplo acima acessa um feed público, por isso o SSL não é necessário. No entanto, se o exemplo acessasse um feed particular, o cliente precisaria se autenticar com o serviço de autenticação do Google, que exige uma conexão SSL.

O snippet a seguir é semelhante ao exemplo anterior, mas aqui o CalendarService solicita o metafeed da agenda do usuário, que é um feed particular que requer autenticação. Para autenticar, basta chamar o método setUserCredentials. Esse método aciona uma solicitação HTTPS para o serviço ClientLogin e pega o token de autenticação da resposta. O objeto CalendarService incluirá o token de autenticação em todas as solicitações subsequentes.

CalendarService myService = new CalendarService("exampleCo-fiddlerSslExample-1");
myService.setUserCredentials(username, userPassword);
final String METAFEED_URL = "http://www.google.com/calendar/feeds/default";
URL feedUrl = new URL(METAFEED_URL);
CalendarFeed resultFeed = myService.getFeed(feedUrl, CalendarFeed.class);

System.out.println("Your calendars:");
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
  CalendarEntry entry = resultFeed.getEntries().get(i);
  System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();

Considere o tráfego de rede necessário para autenticar e acessar um feed particular da API Google Data:

  1. Enviar credenciais de usuário para o serviço ClientLogin
    • Envie um POST HTTP para https://www.google.com/accounts/ClientLogin com os seguintes parâmetros no corpo da mensagem:
      • E-mail: o endereço de e-mail do usuário.
      • Passwd: a senha do usuário.
      • source: identifica o aplicativo cliente. Precisa estar no formato companyName-applicationName-versionID. Os exemplos usam o nome ExampleCo-SaberSSLExemplo-1.
      • service: o nome do serviço do Google Agenda é "cl".
  2. Receber o token de autorização
    • Se a solicitação de autenticação falhar, você receberá um Código de status HTTP 403 Acesso negado.
    • Se for bem-sucedida, a resposta do serviço será um código de status HTTP 200 OK, além de três códigos alfanuméricos longos no corpo da resposta: SID, LSID e Auth. O valor Auth é o token de autorização.
  3. Solicitar metafeed da agenda particular
    • Envie um HTTP GET para http://www.google.com/calendar/feeds/default com o seguinte cabeçalho:
    • Authorization: GoogleLogin auth=<yourAuthToken>
      

Execute o snippet e visualize o tráfego de rede no WireShark (usando "http || ssl" como filtro). Você verá os pacotes SSL e TLS envolvidos na transação, mas os pacotes de solicitação e resposta ClientLogin são criptografados nos pacotes "Application Data". Não se preocupe, vamos analisar uma ferramenta para revelar essas informações criptografadas.

Fiddler

O Saber mais é uma outra ferramenta de detecção de pacote gráfico. No entanto, ele se comporta de maneira muito diferente das ferramentas apresentadas até agora. Ele funciona como um proxy entre seu aplicativo e os serviços remotos com que você interage, tornando-se efetivamente um intermediário. Ele estabelece a conexão SSL com o aplicativo e o serviço da Web remoto, descriptografando o tráfego de um endpoint, capturando o texto simples e recriptografando o tráfego antes de enviá-lo. Infelizmente, o GAIA só está disponível para Windows, para todos os usuários de Mac e Linux.

Observação:a compatibilidade com SSL requer o GAIA versão 2 e o .NET Framework versão 2.0.

A visualização do tráfego de rede no GoDaddy é feita principalmente pela guia Inspetor de sessão. Estas são as subguias mais úteis para depurar problemas com as APIs de dados do Google:

  • Cabeçalhos: mostra os cabeçalhos HTTP em formato de árvore recolhível.
  • Auth: mostra os cabeçalhos do Authentication.
  • Raw: mostra o conteúdo dos pacotes de rede em texto ASCII.

DICA: clique no ícone no canto inferior esquerdo da janela do GoDaddy para ativar e desativar a captura.

Ele usa o .NET Framework para configurar conexões de rede e usá-lo como proxy. Isso significa que todas as conexões feitas com o Internet Explorer ou com o código .NET serão exibidas no GoDaddy por padrão. No entanto, o tráfego do exemplo de Java acima não será mostrado porque o Java tem uma maneira diferente de configurar proxies HTTP.

Em Java, defina o proxy HTTP usando as propriedades do sistema. O NGINX é executado na porta 8888. Portanto, para uma instalação local, é possível fazer com que o código Java use o NGINX como proxy para HTTP e HTTPS, adicionando estas linhas:

System.setProperty("http.proxyHost", "localhost");
System.setProperty("http.proxyPort", "8888");
System.setProperty("https.proxyHost", "localhost");
System.setProperty("https.proxyPort", "8888");

Se você executar o exemplo com essas linhas, vai receber um stack trace ruim no pacote de segurança do Java:

[java] Caused by:
  sun.security.validator.ValidatorException: PKIX path building failed:
  sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Captura de tela do Vietnã
O GoDaddy pode descriptografar e exibir o tráfego SSL.

Esse erro ocorre quando não é possível verificar o certificado retornado do servidor em uma conexão SSL. Nesse caso, o certificado inválido vem do NGINX, atuando como um intermediário. Ele gera certificados em tempo real e, como não é um emissor confiável, esses certificados farão com que o Java falhe ao configurar a conexão SSL.

Observação: quando o NGINX estiver em execução, qualquer conexão SSL que você fizer no Internet Explorer acionará um "Alerta de segurança", perguntando se você quer continuar, apesar do certificado de desenho. Clique em "Ver certificado" para ver o certificado gerado pelo GoDaddy.

Como contornar essa exceção de segurança? Basicamente, é necessário reconfigurar a estrutura de segurança do Java para confiar em todos os certificados. Felizmente, você não precisa reinventar a roda aqui. Confira a solução de Francisco Labrie e adicione o método SSLUtilities.trustAllHttpsCertificates() ao exemplo acima.

Depois de configurar o Java para usar o GoDaddy como proxy e desativar a verificação padrão do certificado, você vai poder executar o exemplo e ver todo o tráfego enviado pela rede em texto simples. Não roube minha senha.

Essa transação de autenticação é apenas um pequeno exemplo de tráfego SSL. Alguns aplicativos da Web usam conexões SSL exclusivamente. Por isso, a depuração do tráfego HTTP está fora de questão sem uma maneira de descriptografar os dados.

Conclusão

O tcpdump está disponível no Linux, Mac OS X e Windows. Ele é uma ótima ferramenta quando você sabe o que está procurando e precisa apenas de uma captura rápida. No entanto, existem algumas ferramentas gráficas que apresentam o tráfego de rede em formatos mais fáceis de entender. O tcpdump tem muito mais opções e recursos de filtragem do que os que vimos aqui. Para ver a descrição completa da funcionalidade do tcpdump, digite "homem tcpdump" ou acesse a página do manual do tcpdump.

O WireShark também está disponível no Linux, Mac OS X e Windows. O suporte integrado a centenas de protocolos torna o WireShark uma ferramenta útil para muitos aplicativos, não apenas para depuração HTTP. Essa introdução quase não mostra os muitos recursos do WireShark. Para mais informações, digite "man wireshark" ou visite o site do WireShark.

Ele também tem muitos recursos excelentes, mas o diferencial dele é a capacidade de descriptografar o tráfego SSL. Para mais informações, acesse o site do GoDaddy2.

Esses aplicativos de detecção de pacote são ótimas ferramentas que você precisa ter na sua caixa de ferramentas, e os leitores observados já perceberam que todos são sem custo financeiro! Na próxima vez que você trabalhar com APIs do Google e encontrar algo suspeito, puxe um desses analisadores de rede e analise melhor o que está acontecendo. Se você não encontrar o problema, poste uma pergunta no grupo de discussão. Incluir mensagens de rede relevantes ajuda outras pessoas a entender e diagnosticar o problema específico.

Boa sorte e bom perfume!

Recursos