Discuta este tópico no fórum

Se este conteúdo te ajudou, deixe um presente!

quarta-feira, 8 de maio de 2013

OpenWRT: Utilizando conexões wireless para ligar duas redes - conceitos


Como este post vai ficar um pouco longo, vou dividi-lo em partes. Nesta vou apresentar o problema. Nas próximas vemos as configurações.

Um dos problemas mais comuns de redes wireless é a cobertura do sinal. Vigas, vidro e diversas coisas desconhecidas podem prejudicar seu sinal. Além disto, o sinal do seu equipamento receptor pode não ser uma das melhores maravilhas. Notei isto logo que recebi minha SmartTV. A qualidade do sinal wireless é péssima. A solução para problemas de cobertura são basicamente: reposicionar seu roteador, melhorar a antena e aumentar a potência.


Também comprei um home theater que tem rede mas a wireless é paga "a parte", e muito cara. Isto é comum também nas TVs, mas não é o meu caso. Pelo preço, prefiro comprar outra coisa. Para solucionar o problema de cobertura e para substituir a necessidade de "módulo wireless", optei por adicionar um segundo roteador.

Roteador como AP


O que, em geral, temos em casa é um roteador wireless, que faz o papel de uma ponte da rede sem fio com as portas da rede LAN cabeada (função AP). A função "roteador" é composta de outras funcionalidades como NAT, DHCP, firewall, fazendo a interligação da rede LAN, cabeada ou sem fio, ao mundo externo, geralmente conectado na porta WAN. Portanto, um roteador wireless inclui as funções de um AP simples. Para usá-lo como somente um AP, basta não usar a porta WAN e desativar o DHCP (não preciso nem dizer que dois servidores DHCP ligados em uma mesma rede é receita para desastre). Isto é comum quando o roteador é fornecido pela telecom (roteador ADSL). Achei esta figura que ilustra como ficaria a conexão entre os dois roteadores (e um modem cabeado):


Fonte:https://lantechca.files.wordpress.com/2011/05/add-wireless-ap.png

Mas essa é a melhor forma de ligar os dois roteadores? Sim. E se eu ligar a LAN do roteador da esquerda na WAN do roteador da direira? Sim, pode funcionar. Se as redes LAN dos dois roteador não forem conflitantes (ex: 10.0.0.0/24 e 192.168.1.0/24), você terá conectividade. Porém, você estará fazendo duas vezes a NAT. Se a NAT é ruim para as aplicações pear-to-pear (skype, torrent, emule), duas é um desastre. Não existe técnica de transversão NAT que ajude. Além disto, computadores que estiverem conectados nas portas LAN do roteador da esquerda não irão "enxergar" os computadores conectados no roteador da direita, seja por cabo ou sem fio (mas o inverso sim). E, para os que gostam de jogar online, vai ter ainda mais latência. Ah, e nada de IPv6 no roteador da direita.

Múltiplos access-point wireless

A tecnologia sem fio 802.11 já foi pensada na possibilidade de um usuário se deslocar ao longo de um determinado local, onde o sinal é fornecido por uma série de equipamentos. O princípio é bem simples: quando existir mais de uma rede com as mesmas características (nome, segurança, senha), é função do equipamento cliente escolher o access-point que forneça o melhor sinal. Isto sem mesmo informar a desconexão ao usuário. No máximo deve ser sentido uma pequena engasgada durante a nova autenticação. Tudo isto funcionará se as estações sem fio estiverem operando como APs e compartilharem a mesma rede local.

Aproveitando, independente do OpenWRT, se for construir uma pequena rede sem fio composta de uma série de APs conectados a uma mesma rede e que usam a mesma senha, não escolha SSID diferentes para cada uma! Só vai te atrapalhar e dificultar a vida do usuário.

Roteador Wireless e AP fornecendo múltiplos access-point wireless

Agora vamos juntar os dois conceitos: roteador operando como AP e mais de uma estação fornecendo a mesma rede sem fio. Voltando a figura anterior, se o roteador "Router" fosse substituído por um roteador wireless, você teria dois provedores do sinal da sua rede sem fio. Um seria o roteador principal, operando como roteador da rede e estação wireless, e o segundo roteador wireless operando apenas como um AP. A interconexão entre os dois é feita através de um cabo convencional. Para qualidade de conexão, é a melhor situação. Os equipamentos conectados, seja por cabo ou sem fio, em ambos os roteadores irão enxergar qualquer outro equipamento conectado.

Para ajudar a melhorar o sinal da rede sem fio, os dois roteadores wireless precisam ficar afastados. Passar um cabo de rede longo pode não ser o que a maioria deseja. Inclusive eu. Não seria melhor que os dois roteadores se comunicassem pela rede sem fio? Seria ótimo! Mas tem alguns problemas ao utilizar redes sem fio para ponte. Vamos simplificar na situação onde é desejado conectar duas áreas de rede, com diversos computadores, através de uma conexão wireless.

Interligando dois setores de rede por conexão wireless

A tecnologia Ethernet cabeada e sem fio operam de maneira diferente. Tanto na cabeada quanto na sem fio, os equipamentos são identificados por um endereço físico (MAC). Por um cabo podem trafegar inúmeras conversas entre computadores diversos. Já em uma conexão sem fio, o access-point wireless somente aceitará dados oriundos do mesmo endereço MAC do cliente que fez a conexão. Isto é um problema? Não para o uso comum. Sim para o nosso caso. Vejamos a figura seguinte, onde é mostrado dois computadores conectados por cabo em equipamentos wireless (um em modo cliente e outro access-point) e estas conversando por sinal wireless:

Fonte:https://wiki.openwrt.org/doc/howto/clientmode

O computador "Bridged Host" está conectado por cabo no cliente wireless "W-LAN Client". Este está conectado como um cliente wireless no "W-LAN AP" que, por fim, conecta em um segundo computador "Target". Esta seria a tentativa de conversa entre "Bridged Host" e "Target":
  1. "Bridged Host" prepara um pacote para "Target"  colocando seu endereço MAC de origem e o MAC do computador "Target" como destino. O pacote é enviado à estação "W-LAN Client".
  2. A estação "W-LAN Client" recebe o pacote e o envia para "W-LAN AP". Porém, antes de enviar, ela troca o MAC de origem, antes com o MAC do "Bridged Host", pelo seu próprio MAC. Caso contrário, a estação "W-LAN AP" não aceitaria.
  3. A estação "W-LAN AP" recebe o pacote e o retransmite para o computador "Target".  Pelo endereço MAC de origem, "Target" acha que quem está falando com ele é "W-LAN Client" e não "Bridged Host".
  4. A resposta é enviada para "W-LAN AP"
  5. "W-LAN AP" retransmite o pacote sem modificação pois a limitação de usar seu próprio MAC é dos clientes e não da estação.
  6. "W-LAN Client" não sabe do que se trata tal pacote e ignora
  7. "Bridged Host" nunca recebe uma resposta
Existem algumas soluções para este problema. Vou mostrar as mais interessantes.

WDS - Wireless Distribution System

A solução mais limpa e elegante é utilizar a tecnologia WDS. Com ela, a comunicação entre os equipamentos wireless preservam o MAC de origem. A figura é igual a anterior, com a diferença que, na comunicação entre o "W-LAN Client" e "W-LAN AP", é utilizado o padrão WDS.


