Instalando e configurando NGINX e PHP5 no Debian Lenny

História

Vou migrar de servidores para um VPS na Linode, o 360, então primeiro preciso ter certeza que tudo vai funcionar lá, para tanto preparei um máquina virtual com a mesma configuração de software que vou preparar por lá, o objetivo é rodar uma cópia de algumas instalações do Joomla, WordPress e agora um Drupal.

Como o VPS vai ser bem, digamos, compacto, fiz uma instalação básica do Debian Lenny (netinst) sem nada e parti daí. Segue agora como configurar o stack moderninho 2.0. (Uma solução até de preguiçoso, por usar o Fastcgi ao invés do FPM, mas não quero compilar o PHP agora, deixa para o próximo release).

NGINX

Comçando pelo NGINX, o ideal é pegar o código-fonte e compilar, seguem comandos:

# aptitude install build-essential libssl-dev libpcre3-dev -y
# wget http://nginx.org/download/nginx-0.8.33.tar.gz
# tar -zxvf nginx-0.8.33.tar.gz
# cd nginx-0.8.33
# ./configure --sbin-path=/usr/local/sbin --with-http_ssl_module \
--without-mail_pop3_module --without-mail_imap_module \
--without-mail_smtp_module --with-http_stub_status_module
# make
# make install
# ln -s /usr/local/nginx/conf /etc/nginx
# cd ..
# wget htt://www.manifesto.blog.br/extras/nginx
# mv nginx /etc/init.d/nginx
# chmod +x /etc/init.d/nginx
# update-rc.d nginx defaults

Vamos acertar ainda os logs do nginx, editando o arquivo /etc/logrotate.d/nginx:

/var/log/nginx/*.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
postrotate
[ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
endscript
}

E ainda a configuração do Nginx:

# mkdir /var/log/nginx
# mkdir /var/www

E o conteúdo do arquivo /etc/nginx/nginx.conf :

user  www-data;
worker_processes 4;
error_log /var/log/nginx/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
sendfile on;
keepalive_timeout 60;
tcp_nodelay on;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/css application/x-javascript text/xml \
application/xml application/xml+rss text/javascript \
image/gif image/jpeg image/png;
gzip_disable "MSIE [1-6].(?!.*SV1)";
gzip_vary on;
server {
root /var/www/;
server_name localhost;
listen 80;
location / {
index index.php index.html index.htm;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/$fastcgi_script_name;
fastcgi_param SERVER_NAME $http_host;
fastcgi_ignore_client_abort on;
}
}
}

Pronto, agora o nginx está pronto, basta criar o arquivo /etc/init.d/nginx para controlar o serviço, com o seguinte conteúdo:

! /bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local
DAEMON=/usr/local/sbin/nginx
NAME=nginx
DESC=nginx
test -x $DAEMON || exit 0
if [ -f /etc/default/nginx ] ; then
. /etc/default/nginx
fi
set -e
case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
--exec $DAEMON -- $DAEMON_OPTS || true
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \
--exec $DAEMON || true
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile \
/var/run/$NAME.pid --exec $DAEMON || true
sleep 1
start-stop-daemon --start --quiet --pidfile \
/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
echo "$NAME."
;;
reload)
echo -n "Reloading $DESC configuration: "
start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid \
--exec $DAEMON || true
echo "$NAME."
;;
configtest)
echo -n "Testing $DESC configuration: "
if nginx -t > /dev/null 2>&1
then
echo "$NAME."
else
exit $?
fi
;;
*)
echo "Usage: $NAME {start|stop|restart|reload|force-reload|configtest}" >&2
exit 1
;;
esac
exit 0

E então o ativamos para iniciar automáticamente:

# chmod +x /etc/init.d/nginx
# update-rc.d nginx defaults
# /etc/init.d/nginx start

PHP

Seguimos com a instalação do PHP5, APC e seus principais pacotes, usando os do dotdeb.org para termos versões mais recente, então primeiro adcione o dotdeb aos seus repositórios, adcionando as seguintes linhas ao /etc/apt/sources.list:

deb http://dotdeb.mirror.somersettechsolutions.co.uk/ stable all
deb-src http://dotdeb.mirror.somersettechsolutions.co.uk/ stable all

E agora instalamos o php5 sem o apache, e com os principais modulos:

# aptitude update 
# aptitude install php5 php5-cli php5-cgi php5-curl php5-gd php5-common \
php5-memcache php5-mysql php5-pgsql php5-sqlite php5-apc

Configuramos e agora criamos o script para controlar o serviço do fastcgi do php, em /etc/init.d/php-fastcgi :

#!/bin/bash
BIND=127.0.0.1:9000
USER=www-data
PHP_FCGI_CHILDREN=15
PHP_FCGI_MAX_REQUESTS=1000
PHP_CGI=/usr/bin/php-cgi
PHP_CGI_NAME=`basename $PHP_CGI`
PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin \
PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN \
PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS \
$PHP_CGI -b $BIND"
RETVAL=0
start() {
echo -n "Starting PHP FastCGI: "
start-stop-daemon --quiet --start --background --chuid "$USER" \
--exec /usr/bin/env -- $PHP_CGI_ARGS
RETVAL=$?
echo "$PHP_CGI_NAME."
}
stop() {
echo -n "Stopping PHP FastCGI: "
killall -q -w -u $USER $PHP_CGI
RETVAL=$?
echo "$PHP_CGI_NAME."
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: php-fastcgi {start|stop|restart}"
exit 1
;;
esac
exit $RETVAL

E então o ativamos para iniciar automáticamente:

# chmod +x /etc/init.d/php-fastcgi
# update-rc.d php-fastcgi defaults

Agora com o PHP configurado, terminamos criando uma página e acessando o nosso servidor local, crie em /var/www/index.php como “< ? phpinfo() ? >” e acesse o ip do servidor para ver se funcionou… ou não.

Rede de máquinas virtuais com KVM e VDE

História

Como parte da migração de servidores que estou fazendo, montei uma pequena estrutura virtual para testes… na verdade levantei uma maquina virtual com o KVM com configuração semelhante a que vou usar no VPS.

O objetivo inicial é levantar a máquina com acesso SSH, para poder configurar o servidor (nginx, php e mysql), então segue o passo-a-passo para rede no KVM. O básico do KVM/QEmu pode-se conferir nesse mini tutorial do qemu e nesse micro guia do KVM.

Preparando a VM

Então comece criando o HD, baixando a ISO de sua distro favorita, que é claro que é o Debian, e siga a instalação padrão. Para manter mais parecido com o VPS mantive tudo em uma partição só e deixei um espacinho para o swap.

# qemu-img -f qcow2 debian.qcow 10G
# kvm -monitor stdio -smp 2 -m 360 -localtime -hda debian5.qcow -cdrom debian-lenny.iso
-boot d -net nic,vlan=0 -net user,vlan=0 -name "debian-lenny"

Esses comandos só criam um HD de 10GB e iniciam o KVM com dois processadores virtuais, 360MB de ram, usando as imagens devidas e rede local padrão. Basta seguir a instalação padrão, depois para carregar a VM use o mesmo comando mas sem a imagem do cd e com boot do hda:

# kvm -monitor stdio -smp 2 -m 360 -localtime -hda debian5.qcow -boot c -net nic,vlan=0
-net user,vlan=0 -name "debian-lenny"

Rede do KVM com VDE

Agora parte importante para ter uma rede lega é usar o VDE (virtual distributed ethernet) para configurar a rede do KVM, assim podendo acessar ele como um servidor normal, e ao contrário, assim como em outras VMS.

Primeiro instale o instale o VDE, para a rede distribuída, e o dnsmasq, para servir o DHCP para os guests, no host:

# aptitude install vde2 dnsmasq 
# modprobe tun
# adduser seu_usuario vde2-net
$ newgrp vde2-net

E configure suas interfaces de rede para o vde2, em /etc/network/interfaces adicione:

auto tap0
iface tap0 inet static
address 10.0.2.1
netmask 255.255.255.0
network 10.0.2.0
broadcast 10.0.2.255
pre-up tunctl -u diogo -t tap0
pre-up /etc/init.d/dnsmasq restart
up iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
up echo 1 > /proc/sys/net/ipv4/ip_forward
vde2-switch -

Troque “diogo” pelo seu usuário que vai iniciar a VM, e as faixas de ip se precisar.

Configure por final o DNSMASQ, ao final do /etc/dnsmasq.conf adcione:

user=nobody 
domain=qemu.lan
interface=tap0
dhcp-range=10.0.2.1,10.0.2.253,255.255.255.0,10.0.2.255,8h

Ainda para cada guest que planeje ter pode definir um ip estatico pelo seu mac address, adcionando um linha para cada conforme o exemplo:

dhcp-host=11:22:33:44:55:66,10.0.2.5  

E recarregue sua rede

# /etc/init.d/networking restart  

Agora com o host configurado é a hora do guest, lance sua maquina virtual com o comando final:

kvm -monitor stdio -smp 2 -m 360 -localtime -hda debian5.qcow -boot c
-net nic,macaddr=1a:2b:3c:4d:5e:6f,model=rtl8139,vlan=0
-net vde,vlan=0,sock=/var/run/vde2/tap0.ctl
-name "debian-lenny"

Agora na VM configure a rede:

# ifconfig eth0 up 
# dhclient eth0
# ping 10.0.2.1
# ifconfig eth0 gateway 10.0.2.1
# ifconfig eth0

Presto! O ultimo comando vai mostrar o ip que o guest recebeu (se reservou o ip estático deve ser o 10.0.2.5), o ip do host é 10.0.2.1.

Agora para deixar melhor instale o servidor SSH para acessar a maquina da forma como é devido:

# aptitude install openssh-server  

Agora você pode entrar na maquina usando o ssh como root na primeira vez para criar seu usuário, e depois iniciar a vm com a opção “–nographic” e passar a entrar apenas com o SSH.

Divirta-se!

Troca de mensagens com criptografia em Java, usando AES.

O escopo de uma aplicação incluía a troca de mensagens sensíveis como parte de um WebService, e além do uso de HTTPS, deveria ser usada alguma forma de criptografia na parte crítica do serviço.

Logo deveria haver uma forma de criptografia disponível tanto no servidor como nos clientes, inicialmente um serviço em Java e o cliente seria no Android (depois outros surgiriam), com isso tem quer ser usado um algorítimo de chave simétrica, que permitisse recuperar a mensagem original de posse da chave de criptografia usada. Obviamente deveria ser um mecanismo eficiente.

Escolhi o AES por acreditar ser o padrão ideal atualmente, “lançado” em 2001 entrou em estudo pelo governo dos EUA e hoje é o seu padrão para troca de documentos, incluindo os “tops”. Usando mesmo uma chave de apenas 128bits seria extremamente seguro, a chave pode ser de 128bits, 192bits ou 256bits.

Se você está desenvolvendo em Java EE 5 ou no Android (Ou qualquer Java 6, acredito eu, mas não confirmei), ambos já possuem a implementação deste algoritmo, caso a plataforma não possua você pode usar a implementação do Bouncy Castle, geralmente basta o Provider do bcprov-jdk16-*.jar .

O primeiro passo para a criptografia é definir uma chave, ela pode ser gerada automaticamente pelos mecanismos do sistema:

public byte[] key() throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey key = keyGen.generateKey();
return key.getEncoded();
}

Esse método retorna o array de bytes de uma chave de 128bits, podemos usar 256bits mas esse algorismo nem sempre está disponível ou requer configurações especificas do JRE.

A criptografia trabalha com valores em Hexadecimal, assim a chave também usa valores em hexa, você pode criar uma chave com um array de hexas do tamanho que deseja da chave, uma chave de 128bits são 8 bytes (128/16), assim:

byte[] key = { 0x0f, 0xad, 0x54, 0x12, 0x00, 0xaf , 0x34, 0xff }

Em posse de uma chave de criptografia basta aplica-la a uma engine de criptografia, junto dos bytes da mensagem a ser encriptada, com o seguinte método:

public byte[] encode(byte[] input, byte[] key) throws NoSuchAlgorithmException, 
InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchPaddingException {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(input);
return encrypted;
}

Detalhe para o “AES/ECB/NoPadding” , isso usa o algoritmo AES e não faz o padding da mensagem.

Por trabalhar em hexadecimal, o algoritmo trabalha com blocos de 16 bytes, então a mensagem(seus bytes) devem ter uma tamanho múltiplo de 16 para não haver erros de “BadPaddingException: pad block corrupted, para isso podemos usar os seguintes métodos, que preenchem os espaços que faltam até formar o tamanho necessário com “null”:

public String nullPadString(String original) {
StringBuffer output = new StringBuffer(original);
int remain = output.length() % 16;
if (remain != 0) {
remain = 16 - remain;
for (int i = 0; i < remain; i++) {
output.append((char) 0);
}
}
return output.toString();
}

Então podemos encriptar uma mensagem assim:

String mensagem = "Hello World!";
byte[] enc = encode(nullPadString(mensagem).getBytes(), key);

Para descriptografar a mensagem não tem mistério, basta o seguinte método:

public byte[] decode(byte[] input, byte[] key) throws NoSuchAlgorithmException, 
InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchPaddingException {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(input);
return decrypted;
}

A única diferença é o parâmetro passado ao Cipher, para de descriptografar.

Agora que podemos criptografar e decodificar as mensagens, precisamos garantir seu formato ao ser enviado via HTTP/HTTPS.

Novamente, como trabalhamos com Hexadecimal, ele não é simplesmente convertido para String, não sem perda, e a conversão de volta também traria riscos, ainda mais se for em plataformas diferentes.

Precisa-se então converter esses valores hexadecimais para uma representação “por extenso” destes, e que possa ser transformado de volta, e podemos alcançar isto com os seguintes métodos:

public String fromHex(byte[] hex) {
StringBuffer sb = new StringBuffer();
for (int i=0; i < hex.length; i++) {
sb.append( Integer.toString( ( hex[i] & 0xff ) + 0x100, 16).substring( 1 ) );
}
return sb.toString();
}

public byte[] toHex(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}

Então para enviar uma mensagem podemos proceder da seguinte forma (contando que ambos possuem a mesma chave):

String mensagem = "Hello World!";
byte[] enc = encode(nullPadString(mensagem).getBytes(), key);
String msgParaEnviar = fromHex(enc);

Enviamos então via http a string msgParaEnviar, e ao recebe-la procedemos a decodificação:

byte[] msgEnc = toHex(msgRecebida);
byte[] msg = decode(msgEnc,key);
String mensagem = new String(msg).trim();

Assim temos a mensagem nas duas pontas, o trim é necessário devido ao “padding”.

Veja o código da Classe de Criptografia que uso.

PHPDocumentor: Documentação de API em PHP

Outra parte importante em um projeto, principalmente se está tratando de pacotes públicos e frameworks, é uma documentação completa. Mas documentar é um saco.

Parte da documentação incluí a API de classes, com os pacotes, classes, métodos e suas descrições. O padrão para documentação destes são o docblocks, ou phpdoc, que são comentários no código, sobre a classe, propriedade ou método, e possuem descrição e tags padrões para completar a documentação.

< ?php

/**
* Class Foo
*
* This class implements a hello speaker
* @package hello
*/
class Foo {
/**
* this is some useless var
*/
private $bar ;

/**
* Says hello to provided name
* @param string $name this is the name to be said
* @return Foo
*/
public function hello($name="world") {
echo "Hello, ".ucfirst($name)."!";
return $this
}
}

