Archive

Archive for March, 2010

Postfix a La Carte :)

Este e uma compilação das formas possiveis de uso do postfix como eu tive uma certa dificuldade de entender alguns conceitos do postfix como para que servia o virtual_alias_* , virtual_mailbox_*.

Então resolvi falar um pouco sobre algumas formas que o postfix trabalha.  Vamos lá 😀

Arroz com feijão

O feijão com arroz do postfix é bem simples iremos configurar um servidor de e-mail respondendo a um único dominio apenas. No nosso exemplo o dominio será yamaha.com.br. Será usada essa mesma configuração para todos os ambientes posteriores de teste que utilizaremos.

Dominio: yamaha.com.br
SMTP: mail.yamaha.com.br
Endereço IP: 192.168.1.10/24

Segue topologia abaixo:


myhostname = mail.yamaha.com.br
mydomain = yamaha.com.br
mydestination = localhost, yamaha.com.br

Vamos la o primeiro parametro é o “myhostname” o qual é o nome do host que esta instalado o servidor de e-mail, ou seja o MTA(MTA e o servidor de e-mail proprieamente dito) no nosso caso configuramos o nome do servidor de e-mail como “mail.yamaha.com.br” um nome ficticio.
O segundo parametro é o “mydomain” que indica o nome do domínio que o servidor de e-mail(postfix) acomoda.
O terceiro parametro “mydestination” e muito importante ele que diz quais dominios o servidor de e-mail ira atender, no caso yamaha.com.br, entao sendo assim todos os emails destinados ao user@yamaha.com.br deverá ser entregue ao nosso servidor com endereço ip 192.168.1.10 ou mail.yamaha.com.br qualquer outra coisa por exemplo user@honda.com.br será rejeitado com a mensagem nos logs “user unknown”.

Funcionamento

O usuário na estação workstation envia um email apartir de fulano@yamaha.com.br para ciclano@yamaha.com.br, para esse envio funcionar os usuarios fulano e ciclano devem existir no /etc/passwd. Outro exemplo o fulano@honda.com.br envia e-mail para ciclano@yamaha.com.br o mta do dominio honda ira consultar o registro MX do dominio yamaha.com.br no servidor dns responsavel pelo dominio no caso ns1.yamaha.com.br o qual irá responder mail.yamaha.com.br, assim sendo o cliente fulano@honda.com.br envia outro pedido para resolucao de endereço ip do nome mail.yamaha.com.br para somente entao enviar o email para ciclano@yamaha.com.br. Quando o postfix receber o pacote de dados ira checar se existe o usuario ciclano no /etc/passwd e entregar a mensagem. Esse e o hello world em postfix 😀

Preparando os ingredientes

Blz funcionou o ambiente com um único dominio, mas se eu precisar de que um postfix atender a mais de um dominio. Por exemplo yamaha.com.br e honda.com.br? para isso vou utilizar o virtual domain do postfix. Postfix pode enviar, receber e armazenar mensagem para mais de um dominio usando dois métodos.

  • virtual_alias_domains
  • virtual_mailbox_domains

O primeiro método virtual_alias_domains expande o número de dominios para o qual o servidor postfix é o destino final. Os dominios listados no parametro “mydestination” são chamados de dominios canonicos porque normalmente listão todas os domínios da máquina local. Para ter dominios a mais ou seja sem o dominio ser local é preciso criar um virtual_alias_domains. Por exemplo no exemplo anterior nos tinhamos o base de usuarios de email ficava no /etc/passwd e atendia pelo dominio yamaha.com.br, porém imaginemos que acontece aquelas fusões de grandes empresas e a yamaha comprasse a honda. Entao teriamos que ter alguns usuarios com o dominio yamaha.com.br e o dominio honda, dessa forma teriamos o usuário fulano como fulano@yamaha.com.br e fulano@honda.com.br na mesma máquina. Utilizando a configuração anterior poderiamos ter esse ambiente utilizando virtual_alias_domains. Um alias e um apelido logo um alias_domains e um apelido para o dominio no caso o dominio local se chama yamaha.com.br e o apelido seria honda.com.br. Esse apelido pode ser para a mesma conta de usuario, mailbox ou para conta de usuario distinta, outra mailbox. Segue nova configuração abaixo.

myhostname = mail.yamaha.com.br
mydomain = yamaha.com.br
mydestination = localhost, yamaha.com.br
virtual_alias_domains = honda.com.br
virtual_alias_maps = hash:/etc/postfix/virtual_alias_maps