Fonte:https://wiki.openwrt.org/doc/howto/clientmode

A figura mostra que existem 4 endereços MAC em todos os pacotes na comunicação wireless WDS: origem e destino das placas sem fio, e origem e destino dos dados. Assim, a informação das entidades envolvidas não é perdida e a comunicação pode se realizar. Porém, WDS depende da implementação do driver e dos softwares envolvidos. Se ambos forem o mesmo equipamento e com OpenWRT, não é problema. Se for com fornecedores diferentes, pode não funcionar.

Ponte com NAT (possivelmente duplo NAT)

Uma segunda solução seria transformar o equipamento "W-LAN Client" em um roteador, traduzindo os endereços por NAT.

Fonte:https://wiki.openwrt.org/doc/howto/clientmode

A conexão "W-LAN Client" funcionaria como uma conexão WAN. Isto é possível com o OpenWRT. Porém, seria a mesma situação do caso onde a ligação entre o roteador da internet e o roteador wireless era feita pela porta WAN: você terá duas NAT, os computadores da rede azul não falarão diretamente com os computadores da rede vermelha, exceto se existir um encaminhamento de porta.

Roteamento entre Redes

Uma última sugestão apresentada aqui seria o uso de roteamento. Ao invés de esconder os computadores atrás de uma NAT, usar uma outra subrede e configurar rotas estáticas nos roteadores da rede azul e vermelha.

Fonte:https://wiki.openwrt.org/doc/howto/clientmode


Esta é uma solução mais complexa de ser implementada. Porém, preserva a conectividade. Ainda assim, os computadores não estarão na mesma rede e algumas facilidades como a descoberta automática de serviços na rede local não irá funcionar entre as redes.

Ainda existem outras soluções como a utilização de um aplicativo que rastreia as conversas que passam pelo "W-LAN Client" e fazem a tradução dos endereços e outras alternativas baseadas em protocolos proprietários. Porém, acho que as 3 propostas apresentadas aqui são as mais recomendadas na maioria das situações.

No próximo artigo vou mostrar como transformar um segundo roteador em uma ponte entre as redes cabeadas e, ao mesmo tempo, um repetidor de sinal wireless.

Até a próxima.

quarta-feira, 1 de maio de 2013

OpenWrt: 12.09 chegou! Como faço o Upgrade?

Depois de um ano e pouco desde o último lançamento de uma versão estável (10.03.1), foi lançado o OpenWRT 12.09. Já sou usuário desta versão faz um bom tempo, desde o seu tempo de beta e RC. Recomendo-o aos atuais usuários do OpenWRT.

Como sempre, temos diversas melhorias, novas plataformas e modelos suportados na versão estável, pacotes atualizados. O kernel passou para 3.3, a interface deu uma melhorada, mais funcionalidades no firewall, mais fácil usar uma unidade externa como raiz, e assim vai...

Com a evolução do código, também ocorre outro efeito: algumas plataformas antigas são descontinuadas. Isto ocorreu para as plataformas que usavam driver fechado do fabricante atrelados ainda ao kernel 2.4 e sistemas com pouca memória RAM (16 MB). Em geral, isto não será problema aos roteadores comprados nos últimos anos. Também talvez não faria sentido atualizar seu roteador antigo pois sem memória RAM ele não teria recurso para usar grande parte das melhorias. É a sina da obsolescência programada.

Agora para quem possui um roteador compatível e já usa OpenWRT, deve estar coçando para atualizar. E como faço isto?

A escolha da imagem segue o mesmo princípio que é usado para escolher a imagem da primeira instalação. Selecione a imagem pela arquitetura, modelo e versão do hardware. Como sempre, recomendo a versão squashfs, que possui modo de recuperação. A diferença entre a primeira instalação e esta é que não será usada a imagem "factory" e sim a "sysupgrade". E muito importante, leia a wiki do seu roteador! Pode existir algo muito importante ali como o problema com o TL-MR3420 na versão 10.03.1.

Bem, se eu simplesmente ir na interface, fornecer a nova imagem, ele vai funcionar? Provavelmente, mas talvez não é a maneira que dê menos trabalho. Vamos a algumas sugestões:

Em primeiro lugar, faça um backup geral do seu sistema. Sugiro três coisas diferentes: backup gerado pelo openwrt, lista de pacotes instalados e todos os arquivos do overlay.

A primeira e mais simples é o backup gerado pelo openwrt. Este é obtido na mesma página de atualização de firmware do seu roteador. Ele contém uma seleção prévia de várias configurações, inclusive tudo que está em /etc/config. Contudo, o backup não irá manter todos os arquivos modificados em /etc ou em outro lugar. Por exemplo, se você fez alguma modificação no /etc/dnsmasq.conf, ele não será preservado. Se criou um script em /bin ou para os botões em /etc/hotplug.d/button, ele não será preservado. Para incluir estes e outros casos, informe o caminho destes arquivos extras em /etc/sysupgrade.conf. Na interface WEB também tem a edição deste arquivo, no mesmo local da atualização da firmware, na parte de configuração. Gere um arquivo de backup novo e verifique se tudo que você quer está lá dentro. Somente estes arquivos serão preservados em um upgrade.
Dica: olhe todo o conteúdo em /overlay. Ele terá tudo o que foi modificado. Cuide principalmente dos arquivos em /etc.
Porém, o backup do openwrt não é feito para guardar os programas instalados. Ele se limita a scripts, dados e arquivos de configuração. Programas instalados por pacotes devem ser reinstalados manualmente. Por isto a próxima sugestão.

A segunda sugestão é gerar uma listagem de todos os pacotes instalados. Esta pode ser obtido pela interface web ou pelo comando "opkg list-installed". Ela será usada de referência para reinstalar todos os seus programas. Como os programas não serão preservados (somente suas configurações e se estiverem no backup) você terá que reinstalá-los. Em geral, é uma meia dúzia de programas.

A terceira sugestão é fazer um backup completo de todo o /overlay. Afinal de contas, falamos de poucos megabytes mas dentro deles podem estar algumas horas de trabalho. A cópia pode ser feita com um tar. É provavel que você não tenha espaço para criar este tar diretamente no roteador. Você terá que fazê-lo jogando em um disco externo conectado pela USB ou, a forma que eu geralmente uso, diretamente pela rede. Pela rede seria assim:
meucomputador$ ssh root@roteador tar -czv /overlay | cat > overlay.tar.gz
A vantagem deste backup é que, se esquecer de colocar algo em /etc/sysupgrade.conf, você poderá recuperá-lo do arquivo tar.gz. Também, se precisar retornar ao firmware antigo, você já teria uma partição overlay pronta. Bastaria instalar a firmware antiga e jogar o conteúdo da overlay por cima.