Esses comentários comuns são mais fáceis de escrever durante o desenvolvimento, e acrescentam muito a documentação. O padrão permite descriçoes muito mais complexas que isso, mas na maior parte das vezes não é necessário.

Agora que esses comentários estão em seu lugar basta usar uma ferramenta para transformar o código em documentação de verdade, pronto para ir online e estar disponível para consulta.

O PhpDocumentor é extremamente fácil de usar e instalar, e gera documentações razoáveis. Ele possui bastante opções de formato de saída (html, pdf, xml…) e templates, mas vou fazer só o básico aqui.

Para instalar o PhpDocumentor você pode usar o PEAR ( se você não conhece, está perdendo muito), basta rodar o comando a seguir:

# pear install PhpDocumentor

Se tudo correr bem você pode agora transformar seu código em documentação com a linha a seguir:

$ phpdoc -t docs -o HTML:default:eathli -d src

Nesse caso a documentação será salva na pasta docs, no formato HTML usando o template earthli, através dos arquivos da pasta src.

Basta apontar seu navegador para a pasta docs e navegar na documentação agora.

 

Documentação em PHP

 

 

Confira mais opções comentários, anotações e tudo mais no Manual do PhpDocumentor.

Testes Unitários em PHP com simpletest

Testes automatizados são parte importante do desenvolvimento de software, apesar de ser a mais demorada prática a se aceitar, é a que mais traz benefícios. O seu uso deve ser simples, e por isso é bom o uso de um framework prático para tal.

