Sobre

Nosso objetivo é prover alguns scripts que podem ser usados para funções de consulta da tabela ARP e bloqueio/desbloqueio de MACs em máquinas GNU/Linux remotas. Para executar os comandos remotamente, será usado o protocolo SSH com autenticação baseada em chaves públicas. A configuração do SSH para esse ambiente será um pouco mais complexa que o usual, para que possamos aumentar a segurança do ambiente.

Durante essa documentação adotaremos a seguinte nomenclatura:

  • Máquina local: host no qual o L2M está instalado
  • Máquina remota: máquina na qual estaremos efetuando as consultas da tabela ARP e o bloqueio/desbloqueio de MACs (tipicamente, essa máquina é o firewall/roteador da sua rede).

Máquina Local

Por questões de segurança, é recomendado que o poller do L2M seja executado com um usuário não root. O usuário que fará as consultas na máquina remota é o mesmo do usado pelo script de poller do L2M (veja sua configuração do CRON para maiores detalhes). Vamos supor que esse usuário é o www-data.

Execute os seguintes comandos para criação de um par de chaves SSH, sem senha, que será usada na execução de comandos remotos:

su - www-data
ssh-keygen -N "" -f ~/.ssh/id_rsa

Esse comando deve gerar dois arquivos:

  • ~/.ssh/id_rsa: chave privada que deve ser guardada em segredo
  • ~/.ssh/id_rsa.pub: chave pública que será enviada para a máquina remota

Um exemplo do arquivo ~/.ssh/id_rsa.pub é como segue:

ssh-rsa AAAAB3NzaC1yc .... 9UhMcP8JjQ== www-data@gerencia

Configuração da máquina remota

Na máquina remota, certifique-se de que o login de root está permitido (pelo menos para execução de comandos: parâmetro PermitRootLogin forced-commands-only no sshd_config ).

Como root, execute os seguintes comandos (substitua a CHAVE pela chave publica SSH criada na máquina local, conforme passo anterior):

mkdir -p ~/.ssh
cat > ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1y....
CRTL+D

Agora, vamos restringir quais comandos podem ser executados com essa chave, para isso, edite o arquivo ~/.ssh/authorized_keys deixando-o parecido com o seguinte:

command="/usr/local/bin/check_ssh_cmd",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1y....

Precisaremos criar o arquivo de checagem. Para isso, crie o arquivo chamado /usr/local/bin/check_ssh_cmd com o seguinte conteúdo:

#!/bin/sh
case "$SSH_ORIGINAL_COMMAND" in
        *\&*)
                 echo "Rejected"
                 ;;
        *\(*)
                 echo "Rejected"
                 ;;
        *\{*)
                 echo "Rejected"
                 ;;
        *\;*)
                 echo "Rejected"
                 ;;
        *\<*)
                 echo "Rejected"
                 ;;
        *\`*)
                 echo "Rejected"
                 ;;
        "LANG=C /usr/sbin/arp -a -n")
                 $SSH_ORIGINAL_COMMAND
                 ;;
        "/usr/local/bin/drop-mac-iptables.sh"*)
                 $SSH_ORIGINAL_COMMAND
                 ;;
        *)
                 echo "Rejected"
                 ;;
esac

Falta ainda criarmos os scripts de bloqueio e desbloqueio dos MACs, que usam o firewall Netfilter/IPTables nativo do Linux. Para o script de bloqueio, crie o arquivo /usr/local/bin/drop-mac-iptables.sh com o seguinte conteúdo:

#!/bin/bash

ACTION="$1"
MAC="$2"
INTERFACE="$3"

CHAIN="DROP-MAC-L2M"
NAME="drop-mac-iptables.conf"
DIR="/usr/local/etc"

[ -d "$DIR" ] || mkdir -p $DIR

function usage(){
   echo "FAIL:USAGE $0 add|del|load  "
   exit 1
}

case "$ACTION" in
   add)
      if [ -z "$MAC" -o -z "$INTERFACE" ]; then
         usage
      fi
      if [ -s "$DIR/$NAME" ] && grep -q "$MAC,$INTERFACE" "$DIR/$NAME" >/dev/null 2>&1; then
         echo "OK:mac already blocked"
         exit 0
      fi
      echo "$MAC,$INTERFACE" >> "$DIR/$NAME"
      ;;
   del)
      if [ -z "$MAC" -o -z "$INTERFACE" ]; then
         usage
      fi
      [ -s "$DIR/$NAME" ] && sed -i "/$MAC,$INTERRFACE/d" "$DIR/$NAME"
      ;;
   load)
      ;;
   *)
      usage
      ;;
esac


iptables -L $CHAIN -n >/dev/null 2>&1
RES=$?
if [ $RES -eq 0 ]; then
   iptables -F $CHAIN
else
   iptables -N $CHAIN
   iptables -I FORWARD -j $CHAIN
   iptables -I INPUT -j $CHAIN
   iptables -A $CHAIN -j RETURN
fi

FAIL=0
if [ -s "$DIR/$NAME" ]; then
   for pair in `cat $DIR/$NAME`; do
      MAC=$(echo $pair | cut -d, -f1)
      INTERFACE=$(echo $pair | cut -d, -f2)
      iptables -I $CHAIN -i $INTERFACE -m mac --mac-source $MAC -j DROP >/dev/null 2>&1
      RES=$?
      if [ $RES -ne 0 ]; then
         FAIL=$((FAIL+1))
      fi
   done
fi

if [ $FAIL -gt 0 ]; then
   echo "FAIL:$FAIL fails"
else
   echo "OK"
fi
exit 0

Dê permissão de execução ao script:

chmod +x /usr/local/bin/drop-mac-iptables.sh

ATENÇÃO: duas coisas importantes que você deve verificar para manter as máquinas bloqueadas enquanto a máquina remota estiver executando são:

  • Carregamento dos bloqueios na inicialização. Você vai precisar configurar seu sistema para executar o script acima na inicialização com o parâmetro “load” (/usr/local/bin/drop-mac-iptables.sh load). Você pode fazer isso adicionando o script ao arquivo /etc/rc.local que é executado na inicialização do sistema na maioria das distribuições.
  • Compatibilidade com outros scripts de firewall. Caso você possua outros scripts de firewall na máquina, deverá verificar uma forma de carregar o script acima sempre que carregar o seu script original, garantindo que as regras de bloqueio de MAC serão aplicadas (geralmente os scripts de firewall fazem FLUSH de toda a tabela IPTables antes de iniciar).