Transição tecnológica
Expediente editorial Diretor Geral Rafael Peregrino da Silva rperegrino@linuxmagazine.com.br
EDITORIAL
Editores Flávia Jobstraibizer fjobs@linuxmagazine.com.br Kemel Zaidan kzaidan@linuxmagazine.com.br Editora de Arte Larissa Lima Zanini llima@linuxmagazine.com.br Estagiário Felipe Brumatti Sentelhas fsentelhas@linuxmagazine.com.br Colaboradores Adriano Matos Meier, Alexandre Borges, Alexandre Santos, Augusto Campos, Charly Kühnast, Dario Bestetti, Erik Bärwaldt, Gavin W. Burris, Hans-Peter Merkel, Jon ‘maddog’ Hall, Klaus Knopper, Kurt Seifried, Michael Uelschen, Tim Schürmann, Zack Brown. Tradução Emersom Satomi, Pablo Hess, Elias Graciano, Rodrigo Garcia. Revisão Cristiana Ferraz Coimbra Editores internacionais Uli Bantle, Andreas Bohle, Jens-Christoph Brendel, Hans-Georg Eßer, Markus Feilner, Oliver Frommel, Marcel Hilzinger, Mathias Huber, Anika Kehrer, Kristian Kißling, Jan Kleinert, Daniel Kottmair, Thomas Leichtenstern, Jörg Luther, Nils Magnus. Anúncios: Rafael Peregrino da Silva (Brasil) anuncios@linuxmagazine.com.br Tel.: +55 (0)11 3675-2600 Penny Wilby (Reino Unido e Irlanda) pwilby@linux-magazine.com Amy Phalen (América do Norte) aphalen@linuxpromagazine.com Hubert Wiest (Outros países) hwiest@linuxnewmedia.de Diretor de operações Claudio Bazzoli cbazzoli@linuxmagazine.com.br Na Internet: www.linuxmagazine.com.br – Brasil www.linux-magazin.de – Alemanha www.linux-magazine.com – Portal Mundial www.linuxmagazine.com.au – Austrália www.linux-magazine.es – Espanha www.linux-magazine.pl – Polônia www.linux-magazine.co.uk – Reino Unido www.linuxpromagazine.com – América do Norte Apesar de todos os cuidados possíveis terem sido tomados durante a produção desta revista, a editora não é responsável por eventuais imprecisões nela contidas ou por consequências que advenham de seu uso. A utilização de qualquer material da revista ocorre por conta e risco do leitor. Nenhum material pode ser reproduzido em qualquer meio, em parte ou no todo, sem permissão expressa da editora. Assume-se que qualquer correspondência recebida, tal como cartas, emails, faxes, fotografias, artigos e desenhos, sejam fornecidos para publicação ou licenciamento a terceiros de forma mundial não-exclusiva pela Linux New Media do Brasil, a menos que explicitamente indicado. Linux é uma marca registrada de Linus Torvalds. Linux Magazine é publicada mensalmente por: Linux New Media do Brasil Editora Ltda. Rua São Bento, 500 Conj. 802 – Sé 01010-001 – São Paulo – SP – Brasil Tel.: +55 (0)11 3675-2600 Direitos Autorais e Marcas Registradas © 2004 - 2011–: Linux New Media do Brasil Editora Ltda. Impressão e Acabamento: RR Donnelley Distribuída em todo o país pela Dinap S.A., Distribuidora Nacional de Publicações, São Paulo. Atendimento Assinante www.linuxnewmedia.com.br/atendimento São Paulo: +55 (0)11 3675-2600 Rio de Janeiro: +55 (0)21 3512 0888 Belo Horizonte: +55 (0)31 3516 1280 ISSN 1806-9428
Impresso no Brasil
Recentemente, em reunião com um corretor de seguros, tivemos novamente aquela epifania de constatação de plantão: estamos assistindo a um “repeteco” tecnológico de algo vivido há 30 anos durante o advento do computador pessoal. O corretor usava um notebook, equipado com (alguma versão do) Windows®, mas seu celular era equipado com Android (Linux, open source). Essa combinação está se repetindo em pelo menos 68% do tempo atualmente, segundo dados das principais consultorias de mercado e conforme divulgado durante a MOTODEV App Summit em maio deste ano. O mais interessante, entretanto, é que, enquanto o celular (ainda) não é suficiente para substituir o PC, seu primo maior, o tablet, está ganhando cada vez mais adeptos. Embora com acesso limitado em grande maioria às classes A e B, seus usuários relatam estar cada vez menos propensos a ligar seus notebooks ou desktops. A mesma plataforma que equipa os celulares predominantemente nos dias de hoje está fadada a equipar os tablets. O Android está se estabelecendo como plataforma padrão para esse tipo de desenvolvimento. A escolha realizada pelo Google – que não quer nada menos do que “aumentar a Internet”, com o objetivo de ganhar escala para o seu modelo de negócios baseado em propaganda sensível a contexto – de fornecer a tecnologia de base para os equipamentos que deverão estar nas mãos de mais de 70% da população do planeta, foi um primor estratégico! Além dos dados de busca, esses aparelhos servirão com certeza como coletores de dados dos hábitos de seus usuários, o que deverá aumentar a assertividade da propaganda veiculada pelo gigante das buscas. Do lado dos fabricantes de aparelhos (Samsung, Motorola, HTC, Sony-Ericsson, Huawei, para citar apenas alguns, pois há mais de 90 no momento), a plataforma caiu nas graças de quase todos. O fato de ser real e totalmente aberta conferiu aos fabricantes um poder nunca antes disponível, qual seja, o de operar em todos os níveis de desenvolvimento de seus sistemas gratuitamente. Para os fabricantes de software, há uma plataforma mais ou menos padronizada para desenvolvimento de programas, que está se consolidando e estabilizando com a chegada do Android 4.0. Veremos praticamente toda uma nova gama de aplicativos aparecendo para a plataforma, da mesma forma que ocorreu com o PC há três décadas. A demanda por profissionais de desenvolvimento para dispositivos móveis está cada vez mais aquecida e os especialistas já disponíveis no mercado estão sendo disputados a tapa. A pilha de serviços em torno do Android está se consolidando e não tardarão a aparecer inclusive entidades que certifiquem a proficiência dos desenvolvedores na plataforma. Para o usuário comum é apenas mais uma ferramenta, mas que democratiza o acesso à tecnologia pelo ganho de escala e pela quantidade de programadores que arregimenta. Como a base de tudo isso é o Software Livre, todas as vantagens oriundas das tecnologias abertas vêm de roldão: competição, inovação mais rápida, soluções mais flexíveis, controle de plataforma e independência de fornecedor, maior estabilidade e segurança, sem esquecer da formação local de mão-de-obra. Parafraseando Linus Torvalds em sua palestra na LinuxCon Brasil 2011: isso tudo vai estar até na pia da sua cozinha – pois já chegou à sua geladeira... ■ Rafael Peregrino da Silva Diretor de Redação
4
www.linuxmagazine.com.br
ÍNDICE
CAPA Encarar os desafios ou pedir para sair?
33
Não são só os usuários que cometem erros primários. Administradores de redes e programadores costumam facilitar frequentemente a vida dos criminosos digitais, seja por descuido ou desconhecimento.
Caça aos invasores
34
No mundo digital, segurança nunca é demais, principalmente se a sua empresa atua diretamente em serviços web. Através da análise de um caso real, saiba como se proteger de um ataque a um serviço de webhost, que partiu de um cliente da própria empresa.
Corrente de confiança
40
Placas-mãe bem equipadas às vezes trazem chips de computação confiável, embora os usuários e sistemas operacionais raramente os utilizem. O kernel Linux já domina essa tecnologia e seus usuários já podem dar suporte a uma ampla corrente de confiança com o TrustedGRUB.
Fora do Radar
46
Em função de seu design inteligente, o Tor oferece máxima segurança aos usuários que desejam resguardar sua identidade.
6
www.linuxmagazine.com.br
Linux Magazine 85 | ÍNDICE
COLUNAS Klaus Knopper
PROGRAMAÇÃO 10
Charly Kühnast
12
Zack Brown
13
Augusto Campos
14
Alexandre Borges
16
Kurt Seifried
18
Programação IPv6 para web
64
NOTÍCIAS Geral
22
➧ O código-fonte do Android 4.0 ➧ Envenenamento de DNS nos provedores brasileiros
CORPORATE Notícias
23
➧ IBM sob nova direção
Linguagens de programação tais como C, Python, Perl e o kit de ferramentas Qt podem trabalhar com IPv6. Mas você precisa se assegurar de que está usando as funções, classes e métodos corretos. Vamos mostrar como levar o seu aplicativo legado para o mundo do IPv6.
ANÁLISE Carteiro bom de briga
51
➧ Riverbed entra para a comunidade OpenStack Entrevista com Martin Roesch
24
Coluna: Jon “maddog” Hall
28
Coluna: Rafael Peregrino
30
Coluna: Alexandre Santos
32
TUTORIAL Conversão de PDF
72
Os desenvolvedores do Postfix queriam uma forma de descartar e-mails indesejados quando fossem entregues, então adicionaram o Postscreen à versão 2.8 de seu servidor. Este módulo filtra e ordena e-mails sem olhar seu conteúdo. Contato físico
56
O projeto Arduino é ideal para experiências com computação física.Demonstramos seu funcionamento com a construção de um timer simples.
SEGURANÇA Segurança além da senha
60
Envie alguns arquivos por email e receba documentos PDF como resposta, usando para isso LibreOffice, Postfix e scripts Shell. Caixa de areia
75
Há muito mais no universo da segurança, do que apenas senhas. Descubra como proteger seus servidores com autenticação de dois fatores.
SERVIÇOS O Arkose permite confinar programas potencialmente instáveis em uma sandbox virtual, mantendo seu sistema protegido contra acidentes e perda de dados.
Linux Magazine #85 | Dezembro de 2011
Editorial
04
Emails
08
Linux.local
78
Preview
82
7
Coluna do Augusto
COLUNA
20 anos do editor de textos vim Apesar de rústico a primeira vista, o editor de textos vim é há 20 anos o melhor amigo do administrador de sistemas.
Q
uando comecei a usar Unix, na primeira metade da década de 1990, tive a oportunidade de fazer alguns cursos introdutórios ao sistema em si e à sua administração em implementações variadas, incluindo o AIX, o HP-UX e, pouco depois, também no Linux. Eram cursos presenciais de uma semana e tinham algo em comum: todos eles destinavam algumas horas ao editor vi – geralmente descrito pelo instrutor como “o editor de textos do Unix” – com uma justificativa ameaçadora. Segundo eles, se o aluno algum dia fizesse alguma bobagem grande demais que impedisse o uso da ferramenta de configuração “fácil” oferecida pelo fabricante (o SMIT, no caso do AIX, ou o SAM no caso do HP-UX), teria que editar os arquivos de configuração “na mão”, e isso exigiria saber usar o vi. Os anos se passaram e eu logo aprendi que editar arquivos de configuração “na mão” não era algo tão indesejável assim, e que até havia alternativas ao vi para fazê-lo. Seu uso também não era tão assustador quanto aqueles instrutores acostumados às ferramentas dos fabricantes pareciam sinceramente acreditar. Mas, até chegar a esse ponto, passei muitas vezes pela “aula do vi” nos cursos que fiz e, mais tarde, até lecionei ela algumas vezes, sempre assistindo aos alunos já acostumados aos editores mais
Os 20 anos do vim foram comemorados por muitos fãs que encontram nele a opção que lhes permite realizar com melhor desempenho suas tarefas de desenvolvimento, administração ou mesmo edição de textos. 14
recentes tropeçarem um pouco antes de vencer o desafio de entender a diferença de contexto entre o modo de inserção e o de comando, e vendo o aluno distraído que não conseguia sair do editor. Isso em uma época em que as aulas eram no console e ainda não havia a discreta opção de fechar a janela do terminal e abrir outra... O heroico vi é criação de Bill Joy, um dos desenvolvedores originais do BSD, que desenvolveu esse editor a partir de 1976 – quando a ideia de um editor visual interativo ainda era tão recente que a alternância de modos e a interface baseada em meras sequências de teclas ainda poderiam ser consideradas bem mais fáceis que outras alternativas existentes. Hoje vivemos uma era de ambientes gráficos em que até mesmo o administrador de sistemas pode passar meses ou anos sem precisar editar algo no vi – mas ele continua sendo ensinado, não apenas por ser um editor poderoso e cheio de recursos, mas por fazer parte do padrão POSIX, o que significa que estará disponível em qualquer implementação ou clone do Unix. Possivelmente estará à mão até mesmo naquelas temidas situações em que a máquina tem problemas que impedem seu boot completo e, assim, precisa ser consertada em modo texto, monousuário ou sob outra condição restrita. Mesmo assim, os 20 anos do vim (a implementação mais moderna e avançada do vi que está na distribuição de Linux que você usa e em muitos Unix) foram comemorados por muitos fãs que o utilizam não por obrigação ou por falta de opções mais fáceis, mas porque encontram nele a opção que lhes permite realizar com melhor desempenho suas tarefas de desenvolvimento, administração ou mesmo edição de textos. Parabéns pelo aniversário, vim, e que venham mais 20 anos! ■ Augusto César Campos é administrador de TI e, desde 1996, mantém o site BR-linux.org, que cobre a cena do Software Livre no Brasil e no mundo.
www.linuxmagazine.com.br
Coluna do Alexandre Borges
COLUNA
Certificação e assinaturas digitais Em um esforço hercúleo, Alexandre Borges se desdobra para ensinar a qualquer um os mistérios da criptografia de chaves simétricas, assimétricas e dos certificados digitais.
E
scuto frequentemente algumas perguntas vindas de analistas: “Como garantir que nossas compras na Internet sejam seguras? O que significa aquele ‘cadeado’ na barra de status do navegador? Por que, quando entramos em algum site de home banking, solicitam-nos que aceitemos o tal do ‘certificado digital’? Afinal, para que serve tudo isso?” Para mim é claro e cristalino que você leitor sabe as exatas respostas para essas perguntas; contudo, de que maneira podemos explicar essas coisas para outros analistas e pessoas leigas exemplificadas por profissionais de outras áreas como vendedores, advogados ou médicos? A informação somente tem valor e melhora a sociedade quando é difundida e desfazer alguns mitos seria interessante para ajudar na conscientização da importância dessas informações e da tecnologia no dia-a-dia. Então quer dizer que é fácil explicar os conceitos de criptografia simétrica, assimétrica, hashing, certificado digital e assinatura digital? Longe disso. Aliás, nada mais difícil, mesmo para técnicos que já fazem parte deste mundo de TI. Eis como eu faço quando quero explicar as questões acima. Imaginem duas pessoas, com suas respectivas máquinas (A e B). A pessoa A quer enviar uma informação para a pessoa B, porém deseja que ninguém possa, no meio do caminho, visualizar a informação. Para tanto ela usa um algoritmo de chave simétrica. Mas o que é isso? Simples: é um algoritmo (ou programa, para leigos) que embaralha as informações e, para fazê-lo, usa uma espécie de senha (chave de sessão ou key session) para codificar os dados e a mesma senha para decodificá-los (desembaralhar os dados). É daí que vem a palavra simétrica: a mesma chave é usada nas duas pontas da comunicação, ou seja: para codificar e decodificar. E então, o que as pessoas fazem? A pessoa da máquina A combina com a pessoa da máquina B um algoritmo e uma senha (key session), e depois codifica os dados a serem enviados como elas combinaram. A pessoa da máquina B, ao receber estes dados, decodifica-
16
-os usando o algoritmo e a senha já combinados entre as partes. Aliás, por que o nome “chave de sessão” (key session)? Porque esta senha (chave) somente vale para cada sessão de envio de informações, ou seja, no próximo envio o usuário pode combinar uma nova senha. Funciona? Muito bem. É rápido? Bastante. Só tem um pequeno problema: como as pessoas vão trocar esta senha (chave de sessão) entre si? Qualquer meio está sujeito a interceptação: email, SMS, telefone, fax, pessoalmente, correios... Nada, absolutamente nada, é seguro para trocar estas senhas (ou chaves). É aí que está o risco: se alguém tiver posse desta senha (chave) e tiver uma vaga ideia do algoritmo usado, poderá decodificar as informações trocadas e ler o que foi enviado. E agora, o que fazer? Neste ponto, entram em jogo os algoritmos assimétricos. Por que assimétricos? Porque a mesma chave que é usada para codificar NÃO é a mesma usada para decodificar. Eis como ocorre o processo: a pessoa da máquina A, através de um algoritmo assimétrico escolhido em comum acordo entre as partes, gera um par de chaves (ou senhas, para leigos), a pública e a privada (pub-A e priv-A). Como o nome diz, a chave pública pode (e deve) ser conhecida por qualquer pessoa; todavia, a privada é somente de conhecimento próprio e individual. Em seguida, a pessoa da máquina B faz o mesmo, ou seja: gera seu par de chaves assimétricas (pub-B e priv-B). E o que se segue é que, como a pessoa da máquina A sabe a chave pública da pessoa da máquina B (pub-B), ela usa esta chave (pub-B) para codificar, usando o algoritmo simétrico combinado, a chave de sessão que elas queriam trocar e não podiam de maneira segura. Aí a tal chave de sessão (codificada) é enviada para a pessoa da máquina B. Agora ambos, com a mesma chave pública, podem trocar dados criptografados como explicado acima. Aí que está a mágica: uma vez que uma informação é codificada dessa forma (usando a chave pub-B), somente com a respectiva chave privada (priv-B) é possível decodificá-la. Esse mecanismo é uma das maravilhas das chaves assimétricas: o que é codificado com uma chave do par gerado (público e pri-
www.linuxmagazine.com.br
vado) somente pode ser decodificado com a outra chave do mesmo par. Funciona? Sim. É rápido? Hum... aí vem um pequeno detalhe: ao contrário dos algoritmos simétricos, os assimétricos são muito (e coloque muito nisso) mais lentos. Se fossem rápidos, poderíamos abandonar os simétricos e já enviar a informação (e não apenas a chave de sessão) com o uso do par de chaves simétricas (pública e privada). Tudo resolvido? Não. Por quê? Porque a pergunta agora é outra: como a pessoa da máquina A pode ter certeza absoluta de que a chave pública da pessoa da máquina B é dela mesma? E se for de um hacker fingindo ser a pessoa da máquina B? Aí a pessoa da máquina A teria um grande problema: ela estaria codificando a chave de sessão com a chave pública do hacker e enviando para a pessoa da máquina B (que não conseguiria abrir a informação). O hacker, interceptando os dados codificados, conseguiria decodificar a informação (que é a chave de sessão) e poderia se passar pela pessoa da máquina B, comprometendo toda a troca de informações entre as partes. É exatamente agora que entra em cena o certificado digital. Aliás, o que é esse certificado e como funciona? A parte interessada (por exemplo, as pessoas das máquinas A e B, ou mesmo uma empresa, em um contexto mais realista), contrata uma terceira parte (autoridade certificadora, também conhecida como CA) e, no momento do contrato, envia sua própria chave pública. Então essa companhia certificadora (CA) emite o certificado dessa pessoa ou empresa. Esse certificado é um objeto (ou um selo, para leigos) emitido pela autoridade certificadora (CA), que possui total idoneidade internacional (Certsign, por exemplo). O certificado contém dentro de si a chave pública enviada pela parte interessada e algumas informações sobre a pessoa ou empresa que está comprando o serviço de certificação digital. E aqui está a ideia principal: quando a pessoa da máquina A pede a chave pública da pessoa da máquina B (pub-B), a pessoa da máquina B não envia a sua chave pública diretamente, e sim seu certificado digital emitido por uma companhia certificadora. Assim, quem está garantindo e atestando que aquele certificado (mais especificamente, a chave pública) vem da pessoa da máquina B é a autoridade certificadora que tem reconhecimento global para tal ação. Ou seja: ninguém (nem a pessoa da máquina A e nem a da máquina B) corre o risco de se ver enganado por um hacker. Funciona? Muito bem. Resolvido o problema? Ainda não. Por quê? Porque quem pode garantir para a pessoa da máquina A que aquele certificado da pessoa da máquina B, emitido e atestado pela autoridade certificadora (CA) foi, de fato, emitido por ela? E se foi um hacker que está se passando pela CA e forjou um certificado? Puxa! Isso parece não ter mais fim... Sempre há um risco, mas tem solução. Antes de avançarmos para o próximo ponto, é útil comentar o que são e para que servem os algoritmos de hash.
Linux Magazine #85 | Dezembro de 2011
Fundamentalmente, a ideia é assegurar a integridade dos dados, ou seja, ter certeza de que os dados enviados pela máquina A são os mesmos recebidos pela máquina B. E como isso acontece? Com esses dados é feita uma conta (daí o uso do algoritmo) e esse cálculo é anexado junto aos dados a serem enviados. Quando esses dados chegam à máquina B, o mesmo cálculo é feito usando-se os dados recebidos, e o resultado é comparado com o cálculo que foi feito pela máquina A e anexado aos dados enviados. Se os resultados forem iguais, os dados que chegaram estão íntegros e não sofreram nenhuma alteração. Se houver discrepância, pede-se para retransmitir os dados novamente. Simples, não? Agora sim é possível falar do último elo desta corrente, que é a assinatura digital. E qual é o seu objetivo? Garantir que, de fato, o certificado digital foi realmente emitido pela companhia certificadora (CA). Para tanto, ocorre o seguinte processo: a CA (companhia certificadora), antes de emitir o certificado para a pessoa da máquina A ou B, faz um cálculo de hash desse certificado e criptografa esse cálculo usando sua própria chave privada (sim... a chave privada e não a pública, por isso chama-se assinatura digital), anexando o resultado no certificado. O usuário da máquina A ou B, através do browser (que já tem diversas chaves públicas cadastradas dentro dele) usa a chave pública da companhia certificadora (CA) para descriptografar o hash codificado do certificado que é, em seguida, comparado com o cálculo feito pela própria máquina de A ou B. Se as os hashes feitos na máquina forem iguais ao hash que veio anexado ao certificado, pode-se garantir que aquele certificado foi, de fato, emitido pela companhia certificadora (CA) em questão, pois a chave pública da companhia certificadora (CA) somente decodifica os dados criptografados com a sua respectiva chave privada. Repare que a assinatura digital é contrária à codificação assimétrica: na assinatura digital, o dado é codificado com a chave privada e decodificado com a pública. Na criptografia assimétrica acontece o inverso, pois o dado é codificado com a chave pública e decodificado com a respectiva chave privada. Esse processo descrito acima é à prova de bala? Sim. As falhas são decorrentes de possíveis quebras dos algoritmos envolvidos, ou ainda erro na implementação deste mecanismo. É exatamente por isso que os hackers (ou melhor, crackers) costumam tentar atacar a ponta mais fraca do processo, que é o usuário, e conseguir as senhas (chaves) antes de tudo começar, pois durante o processo isso é muito difícil – para não dizer impossível. Até o mês que vem. ■ Alexandre Borges (alex_sun@terra.com.br) é instrutor independente e ministra regularmente treinamentos de tecnologia Oracle, Symantec e EC-Council (CEH e CHFI), além de estar sempre envolvido com assuntos relacionados ao kernel Linux.
17
Tropa de elite
CAPA
Encarar os desafios ou pedir para sair? Não são só os usuários que cometem erros primários. Administradores de redes e programadores costumam frequentemente facilitar a vida dos criminosos digitais, seja por descuido ou desconhecimento. por Kemel Zaidan
D
ados bancários, endereço, números de telefone, compras, relatórios, documentos pessoais, conversas telefônicas, agenda de contatos, calendário, editais, impostos, dados governamentais, círculos sociais etc. Poderíamos estender a lista indefinidamente se quiséssemos, mas parece não haver limites para a capacidade da rede de concentrar nossos dados. A tendência parece mesmo ser de que a Internet venha a ser o grande “hub” de nossas vidas sociais, tanto fora quanto dentro do universo digital. Porém, a preocupação com a segurança desses dados não acompanhar a importância da rede em nossas vidas na mesma proporção de seu crescimento. A linha tênue entre o público e o privado está cada vez mais difícil de se distinguir uma vez que hoje é muito mais difícil manter informações pessoais de forma privada, do que era no passado. Por outro lado, boa parte das pessoas que começam a entrar na rede agora, ignoram as possibilidades e a importância de manterem dados pessoais afastados do conhecimento de grandes corporações, pois muitas vezes não se sabe quais e para que fins grandes serviços web, como o Google ou o Facebook, coletam informações de seus usuários. É por essas e outras questões que a Linux Magazine #85 traz para você o tema segurança. Nela, você poderá conferir o interessante caso real relatado por Ygor Bittencourt, de um provedor de hospedagem, que teve seus servidores invadidos e utilizados para atacar um terceiro computador. Você poderá reproduzir não apenas o cenário do ataque, mas também conferir como ele foi descoberto, para só então tomar as medidas preventivas cabíveis para que uma situação como essa não aconteça na sua rede. Outro interessante artigo é o “Fora do Radar”, onde o nosso leitor poderá instalar e configurar o Tor, uma incrível ferramenta para a navegação segura e anônima, cujo código fonte foi originalmente aberto pelo Intituto de Pesquisas da Marinha dos Estados Unidos.
A rede Tor teve um papel importante nos conflitos recentes ocorridos na “Primavera Árabe”. Já no artigo “Corrente de confiança”, o administrador de sistemas irá aprender como tirar proveito dos chips TPM que começam a equipar as placas mães mais modernas ao permitir criar toda uma cadeia de assinatura de software, o que pode fazer toda a diferença em um ambiente de servidores. Portanto, arme-se com a sua Linux Magazine mais recente e prepare-se para a dura batalha do dia-a-dia porque missão dada, “parceiro”, é missão cumprida! ■
Matérias de capa Caça aos invasores
34
Corrente de confiança
40
Fora do Radar
46
ANÁLISE | Introdução ao Arduino
Introdução ao Arduino
ANÁLISE
Contato físico O projeto Arduino é ideal para experiências com computação física. Demonstramos seu funcionamento com a construção de um timer simples. por Dmitri Popov
E
m seu website [1], o projeto Arduino se apresenta como uma “plataforma para protótipos eletrônicos de código aberto, baseada em hardware e software flexíveis e fáceis de usar”, o que não soa muito animador. Mas essa minúscula e econômica plataforma lhe permite construir uma gama de projetos fantásticos – e não há exigência de habilidades com solda. O projeto consiste basicamente de uma placa que pode ser programada
para controlar diferentes dispositivos (motores, luzes etc.) conforme a entrada que ela recebe de sensores conectados. É possível conectar praticamente qualquer sensor à placa do Arduino – por exemplo, um resistor dependente de luz, um sensor de movimento, um termistor ou um sensor de pressão – e programar o microcontrolador da placa para executar várias ações com os controladores conectados aos pinos digitais de saída.
A programação é feita no IDE Arduino, que usa uma linguagem de programação baseada em Processing [2]. A linguagem em si é relativamente fácil de aprender, então mesmo que você não tenha nenhuma experiência com programação, pode aprender o básico rapidamente. A seção de referência no site do projeto contém uma visão detalhada da linguagem para quem quer iniciar, estando disponível também a versão
Figura 1 O IDE Arduino não é muito bonito, mas cumpre bem Figura 2 O Gnoduino é uma alternativa mais polida ao sua função.
56
IDE padrão do Arduino.
www.linuxmagazine.com.br
Introdução ao Arduino | ANÁLISE
sudo add-apt-repository ppa:pmjdebruijn/gnoduino-release sudo apt-get update sudo apt-get install gnoduino
Em seguida conecte a placa Arduino à sua máquina e você estará pronto para começar seu primeiro projeto. É possível criar todo tipo de dispositivos com o Arduino mas, para começar, é melhor algo simples. Então descreverei como construir um timer básico para treinarmos a técnica Pomodoro [6] de gerenciamento de tempo. Nesse projeto só precisamos de três componentes: um LED, um resistor (entre 200 e 680 ohms) e dois cabos de jumper. O resistor é opcional, sendo usado para limitar a corrente e evitar danos ao LED. Figura 3 O Fritzing oferece um ambiente gráfico para criar projetos do Arduino.
livre do Arduino Programming Notebook [3] como guia rápido e prático. Os programas Arduino são chamados de sketches. Você escreve, depura e faz o upload desses sketches na placa usando o IDE. O Arduino foi desenvolvido como uma forma de introduzir às pessoas o mundo da computação física (construir sistemas físicos interativos que podem perceber o mundo analógico e reagir a ele) mas o projeto é mais do que apenas uma ferramenta educacional. É possível usar a placa para todos os tipos de solução inteligente, desde um alarme ativado por movimentos até um disparador acionado por luz para sua câmera. Você pode comprar diferentes modelos Arduino gastando a partir de 30 dólares, sendo desnecessário gastar todas suas economias para poder se iniciar no maravilhoso mundo da computação física. Você pode precisar acrescentar à sua lista de compras também, uma protoboard (placa com furos e conexões condutoras para montagem de circuitos elétricos experimentais), alguns cabos de jumper, alguns LEDs e resistores.
Linux Magazine #85 | Dezembro de 2011
Usando a protoboard, pode-se construir projetos Arduino sem precisar soldar componentes – uma solução perfeita para a experimentação.
Preparação A primeira tarefa é instalar o ambiente de desenvolvimento para poder escrever sketches e fazer o upload no Arduino. Se estiver usando o Ubuntu ou derivados, instalar o programa necessário é simples: sudo apt-get install arduino
Esse comando instala o IDE Arduino padrão, escrito em Java (figura 1). O IDE cumpre sua função, mas não se integra muito bem com o Gnome. Felizmente, o Gnoduino fornece uma alternativa polida e leve, projetada especificamente para esse ambiente de desktop (figura 2). O Gnoduino exibe as janelas nativas do Gnome e tem melhor renderização de fontes, além do recurso útil de numerar linhas. O programa foi escrito em Python e, no Ubuntu, pode ser instalado a partir de um PPA dedicado [5], com os seguintes comandos:
Esquematização Antes de começar a montar os componentes na matriz de contato e cabeá-los, é uma boa ideia desenhar um esquema para ser usado como referência. Embora você possa usar caneta e papel para fazê-lo, há uma ferramenta melhor chamada Fritzing [7]. Esse programa oferece um ambiente gráfico completo para projetos Arduino: você pode usá-lo para desenhar layouts na matriz de contato, esquematização ou circuitos impressos. Usar o Fritzing em um projeto tão simples pode parecer exagero, mas assim que seus projetos Arduino forem ficando mais avançados, você vai começar a apreciar as capacidades e recursos desse programa. O Fritzing não exige uma instalação tradicional. Para obter a última versão, acesse o site do projeto, descompacte o arquivo baixado e execute o script em Bash Fritzing.sh no diretório correspondente para iniciar o aplicativo. A visão Breadboard no Fritzing permite criar designs na protoboard com o posicionamento de componentes e seu cabeamento (figura 3). A coleção principal de componentes
57
ANÁLISE | Introdução ao Arduino
Figura 4 O Fritzing também gera esquemas de cabea-
Figura 5 Com o Fritz você pode projetar esquemas de
mento baseados no projeto da protoboard.
na paleta Parts inclui praticamente todas as partes essenciais: de resistores a switches, de LEDs a diversos tipos de sensor. O Fritzing também permite a importação de coleções de componentes de terceiros. Para fazê-la, selecione File/Parts Bin/Open e escolha a coleção que deseja. Você pode até desenhar suas próprias partes. A página Creating Custom Parts [8] do website tem bastante material sobre isso. Assim que posicionar um componente na protoboard, você pode
58
circuitos impressos.
modificar suas propriedades na paleta Inspector. É possível, por exemplo, especificar tolerância, resistência e espaçamento de pinos para resistores, além de cor e tamanho, para LEDs. Para conectar os componentes com cabos de jumper, clique com o botão direito no socket desejado da matriz, depois arraste o mouse até o socket de destino, enquanto segura o botão direito. Depois é possível mudar a cor do cabo adicionado na paleta Inspector para melhorar a leitura do desenho. Por padrão, o Fritzing usa
Listagem 1: Sketch para um timer
Listagem 2: Sketch aperfeiçoado para um timer
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21
int var = 0; void setup() { pinMode(13, OUTPUT); } void loop() { while(var < 5){ digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); delay(1000); var++; } digitalWrite(13, HIGH); delay(15000); var = 0; digitalWrite(13, LOW); delay(1500000); }
int var = 0; void setup() { pinMode(9, OUTPUT); pinMode(13, OUTPUT); } void loop() { while(var < 5){ digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); delay(1000); var++; } digitalWrite(9, HIGH); delay(15000); var = 0; digitalWrite(9, LOW); delay(1500000); }
cabos retos, que podem ser muito limitadores em estruturas mais complexas. Mas é possível curvar os cabos pressionando a tecla [Ctrl], clicando e arrastando. Enquanto você trabalha no design da matriz, o Fritzing silenciosamente gera um esquema de cabeamento para seu projeto, que pode ser visto ao mudarmos para a visão Schematic (figura 4). Todas as conexões entre componentes são consideradas ligações potenciais, sendo exibidas como linhas finas; você precisa usar o mouse para cabear os componentes de fato. Fazer isso manualmente pode ser um desafio, especialmente se estiver trabalhando com um desenho complexo. Felizmente, o Fritzing tem uma solução elegante: o recurso Autoroute pode cabear automaticamente os componentes. Os resultados podem às vezes ser decepcionantes, mas na maioria das vezes esse recurso faz um bom trabalho. Além disso, você pode melhorar esse resultado manualmente, se necessário. O Fritzing também permite que você exporte o esquema de cabeamento para diversos formatos. É possível salvar o esquema como uma imagem com File/Export/As Image, que oferece as opções PNG, SVG e PDF, entre outros. Também é possí-
www.linuxmagazine.com.br
Introdução ao Arduino | ANÁLISE
vel usar File/Export/List of parts (Bill of Materials) para gerar uma lista de compras bem formatada, com todos os componentes usados nos projetos. Se isso não for suficiente, ainda é possível usar o Fritz para desenhar um circuito impresso, portanto você pode transformar seu protótipo de matriz de contato em um produto de fato ou em um Arduino shield (figura 5). Melhor ainda, o serviço Fritzing Fab [9] pode produzir circuitos impressos, prontos para uso, baseados em seu design. Por enquanto, contudo, usaremos o Fritzing para criar um projeto de protoboard para o timer, como o da figura 3. Depois você pode usar o desenho como guia para cabear os componentes na matriz real e conectá-los ao Arduino para completar o projeto de hardware.
Sketch O próximo passo é escrever um sketch para o timer. Basicamente, você precisa programar o Arduino para ligar o LED a cada 25 minutos, sinalizando que é hora de um intervalo. Para deixar as coisas um pouco mais interessantes, você pode fazer o LED piscar cinco vezes, para atrair a atenção, antes de ligar. Para começar, inicie o Arduino IDE ou o Gnoduino e use o sketch da listagem 1. O que esse sketch faz? Como qualquer programa ou script, sua
primeira tarefa é definir as variáveis a serem usadas. Nesse caso, a declaração int var = 0 define a variável var, que atuará como um contador, com um valor de 0 (zero). Além disso, qualquer sketch Arduino deve conter dois blocos. A função setup() contém todo o código a ser executado uma vez no início do programa, enquanto a função loop() contém o programa em si, que é executado em repetição. “Por que isso?”, você pode se perguntar. Porque, diferentemente de um computador comum, o Arduino não pode executar vários programas ao mesmo tempo e os programas não podem terminar. Basicamente, quando você liga a placa Arduino ela executa o código, parando apenas quando você desliga. Neste caso, a função setup() inicializa o pino digital 13 como uma saída, usando a declaração pinMode(13, OUTPUT). Isso permite que o sketch controle o LED conectado ao pino 13. A função loop() contém o programa em si, que pode ser dividido, a grosso modo, em duas partes. A primeira é o laço while que liga o LED (a declaração digitalWrite(13, HIGH)), espera um segundo (delay (1000)), desliga o LED (digitalWrite(13, LOW)), espera outro segundo e então incrementa o contador em 1 (var++). O loop executa enquanto o valor de
var é menor que 5 (ou seja, o LED pisca cinco vezes). Quando var che-
ga a 5, a segunda parte do programa entra em ação, ligando o LED, esperando 15 segundos, desligando o LED e esperando 25 minutos. Para verificar erros no sketch, use o botão Verify no IDE Arduino. Se tudo correr bem, você deve ver a mensagem Binary sketch size: 1086 bytes (of a 32256 byte maximum) (o tamanho pode variar); do contrário, surgirão alertas indicando os erros. Finalmente, pressione Upload para enviar o sketch para o Arduino. A placa começará a executar o código imediatamente. Parabéns, seu primeiro hardware Arduino funciona!
Etapas posteriores Embora esse timer Arduino seja bem simples, você pode aperfeiçoá-lo. Por exemplo, pode adicionar um segundo LED no pino 9 e reescrever o sketch para que o primeiro LED pisque antes de o segundo ser ligado (listagem 2). Em vez de usar um segundo LED, você pode conectar um alto-falante e programar o Arduino para disparar um tom ou melodia simples. Resumindo, há muitas opções para refinar e melhorar esse simples timer. E depois que dominar o básico, você pode trabalhar em projetos mais complexos e empolgantes. ■
Mais informações
O autor
[1] Arduino: http://arduino.cc/
Dmitri Popov é formado em letras (idioma russo) e lingüística computacional; há vários anos trabalha como tradutor técnico e colaborador free-lancer. Já publicou mais de 500 artigos sobre software de produtividade, computação móvel, aplicativos web e outros tópicos relacionados à informática. Seus artigos já apareceram em sites e revistas da Dinamarca, Inglaterra, EUA, Alemanha, Rússia e, agora, do Brasil.
[2] Linguagem de programação Processing: http://processing.org/ [3] Arduino Programming Notebook: http://www.lulu.com/product/ file-download/arduino-programming-notebook/3524028 [4] Gnoduino: http://gnome.eu.org/evo/index.php/Gnoduino [5] PPA Gnoduino: http://launchpad. net/~pmjdebruijn/+archive/gnoduino-release [6] Técnica Pomodoro: http://www.pomodorotechnique.com/ [7] Fritzing: http://fritzing.org/ [8] Partes customizadas no Fritzing: http://fritzing.org/ learning/tutorials/creating-custom-parts [9] Fritzing Fab: http://fab.fritzing.org/fritzing-fab
Linux Magazine #85 | Dezembro de 2011
Gostou do artigo? rtigo? Queremos ouvir sua opinião. pinião. Fale conosco em m cartas@linuxmagazine.com.br zine.com r Este artigo no nosso osso site: e: http://lnm.com.br/article/6109 br/art /610
59
PROGRAMAÇÃO | Aplicativos web e IPv6
Aplicativos web e IPv6
PROGRAMAÇÃO
Programação IPv6 para web Linguagens de programação tais como C, Python, Perl e o kit de ferramentas Qt podem trabalhar com IPv6. Mas você precisa se assegurar de que está usando as funções, classes e métodos corretos. Vamos mostrar como levar o seu aplicativo legado para o mundo do IPv6. por Peter Hrenka
A
migração para a Internet IPv6 só vai funcionar se as aplicações que estão rodando na web também migrarem. Este artigo explica como os desenvolvedores podem readequar programas tanto para IPv4 quanto para IPv6. Você vai ver como trabalhar com IPv6 em C, Python, C++, Perl e com o kit de ferramentas Qt. A maioria dos programas usados como exemplo não necessitam de uma conexão nativa em IPv6 à Internet, o que significa que você pode testar seu código localmente, em qualquer distribuição Linux recente.
C 101 Os programadores ainda precisarão emitir uma chamada de sistema via socket() no IPv6 para definir um destino no formato de descritor de arquivos. Se esse destino tiver de ser compatível com o IPv6, o domínio deve ser PF_INET6 ou AF_INET6. Os tipos aqui podem ser os mesmos usados no IPv4, SOCK_STREAM para UDP e SOCK_DRAM para TCP. As coi-
64
sas começam a ficar empolgantes de verdade quando o socket realmente quer iniciar uma conexão. No lado do cliente é connect() e no lado do servidor é bind(). Ambos com a expectativa de obter um const struct sockaddr*. Mas onde encontrá-lo? Entre outras coisas, o RFC 3493 [1] descreve a função getaddrinfo(), que retorna estas estruturas sockaddr. O getaddrinfo() substitui o gethostbyname(), que é obsoleto e incapaz de realizar multithreading (ou, para ser mais preciso: incapaz de reentrância). De modo geral, a função getaddrinfo() ajuda a migrar gradualmente, sem dor, do IPv4 para o IPv6. A função trabalha com resolução de nomes, parsing (análise sintática), criação de estruturas de endereços e parâmetros para chamadas subsequentes de rede. A listagem 1 introduz a função getaddrinfo() e seus parâmetros. A node aponta para uma string que descreve o endereço com maior detalhamento. A string é normalmente um hostname na forma de www.
linuxmagazine.com.br. Também são
permitidas notações de endereços IPv4 ou IPv6, tais como 127.0.0.1 ou FF80::0201:02FF:FE03:0405%eth0. O parâmetro service descreve o número da porta.0 Os designadores de serviço, como aqueles listados em / etc/services, também são permitidos – por exemplo, http ou ssh – bem como números de portas em notação decimal. O parâmetro opcional hint pode apontar para uma addrinfo structure tal como a que é definida na listagem 2. res também usa essa estrutura, que dá suporte a vários resultados ligados por ai_next para chamar freeaddrinfo() quando os endereços não são mais necessários. Os desenvolvedores especificam o AF_INET como sendo o ai_family para receber endereços IPv4 e o AF_INET6 para receber endereços IPv6. Caso precise dos dois tipos de endereço, você deve especificar o AF_UNSPEC, que vai lhe dar primeiro o(s) endereço(s) IPv6 e depois o(s) IPv4. A estrutura res nunca possui AF_UNSPEC. Em vez
www.linuxmagazine.com.br
Aplicativos web e IPv6 | PROGRAMAÇÃO
disso, mantém a família de endereços tangíveis do endereço de retorno. Para o ai_socktype, você deve inserir o SOCK_STREAM para UDP, ou o SOCK_DGRAM para TCP, na estrutura hint. Ao inserir um 0, você verá várias entradas com os possíveis tipos para cada endereço, se houver. O ai_protocol permite ao programador requisitar um protocolo, tal como FP_INET ou FP_INET6. Geralmente é normal usar o valor 0 para receber resultados que batam com os outros parâmetros. Um aspecto prático é que os campos ai_family, ai_socktype e ai_protocol correspondem precisamente aos parâmetros domain, type e protocol na chamada de sistema socket(), o que significa que você pode simplesmente deixá-los para lá. O campo ai_addrlen armazena o valor retornado do comprimen-
to da estrutura do sockaddr_in. O ai_addr contém um ponteiro para um sockaddr_in para IPv4, ou um sockaddr_in6 para IPv6 dentro da estrutura res. Este apontador pode ser usado junto ao ai_addrlen como parâmetro para as chamadas de sistema connect(), bind(), sendto() ou recvfrom(). O campo ai_canonname da estrutura res contém um apontador para o nome canônico do host, caso você o requisite pelos ai_flags. Dê uma olhada no quadro 1 para ter uma ideia sobre as flags.
Efeitos colaterais Se você quiser escrever programas compatíveis com IPv6, deve evitar certas funções. Por exemplo, evite aquelas que esperam ou retornam uma struct in_addr como parâmetro (listagem 3).
As funções alternativas inet_pton() e inet_ntop() existem por causa de inet_aton() e inet_ntoa(), que convertem notações numéricas ASCII e struct in_addr para lá e para cá (listagem 4).
Python A versão 2.2 do Python adicionou uma função getaddrinfo() ao módulo padrão do socket [2]. Felizmente, as características perversas do C (o que inclui parâmetros obsoletos dentro das estruturas hints ou res) não se aplicam ao Python. Alguns parâmetros opcionais desta linguagem manipulam a função da estrutura hints da interface C: socket.getaddrinfo(host, port,family=0,socktype=0, U proto=0, flags=0)
Listagem 1: getaddrinfo()
Listagem 5: getaddrinfo.py
01 02 03 04 05
01 #!/usr/bin/env python 02 import sys 03 from socket import * 04 05 host = sys.argv[1] 06 port = 80 if len(sys.argv)<3 else sys.argv[2] 07 08 for addrinfo in getaddrinfo(host, port, AF_ UNSPEC, SOCK_STREAM): 09 family, socktype, proto, canonname, sockaddr = addrinfo 10 socketObject = socket(family, socktype, proto) 11 #socketObject = socket(*addrinfo[:3]) 12 if socketObject is None: continue 13 haveConnection = False 14 try: 15 socketObject. connect(sockaddr) 16 socketObject.close() 17 haveConnection = True 18 except: 19 pass 20 familyString = “IPv6” if family==AF_INET6 else “IPv4” 21 args = familyString, sockaddr[0], haveConnection 22 print(“{0} address {1}, connect = {2}”.format(*args))
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); void freeaddrinfo(struct addrinfo *res);
Listagem 2: struct addrinfo 01 struct addrinfo { 02 int ai_flags; 03 int ai_family; 04 int ai_socktype; 05 int ai_protocol; 06 size_t ai_addrlen; 07 struct sockaddr *ai_addr; 08 char *ai_canonname; 09 struct addrinfo *ai_next; 10 };
Listagem 3: Funções incompatíveis com IPv6 01 02 03 04 05 06 07
int inet_aton(const char *cp, struct in_addr *inp); in_addr_t inet_addr(const char *cp); in_addr_t inet_network(const char *cp); char *inet_ntoa(struct in_addr in); struct in_addr inet_makeaddr(int net, int host); in_addr_t inet_lnaof(struct in_addr in); in_addr_t inet_netof(struct in_addr in)
Listagem 4: inet_pton e inet_ntop 01 02 03
int inet_pton(int af, const char *src, void *dst); const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
Linux Magazine #85 | Dezembro de 2011
65
PROGRAMAÇÃO | Aplicativos web e IPv6
As constantes requeridas AF_ e AI_ também estão disponíveis no módulo socket.
O valor de retorno do socket.getaddrinfo() é uma lista de cinco sets, na seguinte forma:
Figura 1 O Google pode ser encontrado tanto pelo IPv4 como pelo IPv6, tal como mostra este programa exemplo em Python.
Figura 2 O servidor programado em Python responde às conexões telnet em IPv6 e IPv4.
Figura 3 Um pequeno programa em Qt para a linha de comando descobre os endereços IP dos hostnames.
66
(family, socktype, proto, canonname, sockaddr)
Os três primeiros parâmetros podem ser passados para o socket.socket() para criar um objeto socket. O canonname retorna o valor do nome canônico se for requisitado via flags. O último parâmetro, sockaddr, corresponde ao ai_addr, o qual é retornado pelo Python como um set com diferentes tamanhos, dependendo da família de endereços. A primeira entrada neste conjunto é sempre uma string que contém um endereço
Listagem 6: server.py 01 #!/usr/bin/env python 02 import sys 03 from socket import * 04 from select import select 05 06 host = None 07 port = sys.argv[1] 08 flags = AI_PASSIVE 09 10 serverSockets = [] 11 12 for addrinfo in getaddrinfo(host, port, AF_ UNSPEC, SOCK_STREAM, 0, flags): 13 family, socktype, proto, canonname, sockaddr = addrinfo 14 serverSocket = socket(family, socktype, proto) 15 if family==AF_INET6: 16 serverSocket. setsockopt(IPPROTO_IPV6, IPV6_ V6ONLY, 1) 17 serverSocket. bind(sockaddr) 18 serverSocket.listen(1) 19 serverSockets. append(serverSocket) 20 21 22 while True: 23 readable, writable, special = select( serverSockets, [], []) 24 for readSocket in readable: 25 connectionSocket, connectionAddress = readSocket. accept() 26 connectionSocket. send(“Hello {0}\n”. format(connectionAddress). encode(“ascii”)) 27 connectionSocket. close()
www.linuxmagazine.com.br
Aplicativos web e IPv6 | PROGRAMAÇÃO
IP em notação numérica; a segunda é sempre o número da porta. Para o IPv6, há entradas adicionais para flow info e scope id. Em ambos os casos, o ajuste pode ser usado como parâmetro para os métodos socket bind() e connect(). O primeiro programa exemplo é um pequeno script Python (listagem 5) que usa getaddrinfo() para exibir os endereços para um host e tenta conectar-se a cada um destes endereços. Você pode usar getaddrinfo(), por exemplo, para verificar se um determinado servidor web é acessível via IPv6. O código é compatível com ambas as versões do Python: 2.7 e 3.1. O primeiro parâmetro que o script espera é o nome de um host (hostname) que ele passa, sem mudanças, para getaddrinfo() (linha 8). O padrão é 80. O script, então, tenta fazer uma conexão para cada endereço encontrado, criando um objeto socket com family, socktype e com os parâmetros proto que foram retornados. Feito isto, tenta fazer uma conexão connect() em relação a sockaddr (linha 15). Se isso funcionar, será criada uma nota em haveConnection. O Google só fornece endereços IPv6 a certos provedores que tenham passado no teste IPv6. É possível observar isso nesta saída que mostra que cada família de endereços pode conter diversas entradas (figura 1). O nome de host ipv6.google.com sempre retorna um endereço IPv6. Tal como é possível ver do Facebook, você pode adicionar uma mensagem de alerta para um endereço IPv6 de forma criativa: $ python getaddrinfo.py www.facebook.com IPv6 address 2620:0:1c08:4000: face:b00c:0:1,connect = True IPv4 address 69.171.224.41,connect = True
Qual a aparência do lado do servidor? Em uma aplicação servidora capacitada a IPv6, é necessário es-
Linux Magazine #85 | Dezembro de 2011
Listagem 7: connectToHost 01 void connectToHost ( const QString & hostName, quint16 port, OpenMode openMode = ReadWrite )
Listagem 8: simpleClient.cpp 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
#include #include #include #include #include
<QtCore/QCoreApplication> <QtCore/QStringList> <QtNetwork/QHostAddress> <QtNetwork/QTcpSocket> <iostream>
int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QString host = app.arguments().at(1); int port = 80; QTcpSocket socket; socket.connectToHost(host, port); if (!socket.waitForConnected(1000)) { std::cout << “Could not connect” << std::endl; return 10; } QHostAddress peerAddress = socket.peerAddress(); QString address = peerAddress.toString(); std::cout << “Connected to “ << address.toAscii().constData() << std::endl; socket.close(); return 0; }
Listagem 9: greeter.h 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#ifndef GREETER_H #define GREETER_H #include <QtCore/QObject> #include <QtNetwork/QTcpServer> #include <QtNetwork/QTcpSocket> class Greeter : public QObject { Q_OBJECT public: Greeter(QObject *parent) : QObject(parent) {} public slots: void newConnection(QObject* serverObject) { QTcpServer* server = static_cast<QTcpServer*>(serverObject); QTcpSocket* connection = server->nextPendingConnection(); connect(connection, SIGNAL(disconnected()), connection, SLOT(deleteLater())); QHostAddress peerAddress = connection->peerAddress(); QString address = peerAddress.toString(); connection->write(“Hello “); connection->write(address.toAscii()); connection->write(“\n”); connection->disconnectFromHost(); } }; #endif
67
PROGRAMAÇÃO | Aplicativos web e IPv6
Quadro 1: Detalhes dos AI_FLAGS AI_ADDRCONFIG: Se o programador fornecer apenas as especificações deste sinal (flag), os endereços só serão retornados se alguma interface de rede tiver configurado pelo menos um endereço não-loopback de tipo correspondente. Isso significa que um dispositivo sem conexão IPv6 só receberá endereços IPv4 e vice-versa. Infelizmente, os desenvolvedores das atuais bibliotecas Glibc [10] e Eglibc [11] tomaram a decisão questionável de aceitar endereços para links locais IPv6 como configuráveis. Isso quer dizer que o getaddrinfo() apresenta endereços IPv6 inalcançáveis para os computadores que não tenham endereços IPv6 globais. Em tais ambientes as conexões normalmente falham logo, mas grandes timeouts ocorrem em alguns casos, e é justamente para evitá-lo que esta opção foi projetada. Fora isso, é aconselhável usar essa opção no lado do cliente para evitar tentativas de conexão e consultas DNS propensas a erros. AI_PASSIVE: Retorna sockets apropriados às chamadas de sistema bind() e accept(). AI_V4MAPPED: Retorna endereços IPv4 identificados por sockets AF_ INET6, para os quais nenhum endereço IPv6 pôde ser verificado como endereço IPv6 do tipo mapeado em IPv4. AI_ALL: Retorna todos os endereços IPv6 e IPv4 mapeados (apenas se for combinado com o AI_V4MAPPED). AI_CANONNAME: Resolve um hostname canônico e o retorna dentro de uma lista res como primeiro item. AI_NUMERICHOST: Evita consultas ao DNS. O node precisa ser especificado em notação numérica.
pecificar None como host, AF_UNSPEC como a família e AI_PASSIVE para os flags receberem os parâmetros e os endereços para sockets servidores que escutam as conexões em todas as interfaces de rede. Isso significa pelo menos dois sockets. A primeira questão é quando um socket IPv4 ou IPv6 darão bind para a mesma porta, ao mesmo tempo. E a resposta é: depende da opção de socket IPV6_V6ONLY, já descrita no RFC3493. No Python, você pode ajustar esse detalhe ao usar o método socket sockopt(). socket.setsockopt (IPPROTO_IPV6, IPV6_V6ONLY, 1)
Infelizmente, a configuração padrão para essa opção depende do sistema operacional e até mesmo da distribuição. Alguns sistemas BSD a ativam por padrão e, no Linux, o administrador pode ativá-la durante a execução do sistema: sysctl net.ipv6.bindv6only=1
68
É aconselhável que os programadores ajustem essa opção explicitamente e, neste caso, devem estar sempre prontos para ligar uma porta IPv6 mesmo que esta já esteja vinculada ao IPv4. Caso o IPV6_V6ONLY esteja desabilitado, as novas mensagens IPv4 são redirecionadas a um socket IPv6 por um socket V4-mapped. As especificações IPv6 incluem uma técnica para mapeamento de endereços IPv4 para endereços IPv6 [3]. Apesar de os endereços IPv4 mapeados serem práticos, também possuem desvantagens. Uma delas é não ter representação textual, o que leva a strings modificadas, mais especificamente em saídas de log. Isso pode causar problemas para ferramentas de análise que usam, digamos, expressões regulares para buscar endereços IPv4 e não conseguem identificar novas strings. Por outro lado, uma série de problemas de segurança potenciais estão relacionados aos endereços mapeados em IPv4 [4]: o aplicativo não
consegue distinguir se uma conexão IPv4 existe ou se está lidando com uma conexão IPv6 com um endereço manipulado. O segundo problema com os dois server sockets é que a chamada accept() normalmente fica bloqueada enquanto espera por uma conexão. Para contornar esse problema, os desenvolvedores poderiam, teoricamente, ativar dois processadores no servidor ou trabalhar com várias threads. Contudo, isso não é necessário porque o select oferece uma solução bem mais elegante para o problema ao permitir que o programa espere por diversos sockets ao mesmo tempo. Essa abordagem pode parecer um pouco intrincada, mas os aplicativos mais complexos não conseguirão resolver o problema sem usar o select ou alternativas como poll ou epoll. Em Python, você vai encontrar a função select() no módulo padrão Select [5]. readable, writable, special = select.select(rlist, wlist, xlist[, timeout])
Os parâmetros rlist, wlist e xlist são listas de arquivos ou objetos socket que reagem a leitura, escrita e eventos incomuns. Os três valores de retorno dados ao programa são listas de objetos que chegaram a um estado de espera. O valor para novas conexões é readable. Em Python, o accept() é suprido como método de objeto socket que retorna um 2-tuple, (conn, address) = socket.accept()
em que conn é o novo socket na conexão estabelecida e address é o endereço da outra parte da notação tuple do Python. O próximo exemplo de código (listagem 6) usa uma dessas técnicas IPv6 do Python na prática. O código encarregado de “escutar” ouve a porta, aceita as conexões que estão
www.linuxmagazine.com.br
Aplicativos web e IPv6 | PROGRAMAÇÃO
chegando e transfere seu endereço IP. A figura 2 mostra uma sessão Telnet em que o servidor usa IPv6 e Ipv4.
Kit de ferramentas Qt O framework QT orientado a objetos C++ fornece diversas abstrações para programação voltada para redes dentro da biblioteca QtNetwork [6]. Em circunstâncias normais, os programas cliente que usam os métodos corretos serão conectados automaticamente via IPv6. O Qt oferece as classes QTcpSocket e QudpSocket para programação de re-
des. Ambas são derivadas da classe básica QAbstract-Socket. Para estabelecer uma conexão TCP em um programa cliente, o desenvolvedor precisa primeiro criar uma QTcpSocket e, então, chamar o método QAbstractSocket, definido na classe base connectToHost() (listagem 7). Como exemplo, considere um programa mínimo de Qt (listagem 8) que tenta abrir uma conexão para um servidor web usando o nome passado pelo usuário como primeiro parâmetro na linha de comando (figura 3).
Quadro 2: IPv6 na programação Perl Se você deseja escrever programas voltados para o IPv6 em Perl, sua única opção é o módulo CPAN Socket6, que oferece funções como getaddrinfo(). O Perl 5.14 (maio de 2011) foi a primeira versão a implementar a funcionalidade no módulo do Socket [12] no núcleo da linguagem. A listagem 11 mostra uma exemplo de aplicativo nesse sentido. A programação de Socket é mais conveniente com o IO::Socket [13]. O IO::Socket::INET, necessário para o IPv4, já faz parte do núcleo do Perl há muitos anos. O IO::Socket::INET6 do CPAN fornece um duplo módulo para o IPv6. use IO::Socket::INET6; my $sock6 = IO::Socket::INET6->new( '[::1]:12345' ); my $sock4 = IO::Socket::INET6->new( '127.0.0.1:12345' ); O módulo Socket6 é compatível retroativamente com o IO:Socket::INET e também pode criar conexões IPv4. O Socket6 aceita endereços como nomes de host na notação IPv4 ou IPv6 porque o IO::Socket::INET suporta programação mais simplificada e sockets no estilo Libc. Muitos programas e módulos Perl o usam, com o sacrifício de suas capacidades IPv6 (por exemplo, módulos do núcleo, tais como o Net::SMTP, Net::FTP e módulos importantes do CPAN, tais como LWP). Em muitos casos, é possível readequar programas ao IPv6 com a ajuda do Net::INET6Glue::INET_is_INET6 [14], que substitui o IO::Socket::INET por IO::Socket::INET6: use Net::INET6Glue::INET_is_INET6; use LWP::Simple; print get('http://ipv6.google.com/'); A seguinte linha de comando habilita ao IPv6 um programa já existente: $ perl -Mnet::INET6Glue::INET_is_INET6 ipv4_programm.pl Net::INET6Glue::FTP ainda estende o Net::FTP, adicionando os comandos essenciais EPRT e EPSV para IPv6. O IO::Socket::SSL fornece suporte simples ao SSL e, automaticamente, ao IPv6, desde que o IO::Socket::INET6 esteja instalado. Além disso, o Perl oferece diversas bibliotecas para manipulação não-bloqueável de sockets. Em muitos casos, essas soluções já suportam o IPv6, mas não usam o bloqueável getaddrinfo() para consultas de endereços, preferindo os seus próprios. Os exemplos incluem AnyEvent e POE. Contudo, o gerenciador deverá retornar os resultados em ordem diferente da que você poderia esperar com o getaddrinfo().
Linux Magazine #85 | Dezembro de 2011
O QHostAddress [7] é usado para saída: essa é a abstração Qt para endereços IPv4 e Ipv6. Entre outras coisas, ela fornece o método QHostAddress::toString(). A aplicação QCoreApplication dá aos desenvolvedores a opção de criar programas Qt sem uma GUI (listagem 8, linha 10). Após connectToHost() (linha 16), que imediatamente retorna as chamadas de código de waitForConnected() para esperar por uma conexão (linha 18). Uma outra alternativa é atribuir o sinal connected() a um slot apropriado. Uma vez estabelecida a conexão, o programa exibe o peerAddress. Em um ambiente com suporte a IPv6, é possível ver que o programa estabelece automaticamente a conexão IPv6. $ ./simpleClient www.google.com Connected to 2A00:1450:4001:C01:0:0:0:68%0
Isso é prático, mas não lhe dá a possibilidade de intervenção que o getaddrinfo() dá aos programadores C. A função que chega mais perto de fazê-lo é QHostInfo [8], que oferece métodos para resolução de nomes. Infelizmente, QHostInfo não oferece toda a conveniência que getaddrinfo dá. Por exemplo, é impossível especificar quando você quer endereços IPv4 ou IPv6 e o desenvolvedor não pode especificar flags, tais como AI_ADDRCONFIG. A implementação é simples: o método estático, QHostInfo::fromName(const QString& name) retorna uma instância QHostInfo , que usa QHostInfo::addresses() para retornar uma QList de instâncias QHostaddress. Uma variante do nome lookupHost() trabalha em outra direção, usando threads separadas para lidar com requisições feitas, as quais são chamadas dentro do slot especificado do objeto. As aplicações de servidor não são automaticamente compatíveis com o
69
PROGRAMAÇÃO | Aplicativos web e IPv6
IPv6 no Qt. O QTcpServer que usa abstração para o socket servidor apenas escuta um endereço. Infelizmente,
o argumento padrão é um endereço IPv4 QHostAddress::Any dentro do método listen().
Listagem 10: server.cpp 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
70
#include #include #include #include #include #include #include #include
<QtCore/QCoreApplication> <QtCore/QSignalMapper> <QtCore/QStringList> <QtNetwork/QNetworkInterface> <QtNetwork/QHostAddress> <QtNetwork/QTcpServer> <iostream> “greeter.h”
int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); int port = app.arguments().at(1).toInt(); Greeter* greeter = new Greeter(&app); QSignalMapper* sigMap; sigMap = new QSignalMapper(&app); greeter->connect(sigMap, SIGNAL(mapped(QObject *)), SLOT(newConnection(QObject *))); QList<QTcpServer> servers; QList<QNetworkInterface> ifs; ifs = QNetworkInterface::allInterfaces(); foreach(const QNetworkInterface& i, ifs) { QList<QNetworkAddressEntry> entries; entries = i.addressEntries(); foreach(const QNetworkAddressEntry& entry, entries) { QHostAddress address = entry.ip(); // fix scope of link-local addresses Q_IPV6ADDR addr6;// = address.toIPv6Address(); addr6 = address.toIPv6Address(); if (addr6[0] == 0xfe && addr6[1] == 0x80) { QString name=i.humanReadableName(); address.setScopeId(name); } QTcpServer* server; server = new QTcpServer(&app); sigMap->setMapping(server, server); sigMap->connect(server, SIGNAL(newConnection()), SLOT(map())); server->listen(address, port); if (!server->isListening()) { std::cout << “Cannot listen on “ << address.toString().toAscii().constData() << std::endl; } } } return app.exec(); }
Para contornar essa situação, os desenvolvedores podem especificar o QHostAdress::AnyIPv6 IPv6 para o método listen(). Essa solução vai funcionar em qualquer plataforma e distribuição onde a opção padrão do socket IPV6_V6ONLY for 0. O programa resultante recebe conexões IPv4 via endereços mapeados em IPv4. No entanto, não há uma maneira simples de dizer ao QTcpServer para usar a opção socket IPV6_V6ONLY. Uma solução é injetar um descritor socket criado em C através do QTcpServer::setS ocketDescriptor. Os programadores encontrarão uma solução alternativa ao mergulhar na biblioteca QtNetwork. Se você o fizer, encontrará a classe QNetworkInterface , que enumera todos os dispositivos da rede. Essa classe cria uma lista de instâncias QNetworkAddressEntry para cada dispositivo e cada um tem um QHostAdress. Assim é possível descobrir todos os endereços IPv4 e IPv6 existentes no sistema. O desenvolvedor tem, primeiro, a opção de abrir uma porta no servidor para certas placas de rede
Listagem 11: Socket Perl 01 #!/usr/bin/perl 02 03 use Socket6; # ab 5.14 reicht ‘use Socket’ 04 my @res = getaddrinfo(‘ipv6. google.com’,’http’,AF_ UNSPEC,SOCK_STREAM ); 05 my $sock; 06 while (! $sock and @res) { 07 my ($fam,$type,$proto,$s addr,$cname) = splice(@ res,0,5); 08 socket($sock,$fam,$type,$proto) or die $!; 09 connect($sock,$saddr) and last; 10 undef $sock; 11 } 12 $sock or die $!;
www.linuxmagazine.com.br
Aplicativos web e IPv6 | PROGRAMAÇÃO
apenas. O código para servidores QT (listagens 9 e 10) interage com todos os dispositivos e endereços da rede (linha 29 na listagem 10). Você pode simplesmente usar QN etworkInterface::allAddresses() [9] para isso, mas infelizmente
ele vai retornar 40 endereços locais de links. Para cada endereço de rede, o programa cria um novo QTcpServer (linha 46, listagem 10) e o conecta usando um QSignalMapper, o que é necessário porque o QTcpServer apenas envia um sinal newConnection() vazio que não informa ao receptor qual dos muitos remetentes tem uma nova conexão. O QSignalMapper avalia um sinal com a informação do seu remetente, de forma que o programa possa dizer ao visitante qual IP eles estão usando.
Conclusão Se você sabe o que está procurando, não será difícil fazer um programa compatível com o IPv6. Ainda que os programas clientes sejam razoavelmente simples, os programas servidores têm maior complexidade caso o desenvolvedor deseje abordar quaisquer eventualidades. Os frameworks com alto nível de abstração podem virar um problema caso não tenham funcionalidade crítica em sua camada de abstração, tal como IPV6_V6ONLY dentro do kit de ferramentas QT. ■
Gostou do artigo? rtigo? Queremos ouvir sua opinião. pinião. Fale conosco em m cartas@linuxmagazine.com.br zine.com r Este artigo no nosso osso site: e: http://lnm.com.br/article/6106 br/art /610
Mais informações [1] RFC 3493: http://tools.ietf.org/html/rfc3493 [2] getaddrinfo() em Python: http://docs.python.org / library/socket.html#socket.getaddrinfo [3] Endereços IPv4-Mapped IPv5: http://www.tcpipguide. com/free/t_IPv6IPv4AddressEmbedding-2.htm [4] Aspectos da segurança com endereços V4MAPPED: http:// tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02 [5] select() em Python: http://docs.python.org/ library/select.html#select.select [6] Biblioteca QtNetwork: http://doc.qt.nokia. com/4.6/network-programming.html [7] QHostAddress: http://doc.qt.nokia.com/4.6/qhostaddress.html [8] HostInfo: http://doc.qt.nokia.com/4.6/qhostinfo.html [9] QNetworkInterface: http://doc.qt.nokia. com/4.6/qnetworkinterface.html [10] Glibc bug: http://sourceware.org/bugzilla/show_bug.cgi?id=12377 [11] Bug em Ubuntu Eglibc: https://bugs.launchpad. net/ubuntu/+source/eglibc/+bug/762512 [12] Módulo Perl socket: http://perldoc.perl.org/Socket.html [13] IO::Socket::INET: http:// perldoc.perl.org/IO/Socket/INET.html [14] Net::INET6Glue : http://search.cpan.org/~sullr/Net-INET6Glue-0.5/ [15] Listagens do artigo, incluindo os arquivos para o Qmake: [LINK LINK LINK LINK LINK LINK LINK]
Linux Magazine #85 | Dezembro de 2011
71
TUTORIAL
TUTORIAL | Conversão de PDF
Conversão para PDF baseada em email
Conversão de PDF Envie alguns arquivos por email e receba documentos PDF como resposta, usando para isso LibreOffice, Postfix e scripts Shell. por Olaf Hübner
M
uitos programas Linux criam documentos PDF a partir de diversos formatos. Mas, e se sua equipe precisar converter diversos documentos para PDF de uma vez só? O método precisaria ser econômico, simples, rápido e possuir uma interface gráfica que não ofereça muita dificuldade ao usuário. Uma pesquisa inicial revela diversas soluções em potencial, mas converter vários documentos ao mesmo tempo sempre envolve uma boa dose de entrada de dados por parte do usuário, e o uso de impressoras de PDF virtuais é muito lento quando você tem muitos arquivos. As equipes de escritório têm familiaridade com email, algo que usam todos os dias para diversas funções. Essa ideia básica está por trás do projeto que uma empresa de Berlim, na Alemanha, implementou para combinar um servidor de email com o Open/ LibreOffice, criando para isso uma solução interna. O usuário só precisa enviar os arquivos que quer converter como anexos para o servidor, e receberá de volta o resultado – documentos PDF – no email de resposta.
72
Sequência prática É necessário um endereço de email separado para receber as tarefas de conversão. Neste exemplo, usarei pdf@dominio.tld. No lado em que ocorre a conversão, você precisa do Postfix. A seguinte linha no arquivo /etc/aliases pede para o servidor de email repassar a mensagem para o script de conversão: pdf: "|/usr/local/bin/ pdf-konverter.sh"
O comando postalias /etc/aliases compila a configuração para o Postfix. O script pdf-konverter.sh primeiro desempacota os anexos;
Listagem 1: /etc/postfix/main.cf 01 myhostname = pdfserver.dominio.tld 02 mydomain = dominio.tld 03 mydestination = $mydomain 04 myorigin = $mydomain 05 alias_maps = hash:/etc/aliases 06 alias_database = hash:/etc/aliases 07 # optional smarthost 08 # relayhost = mail.domain.tld 09 mynetworks = 127.0.0.0/8 10 message_size_limit = 51200000
depois, os repassa para o Unoconv [1], um utilitário para comunicação com o Open/LibreOffice. Esse conjunto de aplicativos para escritório cuida do processo de conversão antes de o script finalmente empacotar
Listagem 2: /etc/init.d/ unoconvd 01 02 03 04 05 06 07 08
#!/bin/sh ### BEGIN INIT INFO # Provides: unoconvd # Required-Start: $network # Required-Stop: $network # Default-Start: 2 3 5 # Default-Stop: # Description: unoconvd - Convert to PDF 09 ### END INIT INFO 10 case "$1" in 11 start) 12 /usr/bin/unoconv --listener & 13 ;; 14 stop) 15 killall soffice.bin 16 ;; 17 restart) 18 killall soffice.bin 19 sleep 1 20 /usr/bin/unoconv --listener & 21 ;; 22 esac
www.linuxmagazine.com.br
Conversão de PDF | TUTORIAL
os arquivos de volta, sob a forma de anexos, e os devolve ao remetente. O tamanho máximo de um email é definido pelo parâmetro message_size_limit na configuração do Postfix (listagem 1). Como o LibreOffice é executado como daemon, o processo de conversão em si é muito rápido: um email de 20 MB com 19 anexos consome apenas um minuto na conversão e retorno – e o email de teste ainda passou por um scanner antivírus tanto na ida quanto na volta. No caso de um único arquivo, os usuários o recebem de volta em apenas alguns segundos.
Requerimentos do sistema A equipe em Berlim usou a versão 64-bit do Debian Squeeze, mas tudo pode ser feito da mesma maneira com o Ubuntu 10.10. Como o aplicativo só depende de componentes de código aberto, deve funcionar em outras distribuições também. Além do Postfix como servidor de email, também serão necessários empacotadores e desempacotadores para os anexos. O ripMIME é a escolha certa para desempacotar os anexos: ele pega os anexos codificados como MIME de um email e os grava como arquivos individuais no diretório selecionado. Uma ferramenta alternativa para isso é o Uudeview [2]. O ripMIME atuou como um desempacotador bem ágil em nosso laboratório. O programa está atualmente disponível apenas em código-fonte [3]; você pode compilá-lo com make && make install. O comando chown nobody:nogroup /usr/local/bin/ripmime
define as permissões corretas para o binário. Para o empacotamento, o programa uuenconde está prontamente disponível no pacote debian sharutils. Ele codifica os arquivos convertidos no email de resposta.
Linux Magazine #85 | Dezembro de 2011
Listagem 3: pdf-konverter.sh (trecho) 01 02 03 04 05
#!/bin/sh [...] # extrai os anexos como arquivos individuais /usr/local/bin/ripmime -i $PDFMAIL -d $PDF_PATH --overwrite --syslog --extended-errors
06 07 # lista arquivos compatíveis 08 /bin/ls $PDF_PATH/*.* \ 09 | /bin/egrep -i '\.(do[ct]|doc[mx]|rtf|pp[ts]|xl[st]|csv|od[stdgp]|ott| htm|sd[wcda]|sxc|jpg|pts|bmp|png|tif|gif)$’ \ 10 > $PDF_PATH/files_to_convert.txt 11 12 # cria cabeçalho e corpo do email 13 echo "From: $PDF_FROM" >$EMAIL_RETURN 14 echo "To: $SENDER" >>$EMAIL_RETURN 15 echo "Subject: $SUBJECT" >>$EMAIL_RETURN 16 echo "MIME-Version: 1.0" >>$EMAIL_RETURN 17 echo "Content-Type: multipart/mixed; boundary=\$BOUNDARY"\ >>$EMAIL_RETURN 18 echo "--$BOUNDARY" >>$EMAIL_RETURN 19 echo "Content-Type: text/plain; charset=\"$CHARSET\"; format=flowed" >>$EMAIL_RETURN 20 echo "Content-Transfer-Encoding: quoted-printable" >>$EMAIL_RETURN 21 /bin/cat $PDF_PATH/body_return.txt >>$EMAIL_RETURN 22 23 # processamento linha a linha da lista de arquivos 24 while read FILE_NAME 25 do 26 /usr/bin/unoconv -f pdf "${FILE_NAME}" 27 done < $PDF_PATH/files_to_convert.txt 28 29 # codifica nomes de arquivos como ISO-8859-15, remove caracteres 30 # especiais e codifica os arquivos PDF como base64 31 for ATTACHMENT in $PDF_PATH/*.pdf 32 do 33 FILENAME=$(basename "${ATTACHMENT}") 34 (echo "${ATTACHMENT}" ; echo $FILENAME) >> $PDF_PATH/pdf_filenames_and_basenames.txt 35 ( echo -n "\"=?$CHARSET?Q?" ; \ 36 echo -n $FILENAME | /usr/bin/perl -pe ‘ use MIME::QuotedPrint; $_=MIME::QuotedPrint::encode($_);’ \ 37 | /bin/sed ‘s/\./=2E/g’ /bin/sed ‘s/ /=20/g’ /bin/sed ‘s/=$//g’; \ 38 echo "?="\" \ 39 ) | tr -d ‘\n’ >$PDF_PATH/filenames_codiert.txt 40 FILENAME_CODIERT=$(/bin/cat $PDF_PATH/filenames_codiert.txt ) 41 echo "--$BOUNDARY" >>$EMAIL_RETURN 42 echo "Content-Type: application/pdf;" >>$EMAIL_RETURN 43 echo " name=$FILENAME_CODIERT" >>$EMAIL_RETURN 44 echo "Content-Transfer-Encoding: base64" >>$EMAIL_RETURN 45 echo "Content-Disposition: attachment;" >>$EMAIL_RETURN 46 echo " filename=$FILENAME_CODIERT" >>$EMAIL_RETURN 47 echo "" >>$EMAIL_RETURN 48 # strip first and last line 49 /bin/cat "${ATTACHMENT}" uuencode --base64 $BOUNDARY /bin/sed ‘1,1d’ /bin/sed ‘$d’ >>$EMAIL_RETURN 50 done 51 # fim da mensagem de email 52 echo "--$BOUNDARY--" >>$EMAIL_RETURN 53 54 # envia email 55 /bin/cat $EMAIL_RETURN | /usr/sbin/sendmail -t -f pdf@dominio.tld 55 exit 0
73
TUTORIAL | Conversão de PDF
Servidor Office A ferramenta de linha de comando unoconv será realmente necessária para executar o Open/LibreOffice em modo servidor. Ela usa as ligações de dados UNO para ler os formatos compatíveis e salvá-los no formato escolhido. O site do Unoconv [1] exibe uma lista impressionante de formatos compatíveis para importação e exportação. Para iniciar o LibreOffice como um daemon, use o comando: unoconv --listener
que, por padrão, escuta a porta TCP 2002, embora seja possível mudar isso com a opção --port. Outras grandes vantagens do modo --listener são: a velocidade com que os documentos são convertidos e a sintaxe simples. Mais informações sobre como usar o LibreOffice em modo daemon e sobre a API estão nas páginas de ajuda do LibreOffice [4] e no wiki do OpenOffice [5].
Há, contudo, um senão: se você tiver uma instalação padrão do Debian Squeeze e iniciar o Unoconv no modo --listener, verá uma mensagem de erro sobre a ligação UNO do Python. Para contornar isso, instale o pacote LibreOffice a partir dos backports ao invés do OpenOffice. Como o Unoconv trabalha em cooperação íntima com a versão do Office, você precisa do pacote Debian na versão unstable [6]. Como root, digite os seguintes comandos para criar um script de inicialização para controlar o servidor do LibreOffice e preencha-o com o conteúdo da listagem 2: touch /etc/init.d/unoconvd chmod 755 /etc/init.d/unoconvd
Depois, a ferramenta insserv garante que o serviço será iniciado no nível de execução padrão: insserv -d unoconvd
Se não tiver o insserv, você pode configurar o serviço com update-rc.d
Mais informações: [1] Unoconv: http://dag.wieers.com/home-made/unoconv [2] Uudeview: http://www.fpx.de/fp/Software/UUDeview [3] ripMIME: http://www.pldaniels.com/ripmime/ripmime-1.4.0.9.tar.gz [4] Parâmetros para iniciar o LibreOffice: http://help.libreoffice. org/Common/Starting_the_Software_With_Parameters [5] Exportar para PDF no OpenOffice: http://wiki. services.openoffice.org/wiki/Documentation/OOo3_ User_Guides/Getting_Started/Exporting_to_PDF [6] unoconv-unstable: http://packages.debian. org/sid/all/unoconv/download [7] Antiword: http://freshmeat.net/projects/antiword [8] Pandoc: http://johnmacfarlane.net/pandoc
ou chkconfig, ou então configurá-lo manualmente. Após iniciar o daemon – tanto ao usar a versão RC ou se o fizer manualmente, por exemplo, com o comando /etc/init.d/unoconv start – você passará a ver o unoconv e o soffice.bin na lista de processos. O script que recebe o email, converte-o e o devolve ao remetente está localizado em /usr/local/bin/ pdf-konverter.sh. Sua propriedade deve ser nobody:nogroup. A listagem 3 mostra parte de seu conteúdo. Se não estiver satisfeito com o Unoconv e o Open/LibreOffice, você pode mudar as linhas no script de conversão para uma das muitas alternativas: Antiword [7] (que primeiro converte para Postscript e depois, com o ps2pdf, para PDF), Pandoc [8], JOD, PyODConverter [9] e LOPDFConverter [10] são as opções disponíveis.
Futuro Essa solução basicamente irá permitir que você execute um servidor de conversão PDF bastante ágil. Como a versão 0.4 (ou superior) do Unoconv oferece filtros especiais para exportação, você pode acrescentar outra conta de email a o arquivo /etc/aliases e escrever um segundo script (ou uma seção interna para avaliação de parâmetros) para poder escolher os formatos de exportação [11]. Antes de implementar o conversor PDF em um ambiente de produção, fique atento a algumas recomendações de segurança: executar o Unoconv como um usuário definido, criar cronjobs para apagar diretórios temporários, criar arquivos de log e blindar o Postfix. ■
[9] JOD e PyODConverter: http://artofsolving.com/opensource
74
[10] LOPDFConverter: http://sourceforge.net/projects/lopdfconverter
Gostou do artigo? go?
[11] API OpenOffice API para exportação PDF: http://wiki. services.openoffice.org/wiki/API/Tutorials/PDF_export
Queremos ouvir sua opinião. pinião. Fale conosco em cartas@linuxmagazine.com.br e.com.b
[12] Listagens deste artigo: http://www.lnm. com.br/issues/85/mail2pdf.zip
Este artigo no nosso so site: sit http://lnm.com.br/article/6092 articl 092
www.linuxmagazine.com.br
Sandbox simples com o Arkose | TUTORIAL
Sandbox simples com o Arkose
TUTORIAL
Caixa de areia O Arkose permite confinar programas potencialmente instáveis em uma sandbox virtual, mantendo seu sistema protegido contra acidentes e perda de dados. por Thomas Drilling
U
ma criança pode brincar em segurança dentro de uma caixa de areia, sem o perigo de destruir objetos de valor. Este mesmo princípio, que funciona bem no mundo físico, pode ser aplicado ao ambiente virtual. Uma caixa de areia digital tem um propósito mais restritivo, mas a ideia é a mesma: criar um ambiente para programas no qual eles possam ser executados sem causar danos ao sistema como um todo. Neste contexto, “dano” refere-se a aspectos relacionados tanto ao código do software quanto ao ambiente operacional. O Arkose [1], desenvolvido por Stéphane Graber, é uma ferramenta de contêiner que mantém o mesmo conceito tecnológico do LXC (Linux Container) [2]. Ele foi incorporado ao kernel na versão 2.6.29 e é baseado nos namespaces (espaços de nomes) do kernel [3] (para isolar processos) e Cgroups [4] (para restringir recursos), o que o torna equivalente a um aplicativo ou a um contêiner de sistema. De acordo com o website no Launchpad, “o Arkose é um aplicativo de contêiner seguro e amigável ao usuário [...] Basicamente ele permite iniciar qualquer binário instalado dentro de um contêiner configurável. É possível definir quanto espaço em disco ele ocupará, se terá acesso à rede e se deve ter acesso ao seu diretório /home.”
Linux Magazine #85 | Dezembro de 2011
Este software foi projetado para ser simples e não oferece a mesma gama de recursos incluídos em outros programas como ferramentas de contêiner mais sofisticadas. Contudo, é rápido e fácil. É possível iniciar um aplicativo dentro de um contêiner seguro com um único comando, ou mesmo de dentro do gestor de arquivos Nautilus (figura 1). Tal como você verá neste artigo, o Arkose usa o sistema de arquivos de camadas Aufs para simular o acesso ao sistema de arquivos local, o que significa que o aplicativo que está sendo executado dentro de um contêiner não sabe que está dentro dele ou em uma área local restrita. O Arkose é prático como ferramenta de segurança e desenvolvimento. Seu ambiente fácil e ágil permite montar e testar aplicativos de modo a não danificar o seu sistema.
Como funciona o Arkose? O recurso Cgroups está disponível no kernel Linux desde a versão 2.6.24. Ele permite ao kernel agrupar processos e executá-los dentro de um outro processo específico ou usá-lo como uma unidade dentro de um planejamento. Em um sistema Linux, essa técnica oferece a possibilidade de selecionar um grupo de processos e determinar os recursos que cada um
irá usar, enquanto o kernel cuida da questão das hierarquias. O controlador de recursos de memória do kernel isola esses grupos do restante do sistema e restringe o apetite de programas insaciáveis por memória. Caso os Cgroups estejam habilitados no kernel, este os utilizará para gerenciar todos os recursos – sejam eles processos do espaço do usuário, seus próprios processos ou processos do kernel. O Aufs [5], um novo derivado do UnionFS, exibe mudanças no sistema de arquivos dentro do contêiner. Trata-se de um sistema de arquivos em camadas usado para simular escrita em mídias não-graváveis. Assim, o Arkose dá a cada usuário Linux uma solução simples para colocar programas dentro de uma área restrita.
Instalação Usar o Arkose é muito fácil no “Natty Narwhal”. O Ubuntu 11.04 é a primeira distribuição a vir com esse programa em seu repositório e a incluir uma interface gráfica integrada ao Nautilus. Para instalá-lo, simplesmente selecione os pacotes arkose, arkose-gui (interface gráfica) e arkose-nautilus (integração ao Nautilus) no gerenciador de pacotes. É necessário preencher os seguintes pré-requisitos: a versão 1.3 precisa, no mínimo, do kernel 2.6.36, com suporte a Aufs2 habilitado – padrão no Ubuntu 11.04. É necessário, ainda, ter o LXC,
75
TUTORIAL | Sandbox simples com o Arkose
Figura 1 A integração com o Nautilus permite aos usuários executar qualquer aplicativo dentro de uma área local restrita.
o Python, o Gtk e um emulador de terminal X (todos eles fazem parte da configuração padrão do Ubuntu). Infelizmente, por enquanto, o repositório do Ubuntu 11.04 dispõe apenas da versão 0.3.2. Se você quiser trabalhar com o Arkose, provavelmente vai preferir instalar a atual versão de desenvolvimento 1.3.2. No Ubuntu 11.04 isso é relativamente indolor e é possível fazê-lo ao habilitar o repositório PPA ppa:arkose-devel/stable, onde será possível encontrar também a versão 1.3.2 para o Ubuntu 10.10. Como alternativa, você pode fazer o download da versão 1.3.1 diretamente do Launchpad [6]. Depois de instalado, a interface gráfica (arkose-gui) estará disponível em seu sistema no menu Aplicativos/Ferramentas de sistema/Arkose Desktop Application Sandboxing. É mais fácil iniciar um programa dentro de um contêiner ao selecionar Abrir em uma sandbox no Nautilus – será preciso ter instalado o pacote arkose-nautilus para que esta opção esteja disponível (figura 1).
Configuração O Arkose exibe uma caixa de diálogo com o caminho para o programa ou binário selecionado. Ao clicar em Exibir as opções da área local uma série de novas opções é mostrada (figura 2).
76
Figura 2 O Arkose oferece uma quantidade mínima de opções para configurar a área local.
A opção tamanho do recipiente (Container) permite definir o tamanho máximo do contêiner, o que limita o espaço de trabalho do programa dentro da RAM e suas tentativas de iniciar novas instâncias, criar documentos e arquivos temporários. Se desejar manter as opções selecionadas como padrão para as próximas vezes em que o executar, selecione um das opções Diretório/home real (em vez de copiar-na-escrita) ou Diretório/ tmp real (em vez de copiar-na-escrita). O suporte à rede é autoexplicativo: dá ao programa dentro do contêiner acesso à rede do sistema. A versão 1.3 acrescentou a opção Tipo de armazenamento com dois botões: ext4 (disco) e tmpfs (memória). A segunda faz com que as mudanças permaneçam visíveis ao programa na RAM em vez de escrevê-las no ~/.arkose/. Você também pode iniciar o Arkose pela linha de comando, com sudo arkose. Use man arkose para listar as opções para sua execução, que são as mesmas da caixa de diálogo da interface gráfica.
Arkose 1.3 Um programa controlado pelo Arkose é executado praticamente isolado do resto do sistema, de modo que não tem a possibilidade de acessar
serviços do sistema hospedeiro, tais como o D-Bus. O fato é que, através do Arkose 0.3.2, um programa sequer tem acesso ao PulseAudio. Esta última restrição caiu na versão 1.3, que introduz uma série de mudanças decisivas. Por exemplo, os programas agora podem enviar sons ao PulseAudio e usar dispositivos de vídeo, como a webcam. Além disso, o Arkose tem seu próprio servidor X. Por último, mas não menos importante, sua nova versão permite comunicação via D-Bus.
Conclusão O Linux, particularmente, tem várias boas opções de métodos para colocar aplicativos potencialmente instáveis dentro de áreas restritas. As opções variam entre um simples redirecionamento do diretório raiz até uma virtualização completa do sistema operacional dentro de contêineres. Se tudo o que você quer é isolar programas individualmente, não é necessário instalar programas mais poderosos. Você pode confiar no Arkose, que lhe permite usar as complexas tecnologias de contêiner do Linux com os recursos de um usuário padrão. ■
www.linuxmagazine.com.br
Sandbox simples com o Arkose | TUTORIAL
Quadro 1: Ferramentas de área restrita/local O Linux tem uma gama de tecnologias de sandboxing (restrição de área para programas) a começar pela possibilidade de redirecionar um sistema de arquivos com o chroot, passando pela virtualização de um ambiente ou sistema operacional (OpenVZ, Linux-VServer), indo até a possibilidade de emular todo o hardware hospedeiro. Todas essas tecnologias que suprem um contexto virtual para um programa ou restringem seus direitos de acesso para evitar que cause danos ao sistema hospedeiro podem, por princípio, ser consideradas ferramentas de contenção ou restrição de área. Essas soluções incluem contêineres de recursos tais como OpenVZ, Linux-VServer, Solaris Zones, Parallels Virtuozzo, User-mode Linux (UML) ou LXC (Linux Containers) . Programas como o KVM/Qemu, Bochs, FAUmachine ou Xen e VMware também dão suporte ao sandboxing. O desenvolvedor do Fedora, Daniel Walsh, tem planejado uma área local baseada no SELinux já há algum tempo.
Mais informações: [1] Arkose: http://www.stgraber. org/category/arkose [2] Contêineres Linux (LXC): http://lxc.sourceforge.net [3] Espaços de nomes no kernel: http://lcx.sourceforge. net/index.php/about/ kernel-namespaces [4] Cgroups: http://www. mjmwired.net/kernel/ Documentation/cgroups [5] Aufs: http://aufs. sourceforge.net [6] Arkose no Launchpad: https://launchpad.net/ arkose/trunk/1.3
Gostou do artigo? go? Queremos ouvir sua a opinião. op ão. Fale conosco em cartas@linuxmagazine.com.br .com.b Este artigo no nosso so site: sit http://lnm.com.br/article/6089 articl 089
Linux Magazine #85 | Dezembro de 2011
77
PREVIEW
Linux Magazine #86 Guerra No amor e na guerra, vale tudo, já dizia o ditado. E na guerra contra os crackers é preciso se armar com o que há de mais moderno no ramo da segurança. Nesta edição você poderá conhecer quais as ferramentas e técnicas que os invasores utilizam ao se prepararem para um ataque e como se antecipar a elas. Você também irá conhecer na Linux Magazine #86 uma maneira de proteger suas senha com o phpass e como utilizar ferramentas de monitoramento de forma a perceber qualquer sinal de quebra de segurança. Não perca, porque a próxima edição está um estouro! ■
Admin Magazine #4 Otimização de velocidade Na próxima edição da Admin Magazine, você ira conhecer as melhores dicas e tutoriais para tirar maior proveito dos computadores existentes em seu parque de TI, diminuindo assim a obsolescência do hardware e as mais diversas formas para aumentar o desempenho dos serviços que são executados na rede. Não perca a edição #4 da melhor revista para administrador de redes.
82
www.linuxmagazine.com.br