Agora, finalmente, você está pronto para enviar a nova firmware. Se você usa um espaço externo para expandir o disco, leia até o final deste post. Faça o upgrade pela interface web ou pelo terminal. Inclusive, você pode baixar o arquivo diretamente no roteador. Ex:
cd /tmp
wget http://downloads.openwrt.org/attitude_adjustment/12.09/..../openwrt...xxx...img
sysupgrade openwrt...xxx....img 
E esperar para ver. Se optar por preservar as configurações, tudo que seria guardado em um backup do sistema, inclusive o que está listado em /etc/sysupgrade.conf, será automaticamente levado ao novo sistema. Depois de o sistema iniciar na próxima versão e estiver funcionando, é hora de retornar os programas antigos. Gere uma nova listagem dos programas instalados e compare com a listagem anterior.
Dica: vimdiff instalados.antigo.txt instalados.novo.txt
A mudança nas versões dos pacotes é esperada e pode ser desconsiderada. Para facilitar, tente instalar primeiro os pacotes que dependem de outros, como os pacotes luci-app-*, antes de instalar os demais. É provável que, pela cadeia de dependências, grande parte será automaticamente instalada. Repita a geração dos programas instalados, a comparação e a instalação até estar satisfeito.

Por fim, faça um novo backup geral. É sempre bom preservar o seu trabalho. 

Hum, e eu que uso um disco externo para expandir o espaço interno? É um pouco mais complicado. Ao atualizar o sistema, os módulos e programas que fariam o uso do disco externo irão parar de funcionar. Você precisaria reinstalá-los. Esta é a sugestão de como proceder:

Em primeiro lugar, gere todos os backups sugeridos anteriormente. É importante preservar seu trabalho anterior. Ainda sem instalar, reinicie o sistema sem o disco externo. Com isto, ele vai usar somente a flash interna (com a configuração que você tinha antes de usar o disco externo). Faça todos os backups novamente, preservando os anteriores. Agora à instalação.

Ainda com o disco externo desconectado, instale a nova firmware. Refaça a configuração de uso do disco externo (que no mínimo será reinstalar os pacotes necessários). No disco externo, na partição usada como overlay, remova todo o conteúdo ou mova tudo para um subdiretório afim de que este não seja usado. Como sugestão, crie um "owrt-10.03.1" e mova tudo para lá. Em seguida, popule novamente este disco da mesma maneira sugerida no artigo de expansão do disco interno (usando o tar). Reinicie o sistema.

Neste ponto, você ainda terá as mesmas configurações que tinha quando usou o sistema sem o disco externo. Envie o primeiro backup da versão anterior feito ainda com o disco externo e siga os passos de reinstalação dos pacotes, assim como é feito para ambientes sem o disco expandido. Complete o trabalho com aquele backup final.

Espero que apreciem a nova versão. De agora em diante, vou apenas focar em configurações específicas do 12.09, que ainda podem funcionar no 10.03.1.

Até mais.

domingo, 28 de abril de 2013

OpenWRT: Passo a passo da solução de um bug no kernel

Este post será mais um relato do que tenho feito nos últimos dias em relação a um bug muito estranho mas também poderá passar o caminho das pedras se alguém quiser se aventurar mais abaixo neste mundo Linux.

Um problema que encontrei após a configuração do HD externo pela USB foi que algumas partições não apareciam. Meu disco era grande e tinha este formato:

  • sda: disco de 1.5TB
    • sda1: partição primária NTFS de 60GB
    • sda2: partição estendida com o restante do disco
      • sda5: partição lógica ext4 com 1TB
      • sda6: partição lógica swap de 4GB
      • sda7: partição lógica ext4 com 60GB

Se não conhece o básico da estrutura da tabela de partições da MBR, o que é uma partição primária, estendida e lógica, wikipedia é sua amiga.

Nada muito anormal e nunca tive problemas durante anos de uso do disco. Porém, ao conectar no OpenWRT, a partição sda6 e sda7 não apareciam. Cumé? Como em geral acontece, os logs dão uma dica. Esta é a mensagem do kernel:

[  173.870000] sd 1:0:0:0: [sdb] No Caching mode page present
[  173.870000] sd 1:0:0:0: [sdb] Assuming drive cache: write through

[  180.330000]  sdb: sdb1 sdb2 < sdb5 >

[  180.340000] sdb: partition table partially beyond EOD, enabling native capacity

[  180.350000] sd 1:0:0:0: [sdb] No Caching mode page present
[  180.360000] sd 1:0:0:0: [sdb] Assuming drive cache: write through
[  180.370000]  sdb: sdb1 sdb2 < sdb5 >
[  180.370000] sdb: partition table partially beyond EOD, truncated
[  180.380000] sd 1:0:0:0: [sdb] No Caching mode page present
[  180.390000] sd 1:0:0:0: [sdb] Assuming drive cache: write through
[  180.400000] sd 1:0:0:0: [sdb] Attached SCSI disk
Bem, o que era possível entender era que, por algum motivo, o Linux no OpenWRT estava achando que uma partição estava além do fim do disco (EOD). Ele tentava ativar uma "native capacity", que não resolvia, e depois truncava o disco. No final de contas, eu ficava com as partições até a sda5.

Agora vem a beleza do software livre: eu tenho o fonte :-) Fazendo uma busca textual simples pela mensagem, eu encontrei este trecho de código:
linux-3.3.8/block/partition-generic.c:

int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{
(...)
    state = check_partition(disk, bdev))
(...)
    /*
     * If any partition code tried to read beyond EOD, try
     * unlocking native capacity even if partition table is
     * successfully read as we could be missing some partitions.
     */
    if (state->access_beyond_eod) {
        printk(KERN_WARNING
               "%s: partition table partially beyond EOD, ",
               disk->disk_name);
        if (disk_unlock_native_capacity(disk))
            goto rescan;
    }
(...)
}
Bem, alguma coisa no check_partition(disk, bdev) estava marcando o estado state->access_beyond_eod e gerando a mensagem. Buscando pelo texto access_beyond_eod, achei que ele somente era definido por este código:
linux-3.3.8/block/partitions/check.h:
static inline void *read_part_sector(struct parsed_partitions *state,
                     sector_t n, Sector *p)
{
    if (n >= get_capacity(state->bdev->bd_disk)) {
        state->access_beyond_eod = true;
        return NULL;
    }

    return read_dev_sector(state->bdev, n, p);
}
Pelo código, somente será marcado access_beyond_eod se o setor lido for maior que o tamanho do disco. Agora, quem está errado? O setor? O tamanho do disco? O tamanho do disco parecia estar correto pois ele era apresentado corretamente nas mensagens de kernel e no arquivo /proc/partitions. Deve ser o setor então. Mas ele está errado no disco ou tratado incorretamente?

Para sanar a primeira dúvida, com ajuda da santa wikipedia, fiz um script para interpretar as tabelas de partição na MBR e na partição estendida. Neste ponto, tentando isolar o problema, já tinha apagado as partições 6 e 7, criado uma nova 6 com 1MB, reduzido a partição 1 e criado uma partição 3 entre as partições primárias 1 e 2. Nada disto alterou o resultado. O script mostrou estas informações:
Checking /dev/sdb...

Checking /dev/sdb1...present
Primary Entry: 0001010007FEFFFF3F000000C1676007
Start(CHS): (010100)
End  (CHS): (FEFFFF)
Code      : 07
Start(LBA): 63 (3F000000)
Size(sect): 123758529 sectors, 63364 Mbytes (C1676007)
Checking /dev/sdb2...present
Primary Entry: 00FEFFFF0FFEFFFF1A5E8007E62913A7
Start(CHS): (FEFFFF)
End  (CHS): (FEFFFF)
Code      : 0F
Start(LBA): 125853210 (1A5E8007)
Size(sect): 2803050982 sectors, 1435162 Mbytes (E62913A7)
Extended partition detected! Reading logical partitions...
Checking /dev/sdb5...present