Veja o arquivo “/etc/postfix/virtual_alias_maps”.


# honda.com.br
postmaster@honda.com.br postmaster@yamaha.com.br
jaspion@honda.com.br jaspion@yamaha.com.br
batman@honda.com.br bruce@yamaha.com.br
bruce@honda.com.br bruce@yamaha.com.br

Espaguete

Vamos testar o envio de mensagem.


# echo test | sendmail bruce@honda.com.br
ou
# mail -s test bruce@honda.com.br

Vejam os logs do envio do e-mail.


Mar 26 08:28:04 mail postfix/qmgr[5224]: C8FDBF292:
from=<root@yamaha.com.br>, size=1266, nrcpt=1 (queue active)
Mar 26 08:28:04 mail postfix/smtpd[5230]: disconnect from
localhost[127.0.0.1]
Mar 26 08:28:04 mail postfix/local[5226]: C8FDBF292:
to=<bruce@honda.com.br>, relay=local, delay=0.02,
delays=0.01/0/0/0.01, dsn=2.0.0, status=sent (delivered to mailbox)

Vemos nas partes em negrito a origem(quem enviou o e-mail) e o destino do e-mail no caso root@yamaha.com.br(from) e bruce@honda.com.br(to).

Rocambolé de carne 😛

O próximo método de virtual domain é o virtual_mailbox_domains, um virtual_mailbox_domains são domínios para os usuários que não têm uma conta local (isto é, para os usuários que não estão no arquivo /etc/passwd). Existe um agente de entrega(delivery agent): virtual e local. Por padrão o postfix utiliza o agente local o agente de entrega virtual(virtual delivery agent) não pode acessar seu sistema de usuário local(/etc/passwd) para procurar os nomes dos destinatários. Em vez disso, o agente de distribuição virtual depende inteiramente de mapa que não têm nada a ver com o seu sistema informados na configuração(virtual_mailbox_maps, virtual_mailbox_aliases). Segue abaixo uma configuração utilizando virtual_mailbox_*.


myhostname = mail.yamaha.com.br
mydomain = yamaha.com.br
mydestination = localhost.$mydomain, $myhostname
mynetworks = 127.0.0.0/8, 192.168.0.0/16, 10.1.4.0/24, 10.0.0.0/24
virtual_mailbox_domains = honda.com.br
virtual_uid_maps = static:2001
virtual_gid_maps = static:1001
virtual_mailbox_base = /maildir
virtual_mailbox_maps = hash:/etc/postfix/virtual_mailbox_recipients
virtual_alias_maps = hash:/etc/postfix/virtual_mailbox_aliases

Arquivo “/etc/postfix/virtual_mailbox_recipients”.


batman@honda.com.br batman/
robin@honda.com.br robin/
aquaman@honda.com.br aquaman/
superman@honda.com.br superman/
flash@honda.com.br flash/

O caracter “/” indica que a mailbox está no formato maildir não mais em mailbox, que é o padrão do postfix. Arquivo “/etc/postfix/virtual_mailbox_aliases”


bruce@honda.com.br batman@honda.com.br
dick@honda.com.br robin@honda.com.br
clark@honda.com.br superman@honda.com.br
barry@honda.com.br flash@honda.com.br

Vamos testar o envio de mensagem.


# echo test | sendmail bruce@honda.com.br
ou
# mail -s test bruce@honda.com.br

Vejam os logs do envio do e-mail.


Mar 26 08:28:04 mail postfix/qmgr[5224]: C8FDBF292:
from=<root@yamaha.com.br>, size=1266, nrcpt=1 (queue active)
Mar 26 08:28:04 mail postfix/smtpd[5230]: disconnect from
localhost[127.0.0.1]
Mar 26 08:28:07 mail postfix/local[5226]: CE83BF287:
to=<batman@honda.com.br>, orig_to=<bruce@honda.com.br>,
relay=local, delay=0.24, delays=0.01/0/0/0.24, dsn=2.0.0, status=sent
(delivered to maildir)

Lembrando que toda essa configuração ocorreu sem autenticação e apenas para ilustrar e elucidar os conceitos de virtual_alias e virtual_mailbox que quando comecei a mexer com postfix achei muito confuso e não vi uma documentação explicando apenas receitas de bolos.

Att.

Advertisements
Categories: E-mail

Entrando dentro do kernel sem bater na porta :D

March 19, 2010 1 comment

