Consultas DNS / DNS Queries

By pascal, August 1, 2010

Vou assumir que todos que vão ler esse artigo já sabem o básico sobre DNS, se não sabem podem começar aqui.

Os tipos mais comuns de registros DNS são:

  • A ( Address record ) Retorna um endereço IPv4, utilizado para mapear um hostname a um IP
  • CNAME ( Canonical Name record ) Alias de um registro para outro registro
  • PTR ( Pointer record) Retorna o nome do domínio correspondente ao IP, comumente usado para definir o dns reverso
  • SOA ( Start of Authority record ) Especifica informações sobre a zona, incluindo o ns primário, e-mail do administrador, e diversos “timers” relativos a tempo de atualização da zona
  • MX ( Mail Exchange record ) Aponta quais máquina estão aptas a receber os e-mails para o domínio em questão
  • SPF ( Sender Police Framework record ) Define quem pode enviar emails em nome do domínio. Definido em cima de um registro TXT

Vejamos então, como consultar registros DNS utilizando as ferramentas host e dig, que acompanham por padrão a maioria das distribuições linux atuais.

* Obter o ip de um domínio

pascal@fallout:~$ host terra.com.br
terra.com.br has address 200.154.56.80
terra.com.br mail is handled by 10 vip-us-br-mx.terra.com.

* Consultar o Address record de um sub-domínio

pascal@fallout:~$ dig +short conteudo.terra.com.br
200.154.56.66

* Consultar um CNAME

pascal@fallout:~$ dig +short CNAME esportes.terra.com.br
conteudo.terra.com.br.

* Contultar os registros MX do domínio

pascal@fallout:~$ dig +short MX gmail.com
20 alt2.gmail-smtp-in.l.google.com.
30 alt3.gmail-smtp-in.l.google.com.
40 alt4.gmail-smtp-in.l.google.com.
5 gmail-smtp-in.l.google.com.
10 alt1.gmail-smtp-in.l.google.com.

* Consultar os registos SPF do domínio

pascal@fallout:~$ host -t txt terra.com.br
terra.com.br descriptive text “v=spf1 ip4:200.176.10.0/23 ip4:200.176.2.0/23 ip4:200.154.152.0/24 ip4:208.84.242.0/23 include:tmp-spf.terra.com.br include:ti-spf.terra.com.br include:te-spf.terra.com.br -all”

* Consultando o DNS Reverso de um domínio a partir do IP

pascal@fallout:~$ host 200.154.56.80
80.56.154.200.in-addr.arpa domain name pointer www.terra.com.br.

Se você quiser verificar se os domínios e sub-domínios estão respondendo corretamente a partir de outro servidor DNS você pode fazê-lo adicionando @nameserver ao comando dig:

dig @8.8.8.8 +short A terra.com.br
dig @4.2.2.1 +short A terra.com.br

ou o nameserver no final do comando host:

host terra.com.br 8.8.8.8
host terra.com.br 4.2.2.1

Migração de usuários BSD para Linux

By pascal, July 28, 2010

Você pode converter contas de usuários de sistemas BSD para Linux sem grandes problemas, porem em alguns casos o linux não vai reconhecer as senhas que foram encriptadas utilizando o algorítimo blowfish. Em teoria, você pode saber o tipo de encriptação usada[1] verificando o começo da string:

$1$ = MD5
$2a$ = Blowfish
$5$ = SHA-256
$6$ = SHA-512
o resto é provavelmente do tipo DES

A forma de conversão é simples, mas vamos analisar antes uma linha representando um usuário no arquivo /etc/master.passwd:
josefina:7oxYHBMZv6jso:2353:203::0:0:Josefina da Silva:/home/users/karen:/bin/tcsh

Agora por extenso:
usuário:hash_da_senha:uid:gid:unused:changetime:expiração:geco:home:shell

Para converter uma aquivo de senhas bsd para linux, precisaremos dividir as linhas em master.passwd em dois arquivos: /etc/passwd a /etc/shadow

Segue o formato desses arquivos:
/etc/passwd:
pascal:x:1000:1000:pascal,,,:/home/pascal:/bin/bash
/etc/shadow:
pascal:$6$.FOJk4AsLnQ57aH3kR2hS2a03uIKu5A.iodD0:14803:0:99999:7:::

Uma descrição detalhada de cada campo pode ser vista aqui

De posse dessas informações, não fica tão difícil. Segue então, o link para um script em Python que vai realizar essa tarefa, como input ele recebe o arquivo master.passwd e group, e como output ele gera 3 novos arquivos: file-passwd, file-group, file-shadow


Download

Servindo repositórios do mercurial através do Nginx

By pascal, July 18, 2010

Publicar repositórios do mercurial via http não é difícil e pode ser feito de diversas maneiras.
Vou detalhar a mais simples delas.

# Instalar os pacotes necessários:

apt-get install nginx mercurial apache2-utils

Step #1: Criar os repositórios.

mkdir /srv/mercurial
hg init /srv/mercurial/nome_do_projeto_1
hg init /srv/mercurial/nome_do_projeto_2
hg init /srv/mercurial/nome_do_projeto_3

Step #2: Em cada projeto criado editar o arquivo .hg/hgrc

cat /srv/mercurial/nome_do_projeto_X/.hg/hgrc
[web]
push_ssl = false
allow_push = *
contact = email.de@contato.com
description = "Breve descrição do projeto"
name = "Nome do projeto"

Step #3: Criar a estrutura para gerenciar o hgserver

mkdir /srv/mercurial/config

crie os arquivos:

cat /srv/mercurial/config/start.sh
#!/bin/bash
#
hg serve --webdir-con hgweb.config -A access.log -d -E error.log \
                -p 44000 -a localhost  --pid-file server.pid


cat /srv/mercurial/config/stop.sh
#!/bin/bash
#
kill -9 `cat server.pid`
rm server.pid

Depois torne-os executáveis

chmod +x /srv/mercurial/config/{start.sh,stop.sh}

Step #4: Criar um subdomínio para o mercurial

cat /etc/nginx/sites-enabled/hg.tarzxvf.com
server {
    listen   80;
    server_name  hg.tarzxvf.com;
    access_log  /var/log/nginx/hg.tarzxvf.com.access.log;

    location / {
        auth_basic "Restricted";
        auth_basic_user_file /srv/mercurial/config/passwd;
        proxy_pass http://localhost:44000/;
    }
}

Step #5 Criar um usuário para acessar o repositório via Nginx

htpasswd -c /srv/mercurial/config/passwd SeuUsuario

Step #6 Startar os serviços
Levantar o hg server.

/srv/mercurial/config/start.sh

Dar um reload no nginx

/etc/init.d/nginx reload

Se tudo deu certo você já pode clonar o seu repositório

Dicas OpenLdap

By pascal, July 18, 2010

# Adicionar um grupo com múltiplos usuários
# Adicionar usuário a múltiplos grupos

dn: cn=professores,ou=groups,dc=universidade,dc=com,dc=br
objectClass: posixGroup
cn: professores
gidNumber: 201
memberUid: Joao
memberUid: Pedro

.

# utilizar uma senha de um arquivo /etc/passwd

userPassword: {crypt}07mJ6K7jS3R0E

.

# Buscar com ldapsearch

— (x) faz uma autenticação simples
— (LLL) remove comentários do resultado
— ldapsearch <opções> <base a ser consultado> <condição> <atributos a serem exibidos, se não for especificado, mostra todo os atributos
>

– exibe a dn do uid pascal, o cn e o gidNumber
# ldapsearch -xLLL -b dc=das,dc=ufsc,dc=br uid=pascal cn gidNumber
— exibe todos os atributos da dn do uid pascal
# ldapsearch -xLLL -b dc=das,dc=ufsc,dc=br uid=pascal
— exibe a dn de todos os objetos com o atributo objectClass do tipo posixGroup
# ldapsearch -xLLL -b dc=das,dc=ufsc,dc=br objectClass=posixGroup dn

.

# Adicionar um objeto (ex. usuários, grupos)

— (x) faz uma autenticação simples
— (D) faz o bind na dn especificada, no caso a dn do administrador
— (W) abre o prompt para entrar com o password ( por envolver escrita )
— (f) pede um arquivo como input

# ldapadd -x -D cn=admin,dc=das,dc=ufsc,dc=br -W -f groups.ldif

.

# Deletar um objeto (ex. usuários, grupos)

— (D) faz o bind na dn especificada, no caso a dn do administrador
— (W) abre o prompt para entrar com o password ( por envolver escrita )
— (f) pede um arquivo como input

# ldapdelete -D cn=admin,dc=das,dc=ufsc,dc=br -f groups_to_delete  -W

About bsd

By pascal, July 17, 2010

I’m currently managing a few open and free bsd machines, so here is some tips for myself.

– Install nano
# cd /usr/local/ports/editors/nano/ && make install clean

– Enable and disable pf
# pfctl -e
# pfctl -d

– Load and check a pf ruleset
# pfctl -f /etc/pf.conf ( load )
# pfctl -nf /etc/pf.conf ( check syntax )

– Check pf log using tcpdump ( tip by suinão )
# tcpdump -neti pflog0

Login via ssh sem senha

By pascal, July 17, 2010

Post para “Sysadmin for dummies”

“First of all, where the hell i use this thing!”

Por que ssh sem senha? Tem muita gente que não gosta dessa idéia, mas em certas casos pode ser útil. Por exemplo, em uma rede interna em que você quer ter acesso a um número grande de máquinas e não quer lembrar de todas as credenciais de acesso, você pode logar em uma máquina específca e apartir dela logar nas demais sem ter que lembrar senhas ou mesmo usuários. Qual o risco? Se alguem assumir o controle dessa máquina, poderá acessar todas as demais, por isso você deve caprichar na segurança.

Outra boa razão é poder automatizar scripts via ssh, sem precisar aderir a programas que irão manter sua preciosa senha em plain text. Enfim, existem boas razoes para usar e boas para não usar, mas esse artigo não é para filosofar sobre isso é para mostrar o how to do!

“Second of all, giving names to the male cows”

Existem dois tipos de chaves para conexão SSH, as chaves DSA e RSA, as chaves DSA só devem ser usadas no caso de o servidor SSH remoto ser uma versão antiga. Por padrão a chave RSA é mais segura e tem total compatibilidade com as versões recentes do openSSH.

Sendo assim, esse tutorial se baseia no uso de chaves RSA. A chave será gerada usando o padrão 2048 bits, outros tamanhos podem ser usados, porem 2048 bits é seguro o suficiente para 99.9% dos casos! E não!, por mais segurança que você precise, você não está enquadrado no 0.1% restante.

“Third of all, hands in pasta”

O nosso exemplo assume que você quer acesso ao servidor a partir do seu notebook usando o usuário local ‘eu’

Abra o console e digite:

eu@notebook:~$ ssh-keygen -t rsa

O resultado sera mais ou menos assim:

Generating public/private rsa key pair.
Enter file in which to save the key (/home/eu/.ssh/id_rsa): <enter para default>
Enter passphrase (empty for no passphrase): <enter para default>
Enter same passphrase again: <enter para default>
Your identification has been saved in /home/eu/.ssh/id_rsa.
Your public key has been saved in /home/eu/.ssh/id_rsa.pub.

Vamos imaginar que no servidor remoto, cujo host é ‘palmares.com’ você quer ter acesso a dois usuários, o ‘root’ e o usuário ‘joao’. Você deve logar no servidor e criar os seguintes arquivos:

/home/joao/.ssh/authorized_keys2
/root/.ssh/authorized_keys2

Dentro desses arquivos você coloca o conteúdo do arquivo /home/eu/.ssh/id_rsa.pub gerado no seu notebook. Dessa forma, sempre que você quiser acessar a partir do seu notebook o servidor remoto, usando seu usuário padrão (do notebook) você apenas precisa fazer:

eu@notebook:~$ssh root@palmares.com p/ usuário root
eu@notebook:~$ssh joao@palmares.com p/ usuário joao

para testar tente executar um comando remoto:

eu@notebook:~$ ssh joao@palmares.com pwd
eu@notbeook:~$ ssh root@palmares.com pwd

É isso.

Balanceamento de carga com Nginx

By pascal, March 28, 2010

# Esse post é essencialmente uma tradução deste aqui

O balanceamento de carga com nginx na sua forma mais básica funciona da seguinte maneira:

upstream servers  {
    server srv1.tarzxvf.com;
    server srv2.tarzxvf.com;
}

server {
    server_name www.tarzxvf.com;
    location / {
        proxy_pass http://servers;
    }
}

Esta configuração vai dividir a carga para tarzxvf.com entre srv1.tarzxvf.com e srv2.tarzxvf.com, cada um recebendo 50% das requisições.

ip_hash

O parâmetro ip_hash garante que o cliente que acessar seu site tenha todas as requisições atendidas pelo mesmo servidor. Caso o servidor falhe, o nginx transfere as requisições para outro servidor.

upstream  servers  {
    ip_hash;
    server   srv1.tarzxvf.com
    server   srv2.tarzxvf.com;
}

down

Se um dos servidores precisa ser removido temporariamente – digamos para uma manutenção preventiva, ou atualização do kernel – é possível definir o server como down.

upstream  server  {
    ip_hash;
    server   srv1.tarzxvf.com down;
    server   srv2.tarzxvf.com;
}

weight

O parâmetro weight(peso) permite dividir as requisições de forma não igualitária entre os servidores

upstream  servers  {
    server   srv1.tarzxvf.com weight=4;
    server   srv2.tarzxvf.com weight=1;
}

Essa configuração vai enviar 80% das requisições para o srv1.tarzxvf.com, enquanto o srv2.tarzxvf.com vai receber os 20% restantes.

max_fails and fail_timeout

O parâmetro max_fails define o número de tentativas falhas em um dado período definido por fail_timeout, antes do nginx considerar o servidor inoperante. Se não for setado um valor, o número de tentativas passa a ser 1. Se for setado como 0 essa checagem é desabilitada.
Se fail_timeout não for setado, o nginx assume o padrão: 10 segundos.

upstream  servers  {
    server   srv1.tarzxvf.com;
    server   srv2.tarzxvf.com max_fails=3  fail_timeout=30s;
}

Nessa configuração o nginx vai considerar srv2.tarzxvf.com inoperante se 3 requisições falharem em um período de 30 segundo.

backup

Se todos os servidores estiverem off ou ocupados, os servidores setados como backup serão utilizados.

upstream  servers  {
    server   srv1.tarzxvf.com max_fails=3;
    server   srv2.tarzxvf.com max_fails=3;
    server   srv3.tarzxvf.com backup;
}

Essa configuração envia 50% das requisições para srv1.tarzxvf.com e os outros 50% para srv2.tarzxvf.com. Caso srv1 e srv2 falhem 3 vezes, as requisições serão enviadas para srv3.

Servindo o wordpress através do Nginx

By pascal, March 10, 2010

News: Faz alguns dias que este blog está rodando em um VPS que aluguei na slicehost. Em um primeiro momento fiz a instalação Lamp padrão, contudo isso resultou em um pequeno inconveniente, consumo excessivo de memória ram:

# Consumo de memória com apache
mysql + apache2 rodando wordpress = 165 mb ram

Considerando que meu VPS tem apenas 256 mb de ram resolvi trocar o apache pelo nginx, o resultado foi bem agradável:

# Consumo de memória com nginx
mysql + fcgi + nginx rodando wordpress = 65 mb ram

O processo de instalação foi extremamente simples, e as configurações custaram alguns poucos momentos no google.

# Pacotes necessários:
apt-get install nginx mysql-server php5 php5-cgi php5-mysql spawn-fcgi

Arquivo de configuração do domínio no nginx
cat /etc/nginx/sites-enabled/tarzxvf.com

server {
    listen   80;
    server_name  tarzxvf.com www.tarzxvf.com;
    access_log  /var/log/nginx/tarzxvf.com.access.log;

    location / {
        root   /var/www/tarzxvf.com;
        index  index.html index.htm index.php;

        # this move feed requests to feedburner
        if ($http_user_agent !~ FeedBurner) {
            rewrite ^/feed/ http://feeds.feedburner.com/tarzxvf last;
        }

        # this serves static files that exist without running other rewrite tests
        if (-f $request_filename) {
            expires 30d;
            break;
        }

        # this sends all non-existing file or directory requests to index.php
        if (!-e $request_filename) {
            rewrite ^(.+)$ /index.php?q=$1 last;
        }
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/tarzxvf.com/$fastcgi_script_name;
        include fastcgi_params;
    }
}

Arquivo de inicialização do fcgi
cat /etc/init.d/spawn-fcgi

#! /bin/sh

### BEGIN INIT INFO
# Provides:          spawn-fcgi-php
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts FastCGI for PHP
# Description:       starts FastCGI for PHP using start-stop-daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=spawn-fcgi-php
PID=/var/run/spawn-fcgi-php.pid
DAEMON=/usr/bin/spawn-fcgi
DAEMON_OPTS="-f /usr/bin/php-cgi -a 127.0.0.1 -p 9000 -u www-data -g www-data -P $PID"

test -x $DAEMON || exit 0

set -e

case "$1" in
  start)
        echo "Starting $NAME: "
        start-stop-daemon --start --pidfile $PID --exec $DAEMON -- $DAEMON_OPTS
        echo "done."
        ;;
  stop)
        echo "Stopping $NAME: "
        start-stop-daemon --stop  --pidfile $PID --retry 5
        rm -f $PID
        echo "done."
        ;;
  restart)
        echo "Stopping $NAME: "
        start-stop-daemon --stop  --pidfile $PID --retry 5
        rm -f $PID
        echo "done..."
        sleep 1
        echo "Starting $NAME: "
        start-stop-daemon --start --pidfile $PID --exec $DAEMON -- $DAEMON_OPTS
        echo "done."
        ;;
  *)
        echo "Usage: /etc/init.d/$NAME {start|stop|restart}" >&2
        exit 1
        ;;
esac
exit 0

Uso da CPU (por núcleo) em Python ou parseando o /proc/stat

By pascal, July 9, 2009

Título alternativo: How to get CPU usage per core with python
Teste de indexação do google ;)

Mais um post para a série “Parseando o /proc” [1]. Dessa vez sem motivo explícito, apenas diversão!

Ambientes de testes:

  • Ubunto c/ 1 núcleo e Python 2.6
  • Ubunto c/ 2 núcleos e Python 2.6
  • CentOS c/ 4 núcleos e Python 2.4.
  • Comparei os resultados através do htop e obtive uma proximidade alta nos valores, as diferenças se dão provavelmente pelo momento e duração da medição!

    Quem puder testar em ambientes com mais núcleos ou uso intensivo da CPU e comparar com as ferramentas do sistema por favor me de um feedback

    E quem rir da qualidade do meu inglês nos comentários eu vou banir o ip! :)

    #!/usr/bin/env python
    import time
    import os
    
    # [ reference ]
    # Detect number of cpus
    # http://www.boduch.ca/2009/06/python-cpus.html 
    # Get cpu usage (But this example is not working 100%)
    # http://ubuntuforums.org/showpost.php?p=853257&postcount=4 
    
    INTERVAL = 2
    
    class CPUUsage:
        def __init__(self):
            self.cores = self.detectCPUs()
    
        def createCoreArray(self):
            cores = []
            for i in range(self.cores):
                cores.append("")
            return cores
    
        def detectCPUs(self):
            if hasattr(os, "sysconf"):
                if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
                    ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
                    if isinstance(ncpus, int) and ncpus > 0:
                        return ncpus
            return 1 # Default
    
        def getTimeList(self):
            core = self.createCoreArray()
    
            statFile = file("/proc/stat", "r")
            if not self.cores == 1:
                statFile.readline()
    
            # this FOR will split lines from proc/stat for every active core
            for cid in range(self.cores):
                # when have just one core, split a different range
                if self.cores == 1:
                    core[cid] = statFile.readline().split(" ")[2:7] # 2:6
                else:
                    core[cid] = statFile.readline().split(" ")[1:6] # 1:5
            statFile.close()
    
            # convert all itens in splited list from STR to INT for every core
            for i in range(len(core[0])):
                for cid in range(self.cores):
                    core[cid][i] = int(core[cid][i])
    
            # return the core list now with INT values inside their cpu values
            # like this: ([core,1,values],[core,2,values],[core,3,values]) 
            return core
    
        def deltaTime(self,interval):
            coreT1=self.createCoreArray()
            coreT2=self.createCoreArray()
    
            # get core TIME 1 state per core
            coreT1 = self.getTimeList()
            # wait X seconds to get new state core
            time.sleep(interval)
            # get core TIME 2 state per core
            coreT2 = self.getTimeList()
    
            #Get the diference of coreT2.item[i] and coreT1.item[i] for every core
            for i in range(len(coreT1[0])):
                for cid in range(self.cores):
                    coreT2[cid][i] -= coreT1[cid][i]
            return coreT2
    
        def Usage(self):
            core = self.createCoreArray()
            cpuUsage = []
    
            core = self.deltaTime(INTERVAL)
    
            for cid in range(self.cores):
                # sum of user,system and nice usage
                tmp_use = core[cid][0] + core[cid][1]+core[cid][2]
                # 100.00 * usage / sum of usage + idle + waiting 
                usage = "%.2f" % ((100.00 * tmp_use) / sum(core[cid]))
                cpuUsage.append(usage)
            return cpuUsage
    
    if __name__ == "__main__":
        # Show usage per core
        #print CPUUsage().Usage()
    
        x = 0
        for item in CPUUsage().Usage():
            x = x + 1
            print "CPU[%s]: %s" % (str(x),str(item))
    

    Como impedir a execução de scripts em pastas no servidor

    By pascal, July 8, 2009

    RemoveHandler .py

    Precisei disso para impedir a execução dos arquivos .py em uma pasta de um servidor, enquanto eu tentava por chute quase acertei a sintaxe :)

    De qualquer forma, basta colocar no .htaccess e está resolvido.

    E aqui achei várias dicas que podem ser úteis um dia!

    OfficeFolders theme by Themocracy