Primary Entry: 00FEFFFF83FEFFFF3F0000002C140080
Active? no
Start(CHS): (FEFFFF)
End  (CHS): (FEFFFF)
Code      : 83
Start(LBA): 63 (3F000000)
Size(sect): 2147488812 sectors, 1099514 Mbytes (2C140080)
Secondary Entry: 00FEFFFF05FEFFFF6B1400807B150000
Next ERB(LBA): 2147488875 (6B140080)
Size(sect): 5499 sectors, 2 Mbytes (7B150000)
Checking /dev/sdb6...present

Primary Entry: 00FEFFFF83FEFFFF7B0D000000080000
Active? no
Start(CHS): (FEFFFF)
End  (CHS): (FEFFFF)
Code      : 83
Start(LBA): 3451 (7B0D0000)
Size(sect): 2048 sectors, 1 Mbytes (00080000)
Secondary Entry: 00000000000000000000000000000000
This is the last logical partition!


Checking /dev/sdb3...present
Primary Entry: 00FEFFFF82FEFFFF0068600700F01F00
Start(CHS): (FEFFFF)
End  (CHS): (FEFFFF)
Code      : 82
Start(LBA): 123758592 (00686007)
Size(sect): 2093056 sectors, 1071 Mbytes (00F01F00)
Checking /dev/sdb4...not present
Em resumo, por encontrar todas as partições, e com o tamanho correto, o disco estava íntegro. Era problema na leitura ou interpretação dos dados pelo kernel. Seria bem mais fácil o disco estar errado... Neste ponto, eu abri um bug para o OpenWRT mas continuei a investigar por conta própria.

O passo seguinte é adicionar mais informações de debug de dentro do kernel. A maneira mais simples é adicionar alguns "printk" (printf do kernel) em pontos estratégicos. Mas primeiro, é necessário encontrar estes pontos.

Meu disco, por ser menor que 2TB, ainda usa tabela de partições MS-DOS. Como o problema ocorre a partir da segunda partição lógica, o código deve estar na parte que lê os dados da partição estendida. O código é este:
linux-3.3.8/block/partitions/msdos.c
static void parse_extended(struct parsed_partitions *state,
                sector_t first_sector, sector_t first_size)
    this_sector = first_sector;

    while (1) {
(...)
        data = read_part_sector(state, this_sector, &sect);
(...)

        p = (struct partition *) (data + 0x1be);
(...)

        for (i=0; i<4; i++, p++)
            if (nr_sects(p) && is_extended_partition(p))
                break;
(...)
         this_sector = first_sector + start_sect(p) * sector_size
                   }
(...)
}
Olha a função read_part_sector que pode marcar access_beyond_eod ali no começo! Para conseguir entender o código, é necessário conhecer a estrutura das partições estendidas. Em resumo, a partição estendida possui uma tabela de partição própria (ERB), onde a primeira entrada descreve a primeira partição lógica e a segunda entrada aponta para a próxima tabela de partição. Voltando as aulas de estrutura de dados, é uma lista ligada/encadeada. Eu coloquei printk ao longo de toda esta função para descobrir o que não estava legal. A parte estranha foi justamente esta última, que soma a posição relativa da próxima tabela de partição com o início da partição estendida:

[   98.230000] parse_extended: sector_size = 1

[   98.230000] parse_extended: start_sect(p) = 2147488875
[   98.230000] parse_extended: start_sect(p)*sector_size = 2147488875
[   98.240000] parse_extended: first_sector = 125853210
[   98.250000] parse_extended: first_sector + start_sect(p) * sector_size = this_sector = 18446744071687926405
O que?! 2147488875 + 125853210 = 18446744071687926405 ?? O que aconteceu com  2273342085? Agora que tinha algo mais palpável, mandei diretamente para a lista de desenvolvimento do OpenWRT. Com ajuda de outros desenvolvedores, descobrimos o problema.

Em primeiro lugar, um pouco de contextualização. Todas as variáveis na expressão problemática são do tipo sector_t, que para meu caso é representado por um u64 (valor inteiro sem sinal de 64 bits). Não deveria ter problemas para as grandezas envolvidas pois vai até 18446744073709551615. Além disto, os setores em uma partição MS-DOS são representados por inteiros sem sinal de 32-bit. Então o 64-bit estão sobrando. Por que o problema? Olhando o binário da resposta correta, 2273342085, e a errada, podemos ver uma coisa em comum:

2273342085(b10)           = 0000000000000000000000 1000101011000000111110(b2)
18446744071687926405(b10) = 1111111111111111111111 1000101011000000111110(b2)

Os bits mais significativos ficaram todos 1 quando o correto seria 0. Uma possível causa deste monte de '1' é de um resultado da conversão de um inteiro com sinal 32-bit para 64-bit. Voltando a aula de análise numérica (wikipedia para relembrar?), os números inteiros com sinal serão negativos quando o primeiro bit for 1. Porém, não é simplesmente colocar um bit na frente. O sistema mais usado atualmente é o complemento para dois. O número negativo é a negação dos bits do mesmo número positivo, mas deslocando em um para não ter zero positivo e negativo. O que importa para este problema é que, para converter um número para outro igual com mais bits, basta completar os bits mais significativos com o valor do primeiro bit. A tabela seguinte mostra exemplo desta conversão de 4-bit para 8-bit:

Decimal
4-bit
8-bit
+3
0011
00000011
+2
0010
00000010
+1
0001
00000001
0
0000
00000000
−1
1111
11111111
−2
1110
11111110
−3
1101
11111101


E o mesmo vale de 32-bit para 64-bit. Como o primeiro bit de 2273342085 é 1, se este fosse um número negativo, ao converter para 64-bit, todos seus primeiros bits serão 1. Mas eu não tinha falado que as variáveis daquela expressão problemática são sem sinal? O compilador se perdeu? Só uma forma de dizer isto: olhando o assembly gerado.

Recompilando o kernel com informações de debug ativadas, é possível extrair o assembly em conjunto com o código em C. A arquitetura do roteador é MIPS. Enfim as aulas de assembly da faculdade com o MIPS servem para alguma coisa! O resultado é este:

this_sector = first_sector + start_sect(p) * sector_size;
 344:   02e00013        mtlo    s7
 348:   00052a00        sll     a1,a1,0x8
 34c:   00031c00        sll     v1,v1,0x10
 350:   00a31825        or      v1,a1,v1
 354:   90850008        lbu     a1,8(a0)
 358:   9084000b        lbu     a0,11(a0)
 35c:   02c00011        mthi    s6
 360:   00651825        or      v1,v1,a1
 364:   00042600        sll     a0,a0,0x18
 368:   00641825        or      v1,v1,a0
 36c:   70720000        madd    v1,s2
 370:   00005812        mflo    t3
 374:   afab004c        sw      t3,76(sp)
 378:   00005010        mfhi    t2
 37c:   afaa0048        sw      t2,72(sp)
A parte que importa está em destaque. A instrução madd é a soma entre dois números inteiros com sinal. O correto deveria ser maddu. Então o compilador acha que isto é um inteiro com sinal? Beleza, compilador com bug, joga fora e pega outro.... não é tão simples assim. Não existe outro compilador que possa ser usado além do gcc para compilar o kernel (llvm está quase lá, mas não para MIPS). Será mesmo problema do compilador? Pode ser, mas pode também ter alguma ajuda do código. Voltando a linha problemática, fora as variáveis locais, existe uma chamada externa para start_sect. Este é o código:
linux-3.3.8/block/partitions/msdos.c:
static inline sector_t start_sect(struct partition *p)
{
    return (sector_t)get_unaligned_le32(&p->start_sect);
}
Ele pega a posição do setor inicial na lista de entradas da tabela de partição, que representa em um número 32-bit, com formato big endian, na mesma ordem usada em protocolos de rede. Este buffer de 4 bytes é passado para a função get_unaligned_le32, que converte para o formato de número 32-bit na ordem da máquina. A implementação desta função depende de cada arquitetura. Em processadores x86, existe uma instrução do processador para fazer isto. Para MIPS, é feiro por código:
linux-3.3.8/include/linux/unaligned/le_byteshift.h:
static inline u32 __get_unaligned_le32(const u8 *p)
{
    return p[0] |p[1] << 8 | p[2] << 16 | p[3] << 24;
}
O código é simples: ele pega cada um dos 4 bytes do buffer 32-bit, desloca cada um para a sua posição correta usando o operador left shift e junta tudo com o operador ou. E qual o problema disto? Existe um não aparente. A especificação C99 define que:


   The integer promotions are performed on each of the operands. The type of the result is
   that of the promoted left operand. If the value of the right operand is negative or is
   greater than or equal to the width of the promoted left operand, the behavior is undefined.

Então, se o lado esquerdo possuir menos ou o mesmo número de bits deslocados pelo lado direito do operador, o comportamento não é definido, que em miúdos quer dizer, se você fizer isto, não sei o que vai acontecer. Nisto, o compilador se perdeu e, por algum motivo, ignorou o fato das variáveis serem sem sinal. Pode ser que ele ainda estivesse considerando operações para variáveis sem sinal 8-bit, onde não importa muito se você está usando um operador 32-bit com ou sem sinal. A solução é ligeiramente simples: converter o tipo do lado esquerdo antes de aplicar o operador. Fica assim:
linux-3.3.8/include/linux/unaligned/le_byteshift.h:
static inline u32 __get_unaligned_le32(const u8 *p)
{
    return p[0] | (u32)p[1] << 8 | (u32)p[2] << 16 | (u32)p[3] << 24;
}

E o código assembly indica que o compilador, agora, assume que aquela soma é entre variáveis sem sinal:

 this_sector = first_sector + start_sect(p) * sector_size;
 344:   02e00013        mtlo    s7
 348:   00052a00        sll     a1,a1,0x8
 34c:   00031c00        sll     v1,v1,0x10
 350:   00a31825        or      v1,a1,v1
 354:   90850008        lbu     a1,8(a0)
 358:   9084000b        lbu     a0,11(a0)
 35c:   02c00011        mthi    s6
 360:   00651825        or      v1,v1,a1
 364:   00042600        sll     a0,a0,0x18
 368:   00641825        or      v1,v1,a0
 36c:   70720001        maddu   v1,s2
 370:   00005812        mflo    t3
 374:   afab004c        sw      t3,76(sp)
 378:   00005010        mfhi    t2
 37c:   afaa0048        sw      t2,72(sp)
Note que a instrução mudou de madd para maddu. Provavelmente foram alteradas outras instruções no código mas ao menos agora sei que o compilador está tratando como número sem sinal.

Adicionado o patch ao kernel, recompilando a imagem e instalando, volto a ter acesso a todas as partições do disco!

Acredito que este problema ainda era desconhecido por ser raro juntar uma arquitetura vulnerável ao problema com ao menos uma partição lógica iniciada além do setor 4294967296 (ou 1 TB) na partição. O mundo x86 não é afetado pois a função __get_unaligned_le32 é implementada diretamente por uma instrução do processador.


Agora falta apenas submeter oficialmente o patch para o Openwrt e para o kernel oficial. Enfim, a culpa era do kernel Linux e compilador, não diretamente do OpenWRT.

Até a próxima!

sexta-feira, 19 de abril de 2013

OpenWRT: Torrent diretamente no roteador.

Mais um artigo da série sobre o OpenWRT.

conectamos um HD no roteador e compartilhamos na rede. Falta somente arrumar uma aplicação para encher todo este espaço em disco. E para isto, nada melhor que o torrents.

O BitTorrent, ou Torrent para os mais íntimos, é um protocolo de compartilhamento de arquivos peer-to-peer. A principal característica é que todos que estão baixando também fornecem este conteúdo. Assim, retira-se o gargalo dos downloads de uma única fonte. Bem, o importante é que é uma ótima ferramenta para baixar arquivos grandes como os arquivos do Ubuntu, LibreOffice e outras coisas.

Existe algumas alternativas de cliente BitTorrent no OpenWRT, mas vou me limitar ao Transmission por ser leve, integrado ao ambiente e com a possibilidade de administração remota facilitada. Como de praxe, precisam ser instalados os pacotes do programa:

Outro problema que pode ocorrer com os torrents é a falta de memória. Se seu equipamento possuir 64MB ou mais, em geral, deve funcionar sem problemas. Caso contrário, pode ser necessário utilizar uma partição ou arquivo em disco externo como swap. Se aparecer interessados, eu faço um post sobre isto. Acompanhe as mensagens de kernel do sistema por alertas de processos mortos por falta de memória.

O primeiro a ser instalado é o daemon. Ele será o programa que ficará rodando e baixando seus arquivos. Os demais serão formas de acessá-lo.
opkg update

opkg install transmission-daemon
Uma das primeiras interfaces é a versão CLI (console). Com ela, você poderá acompanhar e configurar seus torrents conectando no roteador pelo SSH e rodando o programa. 
opkg install transmission-cli
Existe também uma versão WEB, equivalente à versão gráfica, mas operável de um navegador.
opkg install transmission-web
E uma das mais interessantes é a possibilidade de rodar um cliente Transmission no seu computador e ele controlar os Torrents no seu roteador. Para isto, instale:
opkg install transmission-remote
A configuração é toda feita no arquivo /etc/config/transmission. E uma forma facilitada de configurá-lo é por um módulo da interface web Luci. Neste caso, precisa instalar mais um pacote:
opkg install luci-app-transmission
Recomendo o uso da interface, apesar da tradução pt_BR ainda estar desatualizada. Tomara que seja feita a sincronia das traduções antes de sair a próxima versão estável do OpenWRT. As partes mais importantes, configuradas na web ou no arquivo, são ativação do serviço, o diretório para downloads e o de configuração. Observe que o usuário que rodar o programa deve ter permissão de escrita nestes diretórios. Se for usar a interface web ou remota, existe uma lista de endereços permitidos que pode necessitar de ajuste. Dispare o serviço pela web ou linha de comando:
/etc/init.d/transmission enable
/etc/init.d/transmission start
É bom olhar os logs para ver se não ocorreu algum problema:
logread | grep transmission
Para gerenciar seus torrents, você pode usar:
  • a interface web pelo endereço http://roteador:9091/
  • a partir de uma conexão SSH, a interface CLI, pelo comando transmission-cli
  • um cliente transmission no seu computador apontando para host roteador, porta 9091. Neste caso, as opções de clientes são variadas.
Trocando "roteador" pelo nome ou endereço do seu roteador. Se o endereço do roteador não foi alterado, ele será o 192.168.1.1.


Depois de ter uma instalação básica funcional, volte as configurações e observe se existe algo interessante para ser ajustado. A opção de diretório de arquivos incompletos pode ser interessante se a sua intenção é montar um mediabox.

Apesar de já ser possível baixar arquivos com esta configuração, você terá melhores resultados se os parceiros também conseguirem conectar no seu cliente. Eles tentarão conectar na porta definida pela opção "peer_port". É necessário liberar esta porta no firewall.
Em geral, você irá habilitar a porta definida na opção "peer_port", vinda de qualquer lugar da wan e para qualquer endereço do roteador. Talvez você também queira desligar a proteção de "syn_flood" no firewall pois volume "normal" de conexões em torrents vai além dos limites desta proteção. Ah, e por usar o IP WAN do roteador, que em geral é um IP válido na internet, pode esquecer a necessidade dos encaminhamentos de porta.

Atualização em 13/03/2016: se estiver utilizando o SQM ou outro QoS inteligente, é bom configurar o peer-socket-tos para "low-cost". Assim ele sabe que não deve dar prioridade ao torrent. No pior dos casos, configurar esta opção não terá efeito ;-).

Com o transmission no roteador, você poderá continuar a baixar seus arquivos por dias e com um consumo de energia muitas vezes menor do que um computador tradicional. Ainda, após terminar seus downloads e depois de disponibilizar uma boa proporção dos arquivos, você pode deixar o serviço transmission desligado e dar uma folga ao HD. Isto vai aumentar a sua vida útil.

Let's share!

Bom compartilhamento para vocês.

sábado, 6 de abril de 2013

OpenWRT: Compartilhando seu HD na rede pelo roteador(NAS)

A porta USB no roteador o torna muito versátil. Um dos usos mais interessantes é transformá-lo em um NAS (Network Attached Storage) ou, em suma, um "HD na rede". Para tal, vamos precisar de um roteador com porta USB, uma unidade de armazenamento USB e espaço em disco para instalar o servidor de arquivos.


Depois de conectar um HD externo e, talvez, aumentar o espaço do disco do OpenWRT para poder instalar mais coisas, vamos a instalação do servidor de arquivos. O servidor de arquivos padrão para o Linux é o Samba. Apesar de ser uma implementação do protocolo "padrão" da Microsoft para troca de arquivos em rede, é o que temos de melhor para troca de arquivos mesmo entre duas máquinas Linux. Se o cliente for um Windows®, nem se fala.

Já existe um pacote pronto do samba para o OpenWRT. Basta instalar o pacote samba36-server e, opcionalmente, luci-app-samba, e você terá tudo que precisa para o servidor. Você pode usar tanto a interface WEB como a linha de comando para a instalação:
opkg update
opkg install samba36-server
A configuração do samba pode ser feita com as opções do arquivo smb.conf ou, de forma mais limitada, pela infraestrutura do OpenWRT, no arquivo "/etc/config/samba" . Vou me limitar ao segundo caso pois atenderá a maioria dos usuários. Quanto ao primeiro, não seria diferente de um sistema Linux padrão. Preferencialmente altere o arquivo "/etc/samba/smb.conf.template" pois a configuração final será obtida juntando as informações deste arquivo com o que for configurado em "/etc/config/samba". O pacote luci-app-samba, opcional, fornece uma página na interface WEB Luci que possibilita a configuração básica do samba ou a edição do arquivo "smb.conf.template" sem precisar saber usar o vim.

Na inteface WEB, assim como no arquivo de configuração, é bom definir o nome e o grupo de trabalho do seu roteador. Os diretórios compartilhados são criados em um item sambashare ou em "Diretórios Compartilhados" na interface Luci. Caso a segurança não seja preocupação, ative a opção "permitir convidados" ou "guest_ok". Assim, não será necessário fornecer um usuário e senha para conectar no roteador. A opção "somente leitura" vai no mesmo sentido. Só lembrando que, por padrão, usuário sem senha assume o usuário unix nobody e este precisa ter permissão de leitura ou escrita ou diretório para poder acessar ou escrever nos diretórios. Se a segurança não for importante, dê acesso completo a todos os usuários:
chmod a+rw /mnt/sd??
Onde o /mnt/sd?? é o local onde seu disco está montado no sistema. Só lembre que ao liberar o acesso sem senha e com permissão de escrita a todos, seus arquivos estarão acessíveis a qualquer usuário que tenha acesso a sua rede local. Isto inclui as suas visitas que conectam no seu wireless. Por padrão, o acesso externo (pela internet) ao samba está bloqueado no firewall. Não recomendaria a abertura deste servidor para a internet e, se for feito, por favor, não usem acesso de convidados.

Para colocar o servidor de arquivos em uso, habilite o serviço e inicie:
/etc/init.d/samba enable
/etc/init.d/samba start
E teste a partir de um computador. No windows, o caminho será \\<nome ou ip do roteador\<compartilhamento> e nas interfaces gráficas do Linux, em geral, smb://<nome ou ip do roteador/<compartilhamento>. Ex:
  • \\roteador\fotos ou smb://roteador/fotos
  • \\192.168.1.1\documentos ou smb://192.168.1.1/documentos
Se seu desejo é o uso somente com usuário convidado, sem senha, este artigo termina aqui para você. Para os mais preocupados com segurança, pode-se criar contas no OpenWRT para cada usuário. O processo é o mesmo de um sistema Linux. Infelizmente, por padrão, não tem os comandos para facilitar esta tarefa. Portanto, para criar usuários, adicione linhas como esta ao arquivo /etc/passwd:
newuser:*:1000:65534:new user name:/var:/bin/false
O newuser é o login do usuário. O número 1000 é o identificador. Deve ser único entre os usuários e preferencialmente acima de 1000. "new user name" é o nome completo, sem muito uso no OpenWRT. "/var" é o home e "/bin/false" o shell. Se ele não for conectar por SSH com este usuário no roteador, pode ficar como está. O caminho do home, "/var", pode ser interessante mudar se for habilitada a opção "homes" ou "compartilhas os homes dos usuários" na configuração do samba. Assim, quando ele se autenticar, será criado dinamicamente um diretório compartilhado com o nome do usuário para este caminho. É necessário definir uma senha para este usuário no samba utilizando o comando smbpasswd. Na primeira vez, é preciso criar o usuário nos bancos de dados do samba.
smbpasswd -a usuário
O mesmo comando pode ser usado para trocar a senha, mas sem o "-a".

Com isto temos mais uma função, um NAS, consolidado no roteador. Com um NAS e um servidor DLNA, você terá um MediaBox. Com o NAS e um cliente Torrent, um SeedBox. E por que não ambos? E por que não mais coisas? Isto fica para outro post. Até mais.

domingo, 31 de março de 2013

OpenWRT: Expandindo o espaço do disco com unidade externa

O grande limitador de um roteador com OpenWRT não está no software que ele usa. Afinal de contas, rodando um Linux, é possível montar um servidor completo. O que restringe os usos do roteador são suas características fisicas, principalmente disco e memória. Processador também é um limitador importante para operações de tempo real, como streaming de conteúdo multimídia, mas pouco podemos fazer para melhorar o processador. Ao menos para o disco e a memória temos alguma alternativa. Sim, também é possível trocar os chips da placa por outros de maior capacidade, mas o que eu vou mostrar aqui é algo bem menos intrusivo.

Como já escrevi anteriormente, em imagens squashfs, OpenWRT divide o sistema de arquivos em duas partes: uma imagem base e as suas alterações. A primeira, chamada de "rom", é um sistema de arquivos completo, imutável, e somente é modificado na gravação de uma nova firmware. O usuário nem nota esta característica pois qualquer alteração efetuada nesta imagem são guardados em uma segunda área de disco, o chamado "overlay". O espaço livre do disco é, na verdade, o espaço disponível na "overlay". Seguindo esta estrutura, não adianta apagar coisas do disco que sejam provenientes da "rom" pois eles somente serão marcados como apagados e não serão liberados do disco.

Por padrão, o "kernel" e a "rom" dividem a flash do roteador e o que sobra fica para a "overlay". Quanto maior as duas primeiras, menos espaço "livre", e tudo isto em uma flash de 4 ou 8MB. O que vamos fazer é configurar o OpenWRT para usar uma unidade externa como a "overlay", expandindo o limite disponível.

O primeiro passo é escolher a unidade externa. No meu caso vai ser um pendrive antigo de 128MB, mas pode ser qualquer dispositivo de armazenamento USB. A configuração inicial é a mesma apresentada no último post. Se conectar o dispositivo e ele aparecer em /mnt ou no comando mount, você está pronto para a segunda etapa.

É bom ter uma configuração funcional antes de iniciar o processo. Caso você remova o disco externo, você terá seu roteador com esta configuração. Sugiro algo simples com a capacidade de acessar a internet.

A montagem automática funciona muito bem para dispositivos de uso eventual. Porém, como será um dispositivo permanente, o ideal é fixar algumas configurações. A primeira coisa a ser melhorada é o ponto de montagem. "/dev/sda5" não diz muito a quem está lendo e quando se trata de discos, é importante não errar a unidade. Também, se for conectada mais de uma unidade, a ordem que estes discos aparecem dependem da ordem de conexão. O primeiro será o sda, o segundo sdb e assim por diante. O ideal é a ordem dos discos não influencie. Para estas configurações, existe o arquivo "/etc/config/fstab". A entrada que nos interessa é a de montagem. Você pode ter quantas entradas destas desejar. No meu caso, terei 2: uma para a partição do HD externo e outra para a nova "overlay".

Atualizado em 2015-09-30: para versões mais novas (como a CC), o recomendado é gerar a configuração "/etc/config/fstab" com:

# block detect >/etc/config/fstab

Depois é só ajustar os valores (normalmente só o enable)

Existem três características que podem ser usadas para identificar um disco no OpenWRT (também suportadas em Linux "convencionais"): dispositivo, nome e uuid. O primeiro é o nome do arquivo que representa o dispositivo, em geral /dev/sd??. Como já comentei, este nome depende da ordem de conexão dos discos e deve ser evitado. A segunda forma, pelo nome, usa o nome ou rótulo dado ao sistema de arquivos, configurado na formatação ou posteriormente. Para partições ext2/3/4, o comando é o tune2fs. O terceiro é o uuid. Ele funciona como um identificador único e é gerado na criação do disco (tune2fs também pode alterá-lo). Se gerado aleatoriamente, é desprezível a possibilidade de conflito. Apesar da segurança do uuid, prefiro a contextualização que o nome me fornece. Estas propriedades dos discos podem ser visualizadas com o comando "blkid". Como usarei dois discos, foram adicionadas as seguintes linhas no meu arquivo /etc/config/fstab:
config mount
        option target   /mnt/usb-dados
        #option device  /dev/sda1
        option label    "usb-dados"
        #option uuid    "b7dc2020-b12a-431e-98d3-619a..."
        option fstype   ext4
        option options  rw,sync
        option enabled  1
        option enabled_fsck 0
config mount
        option target /mnt/extroot
        option label "openwrt-extroot"
        option fstype ext3
        option options rw,sync
        option enabled 1
        option enabled_fsck 0
Para registro, deixei intencionalmente as opções para apontamento por dispositivo e uuid. Porém, estas opções, por estarem comentadas, não serão lidas. Reiniciando o serviço fstab ou o roteador, você terá o disco identificado como usb-dados montado em /mnt/usb-dados e o nomeado "openwrt-extroot" em /mnt/extroot. O caminho deste segundo é temporário e logo será substituído.

Se as partições retornarem de um reboot montadas, é hora de migrar da "overlay" interna para a externa. O primeiro passo é configurar em  /etc/config/fstab a nova partição como a "overlay". E isto depende da versão que você está usando do OpenWRT. Para a versão 12.09, ainda em desenvolvimento, basta trocar onde antes era "/mnt/extroot", colocar "/overlay". Para a versão 10.04.1, backfire, é necessário instalar o pacote "block-extroot" adicionar a opção "option is_rootfs 1" e não alterar a opção target para "/overlay".

Agora basta popular a nova partição Copie os arquivos da "overlay" atual para a nova:
tar -C /overlay -cvf - . | tar -C /mnt/extroot -xf -
Lembre-se de ajustar o nome em negrito para o ponto de montagem em uso pela futura "overlay". Mas preciso usar o tar? É bom pois ele copia todos os atributos necessários e não sei se o cp do busybox faria melhor.

Se tudo der certo, só falta reiniciar. Antes, minhas montagem antes de reiniciar eram estas:
# mount
rootfs on / type rootfs (rw)
/dev/root on /rom type squashfs (ro,relatime)
proc on /proc type proc (rw,noatime)
sysfs on /sys type sysfs (rw,noatime)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noatime,size=30856k)
tmpfs on /dev type tmpfs (rw,noatime,size=512k,mode=755)
devpts on /dev/pts type devpts (rw,noatime,mode=600)
/dev/mtdblock3 on /overlay type jffs2 (rw,noatime)
overlayfs:/overlay on / type overlayfs (rw,relatime,lowerdir=/,upperdir=/overlay)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
none on /proc/bus/usb type usbfs (rw,relatime)
/dev/sda5 on /mnt/usb-dados type ext4 (rw,sync,relatime,user_xattr,barrier=1,data=ordered)
/dev/sdb1 on /mnt/extroot type ext3 (rw,sync,relatime,user_xattr,barrier=1,nodelalloc,data=ordered)
E com a nova "overlay" ficaram:
/dev/root on /rom type squashfs (ro,relatime)
proc on /proc type proc (rw,noatime)
sysfs on /sys type sysfs (rw,noatime)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noatime,size=30856k)
tmpfs on /dev type tmpfs (rw,noatime,size=512k,mode=755)
devpts on /dev/pts type devpts (rw,noatime,mode=600)
/dev/sdb1 on /overlay type ext3 (rw,sync,relatime,user_xattr,barrier=1,nodelalloc,data=ordered)
overlayfs:/overlay on / type overlayfs (rw,relatime,lowerdir=/,upperdir=/overlay)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
/dev/sda5 on /mnt/usb-dados type ext4 (rw,sync,relatime,user_xattr,barrier=1,data=ordered)
none on /proc/bus/usb type usbfs (rw,relatime)
E, principalmente, o espaço livre:
# df -h
Filesystem                Size      Used Available Use% Mounted on
rootfs                  117.6M     13.7M     97.8M  12% /
(...)
Pronto! É espaço de sobra para instalar o que eu pretendo utilizar no roteador. Apesar de ser apenas 128MB, é muito mais do que os 6MB restantes da flash interna. Nos próximos posts, farei a configuração do samba, servidor de impressão e cliente torrent. Até mais e Feliz Páscoa.

segunda-feira, 14 de janeiro de 2013

OpenWRT: conectando um HD pela USB

De volta da vida desconectada, vou começar a escrever as possibilidades de ter um roteador com uma porta USB. Como será um requisito para qualquer uso mais intenso do roteador, precisamos de mais espaço em disco. Isto pode ser obtido conectando qualquer dispositivo de armazenamento USB na porta USB do roteador como Pendrive, HD Externo, leitor de  cartão de memória, celulares, etc. No meu caso, vou conectar um HD externo de 1TB.

Diferentemente de um Linux para Desktop, o OpenWRT precisa economizar espaço em disco ao extremo. Uma das formas de ganhar alguns "mega" é filtrar os módulos de kernel instalados. Em geral, para equipamentos com USB, é pré-instalado um módulo básico de suporte USB como o kmod-usb2. Porém, estes módulos básicos não incluem o uso de unidades de armazenamento USB. O que você vai inicialmente precisar são os pacotes:

  • kmod-usb-storage
  • kmod-usb-storage-extras (opcional, para unidades alternativas como leitores de cartão)
  • para OpenWRT 10.03.1
    • block-hotplug
    • block-mount
  • para OpenWRT 12.09-rc1 (usado nos testes)
    • block-mount (agrega o block-hotplug e o block-extroot)

E os respectivos módulos para cada sistema de arquivos que você pretenda usar:

  • kmod-fs-ext4: para ext2, ext3 e ext4
  • kmod-fs-vfat: para FAT (em geral o que você encontrará em pendrives)
  • kmod-fs-ntfs: NTFS usado pelo windows mas sem acesso de escrita. 

Existem outras alternativas (busque por pacotes kmod-fs-*), mas o que você vai precisar em 99% dos casos são estes três. Se a ideia é deixar um disco fixo no roteador, recomendo usar o ext4. É rápido e feito para ser usado no Linux. Se for movimentar esporadicamente o roteador, ainda assim recomendaria o ext4. Existe driver para windows que funciona muito bem. Também é possível usar o ntfs-3g para montar NTFS com escrita no roteador. Você terá um desempenho inferior e precisará de mais espaço no roteador para instalar os drivers e programas necessários.

Ainda sobre o vfat, e provavelmente o ntfs, você precisará de mais um módulo de suporte da língua do sistema de arquivos. Ao tentar montar o disco, aparecerá uma mensagem de erro do kernel como esta:
FAT: IO charset iso8859-1 not found
Isto significa que você não tem o driver do NLS (Native Language Support) usado pelo seu sistema de arquivos. Instale o correspondente pacote kmod-nls-xxx, onde xxx será a codificação necessária, como kmod-nls-iso8859-1. Com ext4, você não teria este problema.

O que eu uso nas minhas unidades de armazenamento maiores é dividir o disco em duas ou mais partições, sendo uma pequena em FAT e as demais em EXT4. A partição FAT é usada para guardar o driver do ext para windows, para ser instalado em novas máquinas, e para trocas de arquivos com dispositivos não muito abertos como impressoras, TV. As partições EXT4 guardam os dados de verdade.

Com os pacotes instalados, conecte seu HD externo. Deverá aparecer algo similar nas mensagens de kernel (dmesg)
[864448.690000] usb 1-1: new high-speed USB device number 2 using ehci-platform
[864448.840000] scsi0 : usb-storage 1-1:1.0
[864449.850000] scsi 0:0:0:0: Direct-Access     WD       My Book 1110     1030 PQ: 0 ANSI: 4
[864449.860000] scsi 0:0:0:1: CD-ROM            WD       Virtual CD 1110  1030 PQ: 0 ANSI: 4
[864449.880000] scsi 0:0:0:2: Enclosure         WD       SES Device       1030 PQ: 0 ANSI: 4
[864449.890000] sd 0:0:0:0: [sda] 2928904192 512-byte logical blocks: (1.49 TB/1.36 TiB)
[864449.900000] sd 0:0:0:0: [sda] Write Protect is off
[864449.910000] sd 0:0:0:0: [sda] Mode Sense: 23 00 10 00
[864449.920000] sd 0:0:0:0: [sda] No Caching mode page present
[864449.920000] sd 0:0:0:0: [sda] Assuming drive cache: write through
[864449.940000] sd 0:0:0:0: [sda] No Caching mode page present
[864449.940000] sd 0:0:0:0: [sda] Assuming drive cache: write through
[864449.990000]  sda: sda1 sda2 < sda5 >
[864449.990000] sda: partition table partially beyond EOD, enabling native capacity
[864450.000000] sd 0:0:0:0: [sda] No Caching mode page present
[864450.010000] sd 0:0:0:0: [sda] Assuming drive cache: write through
[864450.020000]  sda: sda1 sda2 < sda5 >
[864450.020000] sda: partition table partially beyond EOD, truncated
[864450.060000] sd 0:0:0:0: [sda] No Caching mode page present
[864450.070000] sd 0:0:0:0: [sda] Assuming drive cache: write through
[864450.070000] sd 0:0:0:0: [sda] Attached SCSI disk
No meu caso, sda1 é uma partição FAT, sda2 uma extended que contém a partição sda5. Magicamente, o disco foi montado. O comando mount mostra a localização:
root@router:~# mount
(...)
/dev/sda5 on /mnt/sda5 type ext4 (rw,relatime,user_xattr,barrier=1,data=ordered)
O próprio OpenWRT montou o disco em /mnt/sda5. Só acessar o diretório e todo o conteúdo estará disponível.

Para HD, é bom desligá-los quando eles não forem necessários. Isto poupará suas partes móveis e aumentará a vida útil da unidade. O pacote luci-app-hd-idle realiza esta tarefa. A sua configuração é feita pela interface Web (luci) e é bem intuitivo. Basicamente, configura-se a unidade e o tempo sem atividade até que o disco seja desligado. Se alguma informação for necessária após ele ser desligado, o primeiro acesso apenas levará alguns segundos a mais do que o normal até o disco voltar a girar.

Até este ponto, a unidade estará somente "visível" para o roteador. Já é possível copiar arquivos de e para o roteador usando programas como o scp e o winscp mas nada muito amigável. O próximo passo será a instalação de um serviço de compartilhamento de arquivos (samba).

Até a próxima.