No começo escrevi scripts de testes “na mão” mesmo, com ifs e elses, mas, apesar de ser melhor que nada, não é nada prático se comparado ao uso de um bom framework. Então tentei usar o phpunit uma vez, mas achei mais complexo que o necessário, então parti para o simpletest.

O simpletest é realmente simples, basta fazer o download do pacote e descompacta-lo na sua pasta de testes, e em seguida é só escrever sua suite de testes.

Uma suite de testes é escrita da seguinte forma:


< ?php

include_once 'simplestest/autorun.php';

class AllTests extends TestSuite {
function allTests() {
$this->TestSuite("Meus testes");
$this->addTestCase(new MeuCasoDeTests1);
$this->addTestCase(new MeuCasoDeTests2);
}
}

?>

E cada caso de teste se define da sequinte forma:


< ?php

include_once 'simpletest/autorun.php';

class MeuCasoDeTests1 extends UnitTestCase {
function testFoo() {
$this->assertEqual("foo","foo");
}
function testBar() {
$this->assertEqual("foo","bar");
}
}
?>

Cada função no caso de teste iniciada por “test” será executada na ordem declarada, e o cada “assert” é um teste. Existem vários “asserts” disponíveis.

Basta acessar pelo browser a url do caso de testes ou da suite de testes e ter certeza de testar tudo, para garantir a qualidade do software.

Programando fora da zona de conforto: Programação Funcional e NoSQL

Mais alguns links da série de programação funcional, e também adcionar o NoSQL a lista, banco da dados não relacionais para resolver o problema da escalabilidade.

 Divirta-se. 

Linux em um pendrive: Debian e Enlightenment (E17) persistente.

História

 

Enlightenment E17

 

 

Além de já ter usado o Linux em um pendrive com o DSL, que é uma das distros que melhor se adaptam ao estilo, é fácil hoje instalar outras distros semelhantes, como o Slax, o SliTaz (muito bom) e o TinyCore(abandonei o DSL por este), com seus 10MBs.

A boa noticia é que hoje é bem mais fácil rodar um linux a partir de um pendrive, temos o projeto pendrive linux, com vários distros preparadas para tal, e o unetbootin para configurar e “bootar” qualquer ISO a partir de um pendrive.

Parti então para as distros completas: Ubuntu e Debian. O Ubuntu eu não gosto, acho um desktop muito fraco. O Debian iniciei com o projeto do Debian Live, oficial, mas este se baseia na versão estável, então está muito antigo nos pacotes. Mas como o debian é o debian era possível reconstruir o Debian live em qualquer versão, com o Debian Live Helper, mas também dava muito trabalho e demorava muito.

Foi ai que pensei em ficar com as minimalistas, entre o TinyCore e o SliTaz. Não fiquei com o SliTaz por que me parecia pacotes muito antigos, em especial o kernel, já o TinyCore eu fiquei com preguiça mesmo, afinal ainda seria muito parecido com o DSL.

Ai eu esbarrei no Elive. Na verdade já paquerava o Enlightenment tem um bom tempo, mas E16 não é tão interessante, e o E17 envolvia muitas gambiarras, e as versão “fáceis” de instalar não estavam muito legais.

Uma boa opção me pareceu usar o Elive, baseado no debian, que já vem configurado com tudo de bom e melhor do Enlightenment de desenvolvimento, por isso resolvi testa-lo.

Como fazer

 

Unetbootin com E17 ELIve

 

 

Primeiro instale o Unetbootin, que está presente na maioria das distribuições modernas:

# aptitude install unetbootin

Executando-o como root, o unetbootin já existem diversas distros prontas, ele mesmo se encarrega de baixar a ISO configurar o pendrive e torná-lo bootável com o syslinux.

Você pode também fazer o Download da ISO do ELive você mesmo(eu fiz assim), e seleciona-la no unetbootin, e então é só seguir e iniciar o processo, não tem mistério nenhum.

O passo seguinte, após o unetbootin dizer que terminou, é configurar um arquivo para que o Elive salve as alterações. Você precisa primeiro criar um arquivo para ser a “partição” da persistencia:

# dd if=/dev/zero of=elive-rw bs=1M count=1024

O valor do count diz o tamanho do arquivo em megabytes, veja quanto resta no pendrive e quanto você quer usar, no exemplo vai ter 1GB (mais ou menos).

Em seguida formate-o como ext3, apenas confirme:

# mkfs.ext3 elive-rw

Agora pode copiar o arquivo elive-rw para a raiz do pendrive, e editar o arquivo de boot “syslinux.cfg” nessa mesma raiz. No linha append da entrada padrão adcione “persistent=elive-rw” e salve.

Basta desmontar o pendrive e rebootar o computador com a BIOS configurada para carregar apartir do pendrive e curtir no ambiente. Trate-o como um netbook, pois o espaço é pouco.

Um detalhe importante, que me atrapalhou a testar o elive antes, é que ele não roda no Qemu(e KVM) por algum motivo, mas funciona no VirtualBox e VMWare, eu acredito.

Agora posso carregar meu lindo ambiente de programação para todo canto, combinado com controle de versão, e impressionar todo mundo com como o linux pode ser bonito :D

Compartilhando internet pela rede sem fio no linux

Tutorial de como configurar sua placa de rede sem fio para compartilhar a internet, no linux.

Aqui vou explicar como configurar seu computador/notebook como hotspot wifi, para compartilhar a internet na rede sem fio, com o mínimo de “segurança” WEP apenas.

O Primeiro passo é saber qual a interface que chega a conexão com a internet, no geral se é internet discada, 3G ou se usa o pppoe a interface é ppp0, se a internet chega roteada pela rede é a mesma da interface de rede, eth0 ou outro. Aqui uso internet móvel 3G, então conecta em ppp0.

Temos então que mascarar o encaminhamento de pacotes dessa interface por um nat, usando as regras do iptables. Carregue o módulo de nat, definir a regra e ativar o encaminhamento no sistema, com os seguintes comandos:

# modprobe iptable_nat
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# echo 1 > /proc/sys/net/ipv4/ip_forward

O próximo passo é configurar a rede wifi, com os seguintes comandos:

# ifconfig wlan0 down
# ifconfig wlan0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
# ifconfig wlan0 up

Em seguida definimos as caracteristicas da rede sem fio, definindo o nome, o modo ad-hoc, a chave de encriptação e para apenas aceitar com encriptação, os comandos:
# iwconfig wlan0 essid “acer”
# iwconfig wlan0 mode ad-hoc
# iwconfig wlan0 key ‘s:diogo’
# iwconfig wlan0 key restricted

Para os clientes receberem as configurações devidas você precisará agir como cliente dhcp (ou configurar manualmente a rede nos clientes), você pode instalar o servidor com o seguinte comando:

# aptitude install dhcp3-server

Para configurar o servidor, edite o arquivo /etc/dhcp3/dhcpd.conf, conforme:

ddns-update-style ad-hoc;
option domain-name “home.org”;
option domain-name-servers 208.67.222.222, 208.67.220.220;
default-lease-time 600;
max-lease-time 7200;
authoritative;
log-facility local7;
subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.10 192.168.0.254;
option routers 192.168.0.1;
option broadcast-address 192.168.0.255;
}

Com o dhcp configurado, basta ativa-lo na interface da rede sem fio.

# dhcp3d wlan0

Agora os clientes podem se conctar a sua rede e navegar na sua internet. Você pode tentar configurar outro meio mais seguro que WEP, mas eu não sei ainda :P e definir regras no dhcp e iptables limitando os MACs e IPs, mas isso fica para próxima.

Downgrade de versão no Debian

Sabe, sou um feliz usuário de Linux. Mesmo tendo um hardware complico, isso melhorou com o tempo.

A história deste post está no primeiro link.

Vou explicar aqui o simples passo-a-passo para fazer o downgrade de versão do debian, sem reinstalar o sistema ou fazer algo mais complicado que o apt-get costumeiro. Se você usa o debian, sabe que pode fazer isso com a consciencia limpa.

O debian tem um sistema de “pinning” para o apt, que permite, entre outras coisas, definir preferencias de versões de pacotes, e vamos usar isso para fazer o downgrade, já que por padrão o apt escolhe os pacotes mais novos.

Primeiro devemos acertar os repositórios desejados, eu estou voltando do unstable(Sid) para o testing(Squeeze), então meu /etc/apt/sources.list ficou assim:

# deb ftp://ftp.br.debian.org/debian/ unstable main contrib non-free 
# deb ftp://ftp.br.debian.org/debian-multimedia/ unstable main

#deb ftp://security.debian.org/ testing/updates main contrib non-free
deb ftp://ftp.br.debian.org/debian/ testing main contrib non-free
deb ftp://ftp.br.debian.org/debian-multimedia/ testing main

#deb http://apt.wicd.net/ sid extras

Eu apenas comentei os “unstable” e adcionei as linhas do “testing”.

Agora vamos configurar o tal “pin”, para editar suas preferências do apt e dpkg você pode editar o arquivo /etc/apt/preferences, ou criar um arquivo em /etc/apt/preferences.d/ para cada configuração, no caso para o downgrade para o testing, fiz um assim:

X-comment: Force downgrade to testing.
Package: *
Pin: release a=testing
Pin-Priority: 1100

Veja que facilmente podemos criar outros, para escolher versões especificas de cada pacote, bastando acerta o “pin-priority” para isso.

Após configurado, basta atualizas a lista de pacotes e instala-los:

# dselect update
# aptitude dist-upgrade

E Pronto, seu sistema está “atualizado”, é só reiniciar o X, se não mudou o Kernel nem precisa reiniciar. Se você acha que mudou muitos módulos do kernel em uso pode fazer um “depmod” e depois um “modprobe” nos módulos desejados.

Seja feliz com seu sistema “novo” :)

Introdução a linguagem Lua, você vai querer aprender também.

Em busca de uma programação poliglota, e entender as vantagens da cada linguagem oferece, iniciei meus estudos na linguagem Lua.

Histórico 

 Lua é uma linguagem de extensão, criada nos laboratórios da PUC-RJ, com o objetivo de ser simples de ser embarcada. Isso é, ele é extremamente pequena, sucinta, de sintaxe simples, esta presente praticamente em qualquer sistema. É uma verdadeira “write once, run everywhere”(bem mais que java). O pacote de Lua, com documentação, código fonte e exemplos tem cerca de 800KBs, apenas o runtime compilado(no linux) tem 150KBs. São 1700 linhas de código C portável, o mesmo código compila em várias plataformas.  

Roda em Unix, Linux, Windows, e em várias plataformas embarcadas, como celulares e setop boxes, robôs entre outros. Pode ser incluída em qualquer aplicação feita em outra linguagem , com quase nenhum overhead. Para ter melhor noção, um interpretador Lua completo em puro Java (tanto J2ME quanto J2SE), tem cerca de 150KBs. É usada como linguagem de extensão em produtos da Adobe, roda no Android, esta no Ginga (da TVDigital), e é muito usada em Jogos, como o sempre citado World of Warcraft.

E por que não fazer tudo em Lua então? Lua foi pensada em extensão de aplicativos, então a biblioteca básica é bem limitada, não possui as milhares de funções para tudo como teria em Java ou PHP ou Ruby ou Python ou Outra. Seus 150KBs incluem apenas o necessário, muito tem disponível em módulos externos, como os do LuaRocks. Embora seja possível para certas aplicações, mas não é foco.

Enfim, vendido o peixe de Lua. Agora é demonstrar, afinal “Show me the code”.

Exemplos 

Primeiro o essencial, lua é Imperativo, tem funções como cidadão de primeira classe(ah, deu para entender) e tudo é armazenado em tabelas. Tabelas são como arrays, mas são tabelas, depois eu explico. É tipagem dinamica, essencialmente não é orientada a objetos(pode ser simulado), possui escopo e é modular. Vamos ao exemplo.  

  -- rss.test.lua

local xml = dofile("xml.lua")
local sample = "<?xml ?><channel><rss><title>Lua Rock!</title>"
sample = sample .. "<item><title>Item 1</title></item>"
sample = sample .. "<item><title>Item 2</title></item>"
sample = sample .. "</rss></channel>";
local rss = xml.parse_rss(sample)
assert(rss[1].title == "Item 1","Invalid Item 1 title")
assert(rss[2].title == "Item 2","Invalid Item 2 title")
print("rss tests ok")

Esse simples exemplo é o arquivo de testes de uma biblioteca de parser de rss que uso. O uso do modificador “local” indica o escopo mais fechado possível dessa variável. O não uso de “local” implica numa variável “global”, visível em toda a aplicação.  

A função “dofile” carrega um arquivo (como se fosse um include), esse arquivo carregado pode retornar uma ou mais variáveis, no caso o xml.lua me retorna uma tabela.

A chamada de função é normal, no caso o xml é uma tabela, e um dos seus índices (parse_rss) é uma função que recebe um argumento e retorna uma tabela.

  Fato interessante sobre tabelas em Lua, é que os índices numéricos começam em 1, e não em 0 como estamos acostumados.

  Em “rss[1].title”, eu pego o item de índice 1(o primeiro), da tabela “rss” e o item de índice title dentro desta. No “assert” eu garanto que a expressão retorne True, do contrário levanto o erro no segundo argumento. 

  O arquivo de rss é assim: 

  -- rss.lua
local xml = dofile("utils/xml.lua")
xml.parse_rss = function (str)
local rss = {};
local t = xml.parse(str)
local channel = t[2][1]
for k,v in pairs(channel) do
local label = v['label']
if label == "item" then
local item = {}
for k,v in pairs(v) do
local label = v['label']
if label and v[1] then
item[label] = v[1]
end -- if label and value
end --for pairs in v
table.insert(rss,item)
end -- if is item
end -- for item in channel
return rss
end
return xml

 

Novamente eu carrego um parser xml externo, e na tabela xml eu adcione um índice, o parse_rss. Nesse índice eu ligo uma função, que recebe um argumento. Veja que não tem tipo fixo, eu poderia usar assert para garantir o tipo.

Eu defino então a variável “rss” como uma tabela vazia. Então faço um loop for nos itens retornados pelo parser xml. A função “pairs” retorna as chaves (k) e os valores(v) de uma tabela.

Temos então um IF padrão, nova tabela e mais um for. Então eu uso o “insert”, “table”, que é uma tabela embutida no core do lua. E retorno o RSS, o arquivo então retorna a tabela com as funções.

O parser XML é deveras grande, não vale a pena passa-lo aqui, e isso tudo foi apenas para dar um visão geral na estrutura da sintaxe da linguagem. Vamos agora no passo-a-passo de verdade.

Tutorial 

Em Lua, funções são objetos de primeira classe, então podemos por exemplo ter funções “curried”, como no exemplo abaixo:

  -- curry.lua

function soma(n)
return function(n2)
return n + n2
end
end

local f2 = soma(2)
local soma2e3 = f2(3)
assert(soma2e3 == 5)

 

Podemos levar um pouco alem:

  
-- curry.lua
local somador = function(n)
local soma = n
function f(n2)
if type(n2) == "number" then
soma = soma + n2
return f
else
return soma
end
end
return f
end

local total = somador (1) (2) (3) ()
print(total)

local somador = function (itens)
assert(type(itens) == "table")
local soma = 0;
for k,v in pairs(itens) do
soma = soma + v
end
return soma, #itens
end

local total,n = somador {
1,2,3
}
print(total,n)

local somador = function(```)
local soma = 0;
for k,v in pairs(arg)do
if type(k) == "number" then
soma = soma + v
end
end
return soma
end

local total = somador(1,2,3)
print(total)

 

São as várias formas de fazer a mesma coisa, veja no penúltimo somador uma característica legal, uma função pode retornar mais de uma variável.

Agora que você conhece como fazer funções, loops e condicionais, vamos tratar das tais tabelas.

  --tabelas.lua
local tab = {
"um","dois",
x="3",
y=function() return "hello" end
}
table.insert(tab,"cinco")
table.remove(tab,2)
local final = table.concat(tab," , ") -- apenas numéricos
print(tab[1], tab[2], tab["x"],tab.y,tab["y"](),tab[5],final)

 

Entendeu?

A ultima parte que quero tratar nesse texto é sobre coroutines, que são as “threads” do lua, incluído no core da linguagem, exemplo geral:

  --co.lua
local hello = coroutine.create(function(name)
print ("hello "..name)
end)


coroutine.resume(hello,"diogo")

local hello2 = coroutine.create(function(name)
repeat
print("hello you, "..name)
name = coroutine.yield(name)
until not type(name) == "string"
end)

local h2 = coroutine.resume(hello2,"diogo")
local h3 = coroutine.resume(hello2,"diego")
local h3 = coroutine.resume(hello2)
local h4 = coroutine.resume(hello2)

 

Acho que com esses exemplo já dá para decidir se quer ou não aprender Lua. Caso queira, o melhor lugar é a wiki da documentação de lua.

  Termino com um exemplo de uso real, uma função que realiza uma busca na wikipedia e retorna o resultado, o JSON eu achei na internet, e o http usa o Lua Socket, o wikipedia.lua.