Ola após um longo período bem turbulento sem postagem devido a falta de tempo, agora me sobrou um tempo resolvi postar algo interessante(pelo menos para mim), esse e o primeiro de alguns posts que quero falar sobre lkm. Mas e ai? que macumba é LKM?!?. Bom LKM é Load Kernel Module ou módulos do kernel carregavéis “aportuguesado” :D. O que exatamente é um módulo do kernel? Os módulos são pedaços de código que podem ser carregadas e descarregadas dentro do kernel. Eles estendem a funcionalidade do kernel sem a necessidade de reiniciar o sistema. Por exemplo, um tipo de módulo é o driver de dispositivo, que permite o acesso ao hardware conectados ao sistema. Sem os módulos, teríamos que ter o núcleo do sistema operacional na forma de um kernel monolíticos e quando fosse adicionar novas funcionalidades teria que ser feito direto na imagem do kernel. Ou seja nova compilação, recompilação,.., etc. Outra desvantagem em kernel monoliticos é o tamanho do arquivo de imagem do kernel se torna grande devido a ter que conter todo os “pedaços” de codigos ou drivers para cada possível placa de rede, placa de video, ou dispositivo quaisquer, sem contar que a cada inserção de dispositivo um novo suporte de driver também deve ser adicionado gerando com isso a necessidade de recompilar o kernel e reiniciar a máquina. Bom eu desenvolvi esse modulo quando estava no primeiro ano de faculdade nos primórdios do meu aprendizado em Linux. Conforme eu for encontrando tempo vou postar alguns lkm que fiz um deles para interceptar syscall, device driver didatico, criar uma syscall, o duro vai ser converter e ajustar meu código de kernel 2.4 para 2.6 😛

Bom para criar um lkm voce precisa de pre-requisitos um deles é saber a melhor linguagem de todos os tempos “C” 😛 sendo assim eu vou pressupor que voce leitor ja é um programador C. Segue codigo abaixo do nosso LKM.


/*
* hello_world.c - Um simples LKM.
*/
#include <linux/module.h> /* cabeçalhos requeridos */
#include <linux/kernel.h>

int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
return 0;
}

void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}

Vamos as explicações? Pois bem as primeiras linhas e bem intuitivo declaracao de bilbliotecas do kernel. Na linha:


int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
return 0;
}

E a função responsavél por inicializar nosso módulo ou seja carrega nosso código dentro do espaço kernel, vamos fazer uma parada aqui. Afinal o que é espaço kernel? Bom uma regra, todo LKM e executado no assim chamado “espaço kernel” ou “kernel space” enquanto que aplicativos como o editor vim, openoffice, firefox rodam em “espaço usuário” ou “user space”. Livro do Tannenbaum função de um sistema operacional é a de criar programas ou softwares para serem executados em um computador e criar uma interface para esses programas ou softwares protegendo o acesso nao autorizado a dispositivos de hardware e software tirando assim a responsabilidade do programador de aplicativos de se preocupar em carregar registradores da CPU chamar interrupção tal, etc. Esse “espaço” assim designado e chamado de espaço kernel e cria essa proteção dos softwares de usuários do sistema operacional. Bom agora que sabemos o que é espaço kernel e espaço usuário continuamos analisando o código.


void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}

Como temos a função de entrada no kernel(kernel space), também temos a função de saida do kernel “cleanup_module” simples né. Agora vamos a função dentro de cada item(init e cleanup) os “printk”. Quem e acostumado ou é programador C já sacou o que faz o printk sim ele e equivalente ao printf no espaço usuário porém com resalvas. A macro “KERN_INFO” é uma macro que indica prioridade para a mensagem via printk normalmente utilizado pelo ksyslog ou klogd em sistemas Linux antigos. Com isso você pode definir prioridade quando for definir mensagem para o programador do kernel. Existem 8 niveis de prioridade definidas no arquivo de cabeçalho kernel.h normalmente nos fontes do kernel fica em linux-versao/include/linux/kernel.h, vejam as prioridades abaixo.


#define KERN_EMERG "" /* system is unusable */
#define KERN_ALERT "" /* action must be taken immediately */
#define KERN_CRIT "" /* critical conditions */
#define KERN_ERR "" /* error conditions */
#define KERN_WARNING "" /* warning conditions */
#define KERN_NOTICE "" /* normal but significant condition */
#define KERN_INFO "" /* informational */
#define KERN_DEBUG "" /* debug-level messages */

Blz código explicado vamos compilar, mas antes precisamos criar um arquivo Makefile para ser utilizado pela ferramenta de compilação make. Segue Makefile abaixo:


obj-m += hello_world.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Não é intuito deste post explicar o funcionamento do make senão o post vai ficar muito extenso talvez num post futuro. Após a criacao do arquivo execute o comando make


root@capsula:~/lkm# ls
hello_world.c Makefile
root@capsula:~/lkm#
root@capsula:~/lkm# make
make -C /lib/modules/2.6.31-14-generic-pae/build M=/home/ricardobarbosa/lkm modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.31-14-generic-pae'
CC [M] /home/ricardobarbosa/lkm/hello_world.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/ricardobarbosa/lkm/hello_world.mod.o
LD [M] /home/ricardobarbosa/lkm/hello_world.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.31-14-generic-pae'
root@capsula:~/lkm# ls
hello_world.c hello_world.mod.c hello_world.o Module.markers Module.symvers
hello_world.ko hello_world.mod.o Makefile modules.order
root@capsula:~/lkm#

Ótimo meu módulo compilou com sucesso e podemos ver o modulo .ko (uma curiosidade sabe oque significa a extensao .ko – Kernel Object). Vamos subir nosso módulo dentro do kernel? para isso utilizamos o comando insmod (utilitário para carregamento e descarregamento de lkm).


root@capsula:~/lkm# modinfo hello_world.ko
filename: hello_world.ko
srcversion: 140276773A3090F6F33891F
depends:
vermagic: 2.6.31-14-generic-pae SMP mod_unload modversions 586
root@capsula:~/lkm# insmod hello_world.ko
root@capsula:~/lkm# lsmod
Module Size Used by
hello_world 988 0
crc_ccitt 1852 1 dahdi
iptable_filter 3100 0
ip_tables 11692 1 iptable_filter
x_tables 16544 1 ip_tables
snd_intel8x0 30168 0
snd_ac97_codec 101216 1 snd_intel8x0
ppdev 6688 0
ac97_bus 1532 1 snd_ac97_codec
psmouse 56180 0
snd_pcm 75488 2 snd_intel8x0,snd_ac97_codec
serio_raw 5280 0
snd_timer 22276 1 snd_pcm
lp 8964 0
i2c_piix4 10124 0
snd 59204 4 snd_intel8x0,snd_ac97_codec,snd_pcm,snd_timer
parport_pc 32228 0
soundcore 7264 1 snd
snd_page_alloc 9252 2 snd_intel8x0,snd_pcm
parport 35340 3 ppdev,lp,parport_pc
pcnet32 33156 0
mii 5212 1 pcnet32
floppy 54980 0
root@capsula:~/lkm#

Blz nosso lkm subiu sem erro e podemos ver ele carregado quando executamos o comando lsmod(list modules). Subimos o módulo e como sabemos se o nosso módulo funcionou?? Para isso iremos usar o comando dmesg utilitário que exibe as mensagens de inicialização e vindas do kernel.


root@capsula:~/lkm#
.....
[ 105.300548] eth0: link up, 100Mbps, full-duplex
[ 115.782079] eth0: no IPv6 routers present
[13593.784665] hello_world: module license 'unspecified' taints kernel.
[13593.785548] Disabling lock debugging due to kernel taint
[13593.785716] Hello world 1.
root@capsula:~/lkm#

Notem a mensagem hello world nosso módulo subiu perfeitamente notem tambem a mensagem “hello_world: module license ‘unspecified’ taints kernel.” isso é uma forma de indicar que nosso módulo foi inserido no kernel sem uma declaração de licença explicita, o que falta é uma declaração da licença usada pelo módulo. Para isso usamos a macro.


MODULE_LICENSE("GPL");

Adicione o código acima ao fonte e recompile o módulo. após isso a mensagem de “hello_world: module license ‘unspecified’ taints kernel.” irá sumir. Com essa declaração de licença GPL nosso módulo terá acesso aos símbolos do kernel GPL, isso é feito para garantir que tudo dentro do kernel seja GPL 😀

Agora iremos remover nosso módulo das entranhas do kernel para isso outro utilitário rmmod


root@capsula:~/lkm# rmmod hello_world
root@capsula:~/lkm# dmesg
....
[ 105.300548] eth0: link up, 100Mbps, full-duplex
[ 115.782079] eth0: no IPv6 routers present
[16057.727314] Hello world 1.
[17080.476439] Goodbye world 1.
root@capsula:~/lkm#

Nossa este post estava ficando gigante, espero ter conseguido passar o assunto de forma objetiva. Qualquer dúvidas em relação ao assunto e claro se eu souber basta perguntar 😀

Até a próxima.

Categories: kernel