Mostrando postagens com marcador admin. Mostrar todas as postagens
Mostrando postagens com marcador admin. Mostrar todas as postagens

quinta-feira, 6 de setembro de 2012

Fazendo Mágica com NAT no iptables

O GNU/Linux é um sistema operacional tão poderoso que nos permite interferir no tráfego da interface de rede de forma simplesmente mágica através de ferramentas de rede como iptables.

O iptables é muito conhecido na implementação de firewalls no Linux. Todavia, ele oferece muitos outros recursos, e dentre eles o redirecionamento de pacotes.

Para demonstrar esse potencial, ilustraremos duas situações interessantes:

  1. redirecionar a porta TCP 81 para a 80 na mesma máquina
  2. redirecionar a porta TCP 5436 local para a 5432 de máquina em outra rede

Serão considerados 10.220.10.62/16 como endereço IP local e 10.1.2.71/16 como endereço IP remoto. Atenção: a maioria das instruções citadas neste artigo deve ser executada pelo "root" ou outro usuário com poderes de super-vaca!

Antes de qualquer coisa, devemos nos certificar de que as regras existentes do NAT no iptables tenham sido reinicializadas. Para limpar as tabelas e cadeias (chains) e zerar os respectivos contadores, executamos as instruções a seguir:

iptables -t nat -F
iptables -t nat -X
iptables -t nat -Z

O redirecionamento de portas locais pode ser feito com o alvo (target) REDIRECT.

O REDIRECT redireciona o pacote para a própria máquina alterando o IP de destino para o endereço primário da interface de entrada (pacotes gerados localmente são mapeados para o endereço 127.0.0.1).

Assim, afim de redirecionar a porta TCP 81 para a 80 na mesma máquina, executamos:

iptables -t nat -A PREROUTING -p tcp --dport 81 -j REDIRECT --to-port 80

É interessante analisar se o tráfego está chegando à essa porta 81. Para isso, podemos usar o alvo LOG, o qual provocará a inclusão de uma entrada no /var/log/syslog a cada requisição.

O alvo LOG liga o registro dos pacotes que se encaixam em determinado critério pelo log do kernel (o qual pode ser lido com dmesg ou syslogd). É extremamente útil para ser usado em conjunto com regras que descartam o pacote (i.e., alvos DROP ou REJECT).

Para o nosso caso, basta executar a instrução a seguir para habilitar o log:

iptables -t nat -A PREROUTING -p tcp --dport 81 -j LOG --log-prefix "[Porta 81] "

Executamos o comando abaixo para verificar as regras aplicadas à tabela NAT do iptables:

iptables -t nat -L -n -v

Para testar se o redirecionamento está acontecendo como esperado, abra um novo terminal e execute a instrução a seguir para acompanhar no log do Linux as requisições que chegam à porta 81:

tail -f /var/log/syslog | grep 'Porta 81'

Para este caso, o teste deve ser disparado de uma máquina externa, digamos, do endereço 10.220.8.250/16. Podemos usar o telnet executando essa instrução:

telnet 10.220.10.62 81

Como se trata de um serviço Web, outra opção é usar o próprio protocolo HTTP, através da ferramenta curl. Eis um exemplo:

curl -v http://10.220.10.62:81/

Fácil, não?! Vejamos agora a segunda situação, um pouco mais complicada.

O redirecionamento de IPs precisa ser habilitado no kernel do Linux. Para fazer isso, basta executar esse comando:

echo 1 > /proc/sys/net/ipv4/ip_forward

Para garantir que esse parâmetro do kernel esteja ligado durante uma possível reinicialização da máquina, uma sugestão é adicionar tal configuração no sysctl.conf:

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

Voltando ao iptables, usaremos um outro alvo, o DNAT.

O DNAT determina que o endereço de destino deve ser modificado (assim como todos os demais pacotes da respectiva conexão) e as regras devem parar de ser examinadas.

Assim, para redirecionar a porta 5436 local (10.220.10.62) para a 5432 de outra máquina (10.1.2.71), executamos:

iptables -t nat -A PREROUTING -s 10.220.0.0/16 -p tcp --dport 5436 -j DNAT --to-destination 10.1.2.71:5432

A opção "-s" restringe a origem dos pacotes à subrede da máquina local. Como estamos redirecionando o pacote para uma máquina em outra subrede, precisamos usar o alvo MASQUERADE.

iptables -t nat -A POSTROUTING -j MASQUERADE

Da mesma forma que no caso anterior, podemos ligar o log do Linux para capturar as requisições nessa porta TCP:

iptables -t nat -A PREROUTING -p tcp --dport 5436 -j LOG --log-prefix "[Porta 5436] "

E em seguida acompanhar as mudanças através desse comando:

tail -f /var/log/syslog | grep 'Porta 5436'

Para testar essa nova regra, abra um terminal em outra máquina na mesma subrede e use o telnet:

telnet 10.220.10.62 5436

Como trata-se de um serviço do SGBD PostgreSQL, podemos testar definitivamente usando o cliente psql:

psql -h 10.220.10.62 -p 5436 -U usuario banco

Uma alternativa para acompanhar o tráfego de rede nessas regras de NAT no iptables é a ferramenta tcpdump. Através dela podemos visualizar os IPs com setas mostrando a direção do tráfego, e com isso verificar se as requisições estão chegando e se as respectivas respostas estão voltando.

Por exemplo, para analisar o tráfego que chega à porta 5436 local, podemos usar:

tcpdump -n -i eth0 port 5436

Já para verificar as requisições entre a máquina local e a máquina remota, uma opção seria:

tcpdump -n -i eth0 host 10.1.2.71

Muito simples e prático!

quarta-feira, 19 de outubro de 2011

A Linux trick on Oracle setup

Have you ever tried to install Oracle Database on GNU/Linux and faced the insufficient memory issue below?
Oracle Database 10g Express Edition requires 1024 MB of swap space. This system has ??? MB of swap space.
Well, I've just been caught by that when attempting to set it up on a virtual machine.
# dpkg -i oracle-xe-universal_10.2.0.1-1.1_i386.deb
(Reading database ... 125364 files and directories currently installed.)
Unpacking oracle-xe-universal (from oracle-xe-universal_10.2.0.1-1.1_i386.deb) ...
This system does not meet the minimum requirements for swap space.  Based on 
the amount of physical memory available on the system, Oracle Database 10g 
Express Edition requires 1024 MB of swap space. This system has 1019 MB 
of swap space.  Configure more swap space on the system and retry the installation.
dpkg: error processing oracle-xe-universal_10.2.0.1-1.1_i386.deb (--install):
 subprocess new pre-installation script returned error exit status 1
Errors were encountered while processing:
 oracle-xe-universal_10.2.0.1-1.1_i386.deb
Fortunately a true Operating System can handle it seamlessly! Here are the steps I followed.
Setup is claiming about just 5 megabytes... Well, let's give him it. But no more and no less! Let's create a zeroed dummy file with dd:
# dd if=/dev/zero of=5m.swp bs=1M count=5
5+0 records in
5+0 records out
5242880 bytes (5.2 MB) copied, 0.0132488 s, 396 MB/s
Here you go, an exactly 5 MB size zeroed file:
# ls -la 5m.swp 
-rw-r--r-- 1 root root 5242880 2011-10-19 10:39 5m.swp
Let's check out the available memory in the system using free:
# free
             total       used       free     shared    buffers     cached
Mem:       1026080     921612     104468          0      27036     674936
-/+ buffers/cache:     219640     806440
Swap:      1046524       2552    1043972
Alright, you need it, we'll give you:
# swapon 5m.swp
Are you satisfied now?
# free
             total       used       free     shared    buffers     cached
Mem:       1026080     921736     104344          0      27044     674936
-/+ buffers/cache:     219756     806324
Swap:      1051640       2552    1049088
Let's retry running Oracle installer:
# dpkg -i oracle-xe-universal_10.2.0.1-1.1_i386.deb
(Reading database ... 125364 files and directories currently installed.)
Unpacking oracle-xe-universal (from oracle-xe-universal_10.2.0.1-1.1_i386.deb) ...
That's it! Although that ridiculous additional 5 MB swap won't be automatically available for the next reboot, we still can tune Oracle to allocate less memory than standard settings.

terça-feira, 21 de dezembro de 2010

Buscar diferenças entre diretórios



Eis um problema que já tive que enfrentar diversas vezes: alterar um parâmetro de configuração que não sabia onde estava! Ou ainda: investigar o que foi alterado em algo que antes funcionava e passou a dar problema.

Como na informática tudo gira em torno de 0s e 1s, se algo mudou, tem que haver diferença entre arquivos e ou diretórios. Digamos que você possua dois diretórios contendo parâmetros de configuração de determinado software. Um deles funciona, o outro não. Como saber o que há de diferente entre eles?

Richard Stallman, junto com outros colaboradores da GNU nos proveu o utilitário diff no Linux (ou melhor, GNU/Linux), o qual permite a comparação entre dois arquivos de texto ou binários. O problema é que esse comando precisa ser invocado para cada par de arquivos, o que pode se tornar um complexo "trabalho de estagiário" dependendo da quantidade de subdiretórios e arquivos considerados.

Para atacar essa questão, criei o script em Shell diffdirs.sh contendo o código a seguir:

#!/bin/bash

if [ $# -ne 2 ]
then
    echo "Uso: $0 <dir1> <dir2>"
    exit 1
fi

dir1="$1"
dir2="$2"
list="/tmp/$$.list"
cont="/tmp/$$.cont"

cd $dir1
find -type f | sed 's/^\.\///' > $list
cd - > /dev/null

echo "Analisando diferenças entre diretórios:"
echo "- $dir1"
echo "- $dir2"

while read arq
do
    if ! diff $dir1/$arq $dir2/$arq > $cont
    then
        echo -e "\n$arq:"
        cat $cont
    fi
done < $list

rm -f $list $cont

exit 0


No caso em questão, precisava saber em qual diretório e arquivo residia uma configuração específica da IDE Eclipse. Como não dispunha de ambiente gráfico, a opção foi fazer tudo em modo texto. E esse script resolveu o problema! Veja o resultado exibido após a sua execução:

$ ./diffdirs.sh 
Uso: ./diffdirs.sh <dir1> <dir2>

$ ./diffdirs.sh ws35a/ ws35b/


Analisando diferenças entre diretórios:
- ws35a
- ws35b

.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache:
Os arquivos binários ws35a/.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache e ws35b/.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache são diferentes

.metadata/.plugins/org.eclipse.core.runtime/.settings/org.maven.ide.eclipse.prefs:
1c1
< #Tue Dec 21 09:47:38 AMT 2010
---
> #Tue Dec 21 09:48:27 AMT 2010
3d2
< eclipse.m2.downloadSources=true
10d8
< eclipse.m2.downloadJavadoc=true


Agora é só copiar o script para um diretório no PATH do usuário. :D

sexta-feira, 24 de setembro de 2010

Assembling a local Cassandra cluster in Linux



In order to build a Apache Cassandra [1] cluster exclusively for availability and replication testings, here is a simple solution, based on a single Linux instance, with no virtualization at all.

The idea is to initialize every node, run a testing client, and then manually kill some nodes processes in order to check the service continuous availability and data replication with several replication factors.

Cassandra's last stable version at this post date was 0.6.5, and this is the released considered in the study.

Thinking of a cluster using 3 nodes, we'll create the following file system structure on Linux:

/opt/apache-cassandra-0.6.5/nodes
|
|-- node1
|   |-- bin
|   |-- conf
|   |-- data
|   |-- log
|   `-- txs
|
|-- node2
|   |-- bin
|   |-- conf
|   |-- data
|   |-- log
|   `-- txs
|
`-- node3
    |-- bin
    |-- conf
    |-- data
    |-- log
    `-- txs


That is, each node has its own set of directories, namely:
- bin: binaries (mostly Shell Scripts) tuned for the instance
- conf: configuration files for the node
- data: database binary files
- log: system log in text format
- txs: transaction logs (i.e. commit logs)

In the following sections the steps will be described in detail.


Cassandra installation



First of all, get the required packages for Cassandra from its download site. Extract the file contents into /opt/apache-cassandra-0.6.5/ directory (you'll need administrator privileges in order to do so). Make sure your regular user owns this entire directory tree (use chown if needed).

Certify that you already has Java Virtual Machine (JVM) installed on the system, at least version 1.6. Cassandra is implemented in Java, so it needs JVM to be executed.


Supplying additional network interfaces



As we are building a pseudo-cluster, consider there are no more network interfaces than existing ones. Since Cassandra is a distributed system, their participant nodes must have an exclusive IP address each one. Fortunately we can simulate it on Linux using aliases to the existent loopback interface (i.e., "lo").

Therefore, using root user, we'll issue the instructions below in order to create the aliases lo:2 and lo:3, respectively pointing to 127.0.0.2 and 127.0.0.3:

# ifconfig lo:2 127.0.0.2 up
# ifconfig lo:3 127.0.0.3 up


You can check the overcome of these instructions by invoking ifconfig using no arguments:

$ ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:30848 errors:0 dropped:0 overruns:0 frame:0
          TX packets:30848 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:2946793 (2.9 MB)  TX bytes:2946793 (2.9 MB)

lo:2      Link encap:Local Loopback
          inet addr:127.0.0.2  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1

lo:3      Link encap:Local Loopback
          inet addr:127.0.0.3  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1


That way, node1's IP is 127.0.0.1, node2's 127.0.0.2, and so forth.


Registering node hostnames locally



Instead of using IP addresses in the sequential steps, we'll assign hostnames to them and use those names when referencing a cluster node.

As we have no DNS in this configuration, we need to edit /etc/hosts file and assign those IP mappings there. Change this file according to the example below:

/etc/hosts:
127.0.0.1    localhost    node1
127.0.0.2    node2
127.0.0.3    node3


From now on, we'll call the nodes simply as node1, node2, and node3. In order to finally test hostnames, try pinging the nodes as exemplified:

$ ping node2
PING node2 (127.0.0.2) 56(84) bytes of data.
64 bytes from node2 (127.0.0.2): icmp_seq=1 ttl=64 time=0.018 ms
64 bytes from node2 (127.0.0.2): icmp_seq=2 ttl=64 time=0.015 ms
^C
--- node2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.015/0.016/0.018/0.004 ms



Creating the first node structure



We'll first create the directory structure for node1 and after replicate it to remaining nodes. Switch to Cassandra's root directory, create subdirectories and copy files by issuing the following shell commands using your regular Linux user:

$ cd /opt/apache-cassandra-0.6.5/
$ mkdir -p nodes/node1
$ cp -R bin/ conf/ nodes/node1/
$ cd nodes/node1


The next step is to modify some default settings in the configuration files. Here I opted to use relative paths instead of absolute paths for simplification purposes.

Edit a single line in conf/log4j.properties file.

# Edit the next line to point to your logs directory
log4j.appender.R.File=./log/system.log


Now in conf/storage-conf.xml several tag values must be changed. Be sure to modify the correct tags, as indicated below:

  <Keyspaces>
    <Keyspace Name="Keyspace1">
      ...

      <ReplicationFactor>2</ReplicationFactor>
      ...

    </Keyspace>
  <Keyspaces>
  ...

  <CommitLogDirectory>./txs</CommitLogDirectory>
  <DataFileDirectories>
      <DataFileDirectory>./data</DataFileDirectory>
  </DataFileDirectories>
  ...

  <ListenAddress>node1</ListenAddress>
  <StoragePort>7000</StoragePort>
  ...

  <ThriftAddress></ThriftAddress>
  <ThriftPort>9160</ThriftPort>
  <ThriftFramedTransport>false</ThriftFramedTransport>
  ...


As we are building a special directory arrangement, we'll need to adequate some paths in the scripts. Thus, edit the file bin/cassandra.in.sh by providing the lines below appropriately:

for jar in $cassandra_home/../../lib/*.jar; do
    CLASSPATH=$CLASSPATH:$jar
done


The first node is finally concluded. So, let's turn our attentions to the other two nodes.


Creating the remaining nodes



We are gonna take advantage of the first node directory structure to create the two remaining nodes. Thus, issue the instructions below in order to perform the cloning:

$ cd /opt/apache-cassandra-0.6.5/nodes/
$ mkdir node2 node3
$ cp -R node1/* node2
$ cp -R node1/* node3


When you're done, call a tree command (if available) as illustrated below to check the whole structure:

$ tree -L 2
.
|-- node1
|   |-- bin
|   `-- conf
|-- node2
|   |-- bin
|   `-- conf
`-- node3
    |-- bin
    `-- conf


If you compare this structure to the other one in the beginning of this article, you should note that there are some subdirectories missing (i.e., log, data, txs). That's because they will be created automatically when the server starts up the first time.


Final settings on nodes



The first node is deemed a contact point, i.e., a seed. Other nodes should start the Gossip-based protocol by connecting to it.

Besides, we should make specific settings on each node. Firstly, each node must listen to it's own hostname (i.e., node1, node2, node3). Thus, edit the nodeX/conf/storage-conf.xml for each node by replacing the line below (this example applies to node2):

  <ListenAddress>node2</ListenAddress>


Monitoring on Cassandra is provided through JMX, listening to every host by default on TCP port 8080. As we are building the cluster on the same real instance, this is not possible anymore. Thus, JMX interfaces must be bound to the same host, but we must change the port on each node. Therefore, first node will be listening on 8081, node2 on 8082, and node3 on 8083.

This parameter is configured in nodeX/bin/cassandra.in.sh, so we must change only the port as exemplified below (applying to node2):

# Arguments to pass to the JVM
JVM_OPTS=" \
        -ea \
        -Xms1G \
        -Xmx1G \
        -XX:+UseParNewGC \
        -XX:+UseConcMarkSweepGC \
        -XX:+CMSParallelRemarkEnabled \
        -XX:SurvivorRatio=8 \
        -XX:MaxTenuringThreshold=1 \
        -XX:+HeapDumpOnOutOfMemoryError \
        -Dcom.sun.management.jmxremote.port=8082 \
        -Dcom.sun.management.jmxremote.ssl=false \
        -Dcom.sun.management.jmxremote.authenticate=false"



Starting up every server



For this step it is very interesting to open a new Linux terminal for each node. Thus, issue the instructions below:

$ node1/bin/cassandra -f

$ node2/bin/cassandra -f

$ node3/bin/cassandra -f


Pay attention to the console output on each node. A simple misconfiguration will be related there. Also note the relationship between the nodes. They must discover one another automatically in seconds.


Check services availability



Since every node in the cluster is up and running, their respective TCP ports must appear to the system when executing a netstat command.

In order to check listening TCP ports on Cassandra, one must search for 9160 (Thrift service), 7000 (internal storage), and 808X (JMX interface). Take a look at the example below of a successful cluster startup.

$ netstat -lptn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      -             
tcp6       0      0 127.0.0.3:9160          :::*                    LISTEN      8520/java     
tcp6       0      0 127.0.0.2:9160          :::*                    LISTEN      8424/java     
tcp6       0      0 127.0.0.1:9160          :::*                    LISTEN      8336/java     
tcp6       0      0 :::46954                :::*                    LISTEN      8424/java     
tcp6       0      0 :::53418                :::*                    LISTEN      8336/java     
tcp6       0      0 :::49035                :::*                    LISTEN      8520/java     
tcp6       0      0 :::80                   :::*                    LISTEN      -             
tcp6       0      0 :::42737                :::*                    LISTEN      8520/java     
tcp6       0      0 :::8081                 :::*                    LISTEN      8336/java     
tcp6       0      0 :::8082                 :::*                    LISTEN      8424/java     
tcp6       0      0 :::8083                 :::*                    LISTEN      8520/java     
tcp6       0      0 :::60310                :::*                    LISTEN      8424/java     
tcp6       0      0 :::46167                :::*                    LISTEN      8336/java     
tcp6       0      0 ::1:631                 :::*                    LISTEN      -             
tcp6       0      0 127.0.0.3:7000          :::*                    LISTEN      8520/java     
tcp6       0      0 127.0.0.2:7000          :::*                    LISTEN      8424/java     
tcp6       0      0 127.0.0.1:7000          :::*                    LISTEN      8336/java     


The last test was from a network perspective. You might want to ask Cassandra whether these nodes are talking to each other and participating on a healthy partitioning scheme. In order to do so, another checking is to invoke nodetool's ring command.

$ cd /opt/apache-cassandra-0.6.5/

$ ./bin/nodetool -h localhost -p 8081 ring
Address       Status     Load          Range                                      Ring
                                       142865723918937898194528652808268231850  
127.0.0.1     Up         3,1 KB        39461784941927371686416024510057184051     |<--|
127.0.0.3     Up         3,1 KB        54264004217607518447601711663387808864     |   |
127.0.0.2     Up         2,68 KB       142865723918937898194528652808268231850    |-->|


Here it is, the local cluster is up and running with three nodes! :D




You can also check Cassandra's availability by using its simple client application:

$ ./bin/cassandra-cli --host node1 --port 9160
Connected to: "Test Cluster" on node1/9160
Welcome to cassandra CLI.

cassandra> set Keyspace1.Standard1['rowkey']['column'] = 'value'
Value inserted.

cassandra> get Keyspace1.Standard1['rowkey']['column']          
=> (column=636f6c756d6e, value=value, timestamp=1285273581745000)

cassandra> get Keyspace1.Standard1['rowkey']          
=> (column=636f6c756d6e, value=value, timestamp=1285273581745000)
Returned 1 results.

cassandra> del Keyspace1.Standard1['rowkey']                    
row removed.


As we set replication factor to 2 for this given keyspace Keyspace1, it is expected that each value saved in the Cassandra cluster is replicated to two nodes.

Do you really believe it is happening? If not, save another value (using set) and then kill one of the three node processes. Do not kill more than one! Then, retrieve that key again (using get). The system should be capable of automatically recovering from this intentional disaster.

You can easily make a node participate in the cluster again just by executing its respective bin/cassandra command. Take a look at all console outputs after every step, they are very interesting!


References



[1] Apache Cassandra


quarta-feira, 10 de fevereiro de 2010

Configurando Bash Completion no Debian



O bash completion é uma poderosa ferramenta para administradores Linux que utilizam o shell para realizar suas tarefas, permitindo com que comandos, caminhos de arquivos e mesmo parâmetros específicos sejam autocompletados. Em geral essa feature é habilitada por padrão no Linux, porém em algumas distribuições, tal como no Debian, é preciso configurá-la manualmente. Este é justamente o tema do artigo em questão.

Antes de qualquer coisa, certifique-se de que o pacote bash-completion esteja instalado, executando a instrução a seguir:


# apt-get install bash-completion

Em seguida, é preciso indicar a utilização do bash-completion no perfil do bash. Isso pode ser feito individualmente para cada usuário, através do arquivo ~/.bash_profile, ou para todo o sistema. Para essa segunda opção, modifique o arquivo /etc/bash.bashrc, usando um editor qualquer:


# vi /etc/bash.bashrc

Verifique se as seguintes linhas estão incluídas no arquivo de configurações. Inicialmente elas já existem, porém estão comentadas (i.e. iniciadas com o caracter "#"):


# enable bash completion in interactive shells
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi

A última etapa consiste em testar se o mecanismo de autocomplemento está funcionando. Para isso, é preciso sair da sessão (i.e. fazer um log out do terminal) e iniciar um novo login. Feito isso, tente digitar a inicial de algum comando (ex: service) e em seguida pressionar a tecla TAB uma vez:


# serv<TAB>

Agora que o comando "service" foi autocompletado, pressione a tecla TAB mais duas vezes para que a respectiva lista de seus possíveis parâmetros seja exibida na tela:


# service <TAB>
hwclock networking skeleton udevtrigger
apache2 hwclock-save ondemand umountfs
bootlogd keyboard-setup postfix rsyslog
console-setup procps udev umountroot
dmesg rc sendsigs urandom
halt nagios3 rc.local single

Caso o comando possua múltiplos argumentos, como é o caso do "service", podemos utilizar o TAB mais uma vez, o que fará com que apenas instruções que façam sentido sejam listadas:


# service nagios3 <TAB>
force-reload reload restart start status stop

Agora é só digitar a inicial do argumento, pressionar TAB mais uma vez e executar de vez a instrução completa:


# service nagios3 status
* checking /usr/sbin/nagios3... [OK]

Pronto! Bem fácil, né?


segunda-feira, 7 de dezembro de 2009

PostgreSQL monitoring on ZABBIX



I've recently started to get to know ZABBIX [1] a little deeper, especially regarding PostgreSQL database servers monitoring. At first sight I thought it an incredible monitoring and notification system as it fulfills most of the requirements I wondered to have in Cedrus [2].

After setting up some basic OS-related items to be monitored, I was searching for PostgreSQL specific configurations and then I found a wiki [3] on ZABBIX UserParameters. It is indeed very simple! You just need to create SQL statements and then invoke them with psql. If successful, you could append the corresponding lines into ZABBIX agent configuration file and restart it. Then, in the front-end application, what is left to do is to properly set these PostgreSQL parameters to a given host.

I've created some additional parameters I always use in PostgreSQL instances in order to monitor the server health. In this case, I previously created a user called "zabbix" and a database with same name on PostgreSQL.

Here are the included lines on /etc/zabbix/zabbix_agentd.conf:


# PostgreSQL custom parameters

# instance version
UserParameter=pgsql.version,psql -U zabbix zabbix -Atc 'select version()'

# instance databases summary
UserParameter=pgsql.db.summary,psql -c "select a.datname, pg_size_pretty(pg_database_size(a.datid)) as size, cast(blks_hit/(blks_read+blks_hit+0.000001)*100.0 as numeric(5,2)) as cache, cast(xact_commit/(xact_rollback+xact_commit+0.000001)*100.0 as numeric(5,2)) as success from pg_stat_database a order by a.datname"

# total databases size
UserParameter=pgsql.db.totalsize,psql -Atc "select sum(pg_database_size(datid)) as total_size from pg_stat_database"

# specific database size (in bytes)
UserParameter=pgsql.db.size[*],psql -Atc "select pg_database_size('$1') as size"

# database cache hit ratio (percentage)
UserParameter=pgsql.db.cache[*],psql -Atc "select cast(blks_hit/(blks_read+blks_hit+0.000001)*100.0 as numeric(5,2)) as cache from pg_stat_database where datname = '$1'"

# database success rate (percentage)
UserParameter=pgsql.db.success[*],psql -Atc "select cast(xact_commit/(xact_rollback+xact_commit+0.000001)*100.0 as numeric(5,2)) as success from pg_stat_database where datname = '$1'"


After restarting ZABBIX Agent, you can check whether the added parameters are valid by issuing zabbix_get command in a shell. For instance, to query PostgreSQL instance version, type this:


$ zabbix_get -s localhost -k pgsql.version
PostgreSQL 8.3.3 on i486-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.3 (Ubuntu 4.2.3-2ubuntu7)

This other script returns an overview of existing databases in the instance, highlighting their names, size in disk, cache hit ratio and percentage of successful transactions:


$ zabbix_get -s localhost -k pgsql.db.summary
datname | size | cache | success
-------------+---------+-------+---------
auction5 | 4400 kB | 0.00 | 0.00
auditing | 4512 kB | 0.00 | 0.00
escola | 4656 kB | 0.00 | 0.00
postgres | 4223 kB | 99.81 | 100.00
rodrigo | 4144 kB | 0.00 | 0.00
template0 | 4144 kB | 0.00 | 0.00
template1 | 4144 kB | 0.00 | 0.00
zabbix | 10 MB | 99.99 | 100.00
zahle | 86 MB | 0.00 | 0.00
(9 registros)

In order to measure total space in disk occupied by the entire instance, this script should be used:


$ zabbix_get -s localhost -k pgsql.db.totalsize
1507326452

On the other hand, to retrieve the space (in bytes) occupied by a single database, you just need to specify its name in the parameter key, as exemplified below:


$ zabbix_get -s localhost -k pgsql.db.size[auction5]
4505604

Likewise, to recover cache hit ratio (in percentage) of a single database, use this key:


$ zabbix_get -s localhost -k pgsql.db.cache[zabbix]
99.99

The percentage of successful transactions in relation to all attempts is given by this parameter:


$ zabbix_get -s localhost -k pgsql.db.success[postgres]
100.00


After testing these parameters, it is time to set them up onto ZABBIX Frontend as illustrated below:



It is very interesting to further add some traps and actions based on the configured items. For example, to send an email to the DBA every time a given database grows up faster than expected or whether its cache ratio starts to lower significantly.

At Joe Uhl's blog there is a post [4] concerning using ZABBIX to monitor PostgreSQL TPS (Transactions per Second). It is an interesting source as it explains how to configure deltas and graphs in ZABBIX.

References:


[1] ZABBIX Monitoring Solution
[2] Cedrus: PostgreSQL Manager
[3] ZABBIX Wiki - PostgreSQL UserParameters
[4] Monitoring PostgreSQL TPS with Zabbix

terça-feira, 8 de setembro de 2009

Cedrus PostgreSQL Management versão 2.0




Pessoal, estou organizando esforços para o desenvolvimento da segunda geração do Cedrus [1], um gerenciador para o SGBD PostgreSQL criado em 2006 na CELEPAR e apresentado ao público no CONISLI [4] naquele mesmo ano em São Paulo.


Dessa vez será adotada a plataforma Launchpad para o gerenciamento do projeto. Se você tiver interesse em participar de qualquer das seguintes etapas (requisitos, projeto, desenvolvimento ou testes) ou se desejar somente dar sugestões, mesmo se você só tiver experiência com administração de outros SGBDs, sinta-se livre em conhecer o projeto [2] ou em fazer parte da equipe [3]!


Referências:


[1] Cedrus 1.0 no SourceForge
[2] Cedrus 2.0 no Launchpad
[3] Equipe do Cedrus no Launchpad
[4] CONISLI - Congresso Internacional de Software Livre

sexta-feira, 19 de junho de 2009

Testando HTTP sem usar um navegador



Um servidor WEB funciona utilizando o protocolo HTTP [1], e responde a requisições tais como "HTTP GET" vindas de um cliente (o browser).

Geralmente não vemos o que está sendo transmitido entre as duas partes: cliente (navegador) e servidor WEB. Entretanto, podemos facilmente inspecionar esse tráfego de dados através da ferramenta telnet [2], disponível em praticamente qualquer plataforma.

Para fazer o teste, primeiro abra um terminal no Linux ou um prompt de comando no Windows. Você vai precisar então digitar o comando com a seguinte sintaxe:

telnet [servidor] [porta]

Por exemplo, para acessar a página do Grupo de Usuários PostgreSQL do Brasil [3], execute o seguinte:

telnet postgresql.org.br 80

Com isso você estará conectado ao servidor WEB especificado e poderá desta forma executar qualquer comando do protocolo HTTP [4] desejado, tal como GET, HEAD ou POST.

Em seguida, para efetuar uma requisição HTTP do tipo GET ao servidor, você precisará executar um comando no seguinte formato:

GET [página] HTTP/1.0

Para exemplificar, faça uma simulação à esta página, digitando o texto a seguir no telnet:

GET /node/61 HTTP/1.0

Atenção: pressione ENTER duas vezes. Se a página existir no servidor, você terá como resultado algo como ilustrado na figura abaixo.




Preste atenção no cabeçalho (header) HTTP enviado pelo servidor após a execução. São justamente estes dados que o browser interpreta automaticamente e o usuário não vê.


HTTP/1.1 200 OK
Date: Sun, 21 Jun 2009 02:08:33 GMT
Server: Apache/2.2.9 (Debian) PHP/5.2.0-8+etch15 mod_ssl/2.2.9 OpenSSL/0.9.8g
X-Powered-By: PHP/5.2.0-8+etch15
Set-Cookie: SESSd41d8cd98f00b204e9800998ecf8427e=baefb8cb6bc0a5ed29340ec05aa6ff38; expires=Tue, 14 Jul 2009 05:41:54 GMT; path=/
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Sun, 21 Jun 2009 02:08:34 GMT
Cache-Control: store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
Connection: close
Content-Type: text/html; charset=utf-8


A primeira linha é uma das mais importantes do cabeçalho, pois ela indica se houve sucesso ou erro durante o atendimento da requisição HTTP. O código 200 no exemplo significa que a página HTML foi recuperada com sucesso.

Você pode ainda receber um código de status 404 caso a página não seja encontrada (ou seja, o famoso "Erro 404"), o código 301 se a página tiver sido movida permanentemente ou 401 caso você não tenha autorização para acessá-la.

A lista completa dos códigos de status do protocolo HTTP pode ser consultada aqui [5]. Se você é um administrador de sistemas ou desenvolvedor de aplicações WEB possivelmente esta abordagem lhe será útil. :D

O conteúdo HTML que será renderizado pelo browser vem logo após o cabeçalho.

Referências:
[1] http://pt.wikipedia.org/wiki/Http
[2] http://pt.wikipedia.org/wiki/Telnet
[3] http://postgresql.org.br
[4] Hypertext Transfer Protocol -- HTTP/1.0
[5] RFC 2616 - Status Code Definitions

quarta-feira, 25 de março de 2009

Meu PostgreSQL não conecta!


Começando do início...


Observação: Apesar de os testes terem sido feitos em ambiente Linux, os comandos (ping, telnet, psql) e arquivos de configuração (postgresql.conf, pg_hba.conf) existem e funcionam também no Windows, Macintosh ou FreeBSD, no respectivo terminal.

Antes de tudo, façamos alguns testes que respondem à algumas perguntas.

A máquina está no ar e é enxergada na rede pelo cliente?


Um simples "ping" pode nos ajudar:
$ ping 10.15.23.15
Se estiver tudo correto, aparecerá o texto abaixo:
rodrigo@asgard:~$ ping 10.15.23.15
PING 10.15.23.15 (10.15.23.15) 56(84) bytes of data.
64 bytes from 10.15.23.15: icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from 10.15.23.15: icmp_seq=2 ttl=64 time=0.034 ms
64 bytes from 10.15.23.15: icmp_seq=3 ttl=64 time=0.034 ms

--- 10.15.23.15 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.034/0.037/0.044/0.006 ms
Caso contrário, será exibido algo como:
rodrigo@asgard:~$ ping 10.15.23.150
PING 10.15.23.150 (10.15.23.150) 56(84) bytes of data.
From 10.15.23.15 icmp_seq=1 Destination Host Unreachable
From 10.15.23.15 icmp_seq=2 Destination Host Unreachable
From 10.15.23.15 icmp_seq=3 Destination Host Unreachable

--- 10.15.23.150 ping statistics ---
6 packets transmitted, 0 received, +3 errors,
100% packet loss, time 5008ms, pipe 3
Se este for o caso, resolva este problema de conexão e configuração de rede antes de continuar.

O servidor está respondendo ao serviço na porta do PostgreSQL?


Se não estiver, qualquer acesso externo ao PostgreSQL é barrado, e a seguinte mensagem será exibida:
psql: could not connect to server: Conexão recusada
Is the server running on host "10.15.23.15" and accepting
TCP/IP connections on port 5432?
Para comprovar isso, podemos fazer um simples teste com o "telnet":
$ telnet 10.15.23.15 5432
rodrigo@asgard:~$ telnet 10.15.23.15 5432
Trying 10.15.23.15...
telnet: Unable to connect to remote host: Connection refused
Este é um problema que ocorre com 5 de cada 4 iniciantes neste banco de dados: a conexão não-local!
Bom, o fato é que a configuração padrão do PostgreSQL faz com que apenas conexões locais (via soquete UNIX) sejam permitidas. O primeiro passo é alterar uma opção no arquivo de configurações postgresql.conf:















VersãoOriginalMudar para
7.X e anteriorestcpip_socket = falsetcpip_socket = true
8.X em diantelisten_addresses = 'localhost'listen_addresses = '*'

Após salvar o arquivo, será preciso reiniciar o SGBD (não basta apenas fazer um "reload").

Agora refaça o teste do "telnet". Terá que aceitar a conexão e aparecer este texto:
rodrigo@asgard:~$ telnet 10.15.23.15 5432
Trying 10.15.23.15...
Connected to 10.15.23.15.
Escape character is '^]'.
Dê um CTRL+C para sair. Se ainda não funcionar, será preciso verificar se firewalls não estão impedindo a conexão entre o cliente e o servidor, na porta do PostgreSQL (padrão: 5432). Resolva essa questão antes de continuar a leitura...

Opa! Metade do serviço está concluída! Agora, outro problema que atormenta quem está começando, este erro ao tentar se conectar:
$ psql -h 10.15.23.15 correios rodrigo
psql: FATAL:  nenhuma entrada no pg_hba.conf para máquina "10.15.22.32",
usuário "rodrigo", banco de dados "correios", SSL desabilitado
Sigamos a dica que o PostgreSQL nos dá! Abra o seguinte arquivo de configuração: pg_hba.conf.

Este arquivo controla: quais hosts têm permissão de conexão, como os clientes se autenticam, quais usuários do PostgreSQL podem ser usados e que bancos de dados eles podem acessar. Os registros podem ter uma das seguintes formas:

local      DATABASE  USER  METHOD  [OPTION]
host DATABASE USER CIDR-ADDRESS METHOD [OPTION]
hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTION]
hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTION]
Sendo assim, nestas entradas de permissões de acesso ao PostgreSQL, podemos alterar:
  • tipo de conexão ("local", "host")
  • banco de dados ("all": todos)
  • usuário ("all": todos)
  • endereço IP e máscara (estilo CIDR)
  • método ("reject", "trust", "password", "md5", "ident same user")

Importante: o arquivo é lido de cima para baixo, e a primeira entrada que esteja de acordo com a requisição é considerada. Isso é um fato que às vezes confunde os administradores. Os campos podem ser separados por espaços ou tabulações - tanto faz, funcionará de ambas as formas.

Bom, para resolver o problema em questão, precisamos incluir a seguinte linha:

host    correios    rodrigo        10.15.22.32/32        md5
Desta vez, não será preciso reiniciar o PostgreSQL. No Linux, podemos enviar um sinal do tipo HUP das seguintes maneiras:
$ /etc/init.d/postgresql-8.1 reload
$ killall -HUP postmaster
No Windows eu vou ficar devendo, mas deve ser algo como "recarregar o serviço".

Pronto! Simples, não?

Se você quiser, pode fazer com que o PostgreSQL funcione de modo promíscuo, adicionando a seguinte linha:

host    all    all        0.0.0.0/0        trust
Isso faz com que qualquer usuário, de qualquer IP acesse qualquer banco de dados, e sem necessidade de senha!

Se, ao invés de "trust" for usado "reject", todo acesso será fechado.

Lembre-se que, pelo padrão CIDR de endereçamento, diversos IPs podem ser
configurados com uma só linha! Por exemplo, ambas as linhas abaixo fazem
com que toda a subrede do IP 10.15.22.32/22 tenha acesso, por senha, ao
banco "correios":

host    correios    all        10.15.20.0/22        password
host correios all 10.15.22.32 255.255.252.0 password

Uma coisa interessante é restringir o acesso ao usuário "postgres", Senhor de Todo o Cluster, com a inclusão da seguinte linha:

local   all         postgres                          ident sameuser
Com isso, somente acesso local (via "ssh" e instrução "su - postgres") poderá ser feita com este super usuário, que tem permissão para fazer o que quiser em qualquer banco de dados.

sábado, 7 de março de 2009

Setting up Hamachi on Debian GNU/Linux


"LogMeIn Hamachi [1] is a VPN service that easily sets up in 10 minutes, and enables secure remote access to your business network, anywhere there's an Internet connection."

Hamachi is indeed a great tool for easily setting up VPNs! It creates a virtual network interface and all its configurations are made up with almost no need of user intervention.

For Windows users, a "Next-Next-Finish"-like setup executable is provided. Unix/Linux users, however, have no such facilities and should burn some neurons before putting it to work.

In this article I'll show some tips on how to build up the whole scenario on Debian GNU/Linux operating system, including installing Hamachi binaries, setting up required libraries, and deploying automatic initialization scripts.

First of all, you should download Hamachi binaries for Linux [2]. In the given URL, retrieve the most suitable binary for your processor (i.e. choose between an Intel Pentium or "others"). At the time of writing this very document, the current Hamachi release was 0.9.9.9-20.

For instance, I downloaded hamachi-0.9.9.9-20-lnx.tar.gz as my CPU was an AMD Sempron. I'll use this file name as the example from now on. Save the file on a proper Linux directory, say /usr/src.

Then, get into that destiny directory and extract all the zipped file contents using the following commands:

$ cd /usr/src
$ tar xvzf hamachi-0.9.9.9-20-lnx.tar.gz

Convention: Please observe that in the given notation the prefix "$" means a normal user prompt is needed, whereas a "#" prefix needs a root or superuser terminal to input the commands. Also, texts colored in red are user inputs. Its corresponding outputs are styled in blue.

You should note there is now a sub-directory called hamachi-0.9.9.9-20-lnx. Get into it and then switch to a super user account (i.e. "root" or any supercow-powered user).

$ cd hamachi-0.9.9.9-20-lnx
$ su

Although Hamachi can be set per user, in this case I'll set it up for the entire system, I mean, any user can make use of its networking services, and it will be configured for the "hamachi" account (to be created).

# make install

You should expect some output like this:

Copying hamachi into /usr/bin ..
Creating hamachi-init symlink ..
Compiling tuncfg ..
Copying tuncfg into /sbin ..

Hamachi is installed. See README for what to do next.

Perhaps you get stuck into dependencies, like OpenSSH or OpenSSL. If that is the case, install the required packages (e.g. by calling "apt-get install openssl") before proceeding and then try installing hamachi again. A nice try is to use ldd command onto "hamachi" or "tuncfg" binaries in order to have a clue of what file or package needs to be resolved.

Next, run the TUN/TAP device driver [3] configurator:

# ./tuncfg/tuncfg

This time if nothing comes out everything is alright. :)

The next step consists in generating the user crypto identity:

# hamachi-init

You will see the following output in the terminal:

Initializing Hamachi configuration (/root/.hamachi).
Please wait ..
generating 2048-bit RSA keypair .. ok
making /root/.hamachi directory .. ok

saving /root/.hamachi/client.pub .. ok

saving /root/.hamachi/client.pri .. ok

saving /root/.hamachi/state .. ok

Authentication information has been created.

Hamachi can now be started with
'hamachi start' command and then brought online with 'hamachi login'.

Voilà, all the required security keys (private and public) have just been generated on a hidden directory called .hamachi inside the user's home. Note that it is a highly encrypted 2048-bit RSA keypair!

Initialize manually the service by calling the instruction below:

# hamachi start

This single line should appear:

Starting Hamachi hamachi-lnx-0.9.9.9-20 .. ok

Next, it is desirable for you to set a Hamachi nick for the current client by typing:

# hamachi set-nick zangaro

In your case, replace "zangaro" by, say, the identification you usually give your computer.

Now you should put the daemon online and create an account by running this command:

# hamachi login

This simple message is expected:

Logging in ......... ok

If you have no network yet to join, you will need to create yours by typing:

# hamachi create Agajorte

Replace "Agajorte" by the name you will give your new network. A password will be prompted and then the network will be created.

If you are going to join an existing network, just type:

# hamachi join Agajorte

Then, to appear to other users, type this command:

# hamachi go-online Agajorte

Now, to list other members in the network and their respective status, type:

# hamachi list

By default peers' nicknames are not shown in the listing. In order to enable it, you will need to run this command:

# hamachi get-nicks

If you type "hamachi" without any arguments, the outcome is something like this:

Hamachi, a zero-config virtual private networking utility, ver 0.9.9.9-20

version : hamachi-lnx-0.9.9.9-20
pid : 5063
status : logged in
nickname : zangaro

Also, you could have Hamachi usage tips shown by running this command:

# hamachi help

If you successfully came so far, congratulations! We're half way to conclude the process...

You will now need to stop the daemon. Run this command:

# hamachi stop

As every secondary service in the UNIX world, Hamachi daemon could not be initialized using the superuser root account for security reasons. A so-called system user for this service will be created for Hamachi administration tasks. Type the following instruction to add an user called "hamachi" to /etc/passwd.

# adduser --system --disabled-password --no-create-home hamachi

Adding system user `hamachi' (UID 108) ...
Adding new user `hamachi' (UID 108) with group `nogroup' ...
Not creating home directory `/home/hamachi'.
zangaro:/home/rodrigo# id hamachi
uid=108(hamachi) gid=65534(nogroup) grupos=65534(nogroup)

Note that this user has no home directory. He won't need it.

Then, move the Hamachi first initialized configuration directory to /etc/hamachi. In order to let the superuser to still execute Hamachi operations, a symbolic link will be created. Finally, change /etc/hamachi directory and respective ownership to the newly added "hamachi" account. Here are the referenced commands:

# mv /root/.hamachi /etc/hamachi
# ln -s /etc/hamachi /root/.hamachi
# chown hamachi.hamachi /etc/hamachi/ -R

The next step is to develop a Shell Script to start and stop Hamachi daemon. Run this command:

# vi /etc/init.d/hamachi

Then type the instructions below:



#!/bin/bash
#
# hamachi This shell script takes care of starting and stopping hamachi.
# author: Rodrigo HJORT (http://agajorte.blogspot.com)
#
# chkconfig: 345 99 9
# description: hamachi is a zero-configuration VPN
#

PATH=/sbin:/bin:/usr/bin

HAMUSR=hamachi
HAMDIR=/etc/hamachi
HAMBIN=/usr/bin/hamachi

. /lib/lsb/init-functions

[ -f $HAMDIR/client.pri ] || exit 2
[ -f $HAMDIR/client.pub ] || exit 3

[ -f $HAMBIN ] || exit 4

do_start () {
echo "Starting hamachi..."
/sbin/tuncfg
call_daemon start
}

do_status () {
call_daemon
}

do_stop () {
echo "Stopping hamachi..."
killall tuncfg
call_daemon stop
}

call_daemon () {
su $HAMUSR -c "$HAMBIN -c $HAMDIR $1"
}

case "$1" in
start)
do_start
;;
stop)
do_stop
;;
restart)
do_stop
sleep 1
do_start
;;
status)
do_status
;;
*)
echo "Usage: hamachi {start|stop|restart|status}" >&2
exit 1
;;
esac

Give proper execution permissions to the script file by running the following command:

# chmod +x /etc/init.d/hamachi

Now you could perform a simple test by calling:

# /etc/init.d/hamachi

Usage: hamachi {start|stop|restart|status}

Then start the daemon:

# /etc/init.d/hamachi start

Starting hamachi...
Starting Hamachi hamachi-lnx-0.9.9.9-20 .. ok

And then retrieve the service status:

# /etc/init.d/hamachi status

Hamachi, a zero-config virtual private networking utility, ver 0.9.9.9-20

version : hamachi-lnx-0.9.9.9-20
pid : 4997
status : logged in
nickname : zangaro-lin

The most important fact to observe now is that Hamachi service is no longer bound to "root" superuser, but to its proper account: the "hamachi" system user.

# ps aux | grep ^hamachi

hamachi 5063 0.1 0.0 3104 804 ? S 01:42 0:00 /usr/bin/hamachi -c /etc/hamachi start

You could also restart the service by invoking this command:

# /etc/init.d/hamachi restart

Stopping hamachi...
Shutting down .. ok
Starting hamachi...
Starting Hamachi hamachi-lnx-0.9.9.9-20 .. ok

At last, you could stop the service by calling this:

# /etc/init.d/hamachi stop

Stopping hamachi...
Shutting down .. ok

Hold on, there is only one detail left to do!

It will be very interesting to have the service initialized automatically as the system starts, i.e. on Linux boot time. This is a responsibility for System-V, but usually its configuration is distribution-dependent. You should check out your Linux distro on how to do it.

As Debian environment was chosen for the tests, System-V style init script links were installed through update-rc.d command, as shown below:

# update-rc.d hamachi defaults 09 99

Adding system startup for /etc/init.d/hamachi ...
/etc/rc0.d/K99hamachi -> ../init.d/hamachi
/etc/rc1.d/K99hamachi -> ../init.d/hamachi
/etc/rc6.d/K99hamachi -> ../init.d/hamachi
/etc/rc2.d/S09hamachi -> ../init.d/hamachi
/etc/rc3.d/S09hamachi -> ../init.d/hamachi
/etc/rc4.d/S09hamachi -> ../init.d/hamachi
/etc/rc5.d/S09hamachi -> ../init.d/hamachi

Well, unless you care about your uptime or if you are sure about the configuration you made on Sytem-V, you might reboot your Linux to find out whether the entire effort was worthy. Bon courage !

Even if you have another kind of Linux, I hope most of information detailed in the present document are valuable for you. Please don't hesitate in scratching up some comments. :D

References:

[1] Hamachi Official Site, https://secure.logmein.com/products/hamachi/vpn.asp
[2] Hamachi for Linux Binaries, http://files.hamachi.cc/linux/
[3] TUN/TAP device driver, http://hamachi.cc/tuntap