Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
eddadc2
fixed portal front-end js errors
usg-ishimura Oct 1, 2025
a6999cc
fixed portal and read_for_access 502 bad gateway redirect bug
usg-ishimura Oct 1, 2025
538141a
aligned read_for_access test to 502 bad gateway bug fix
usg-ishimura Oct 1, 2025
c8c011f
added packets drop for unauthorized macs on 443 and restored init.d p…
usg-ishimura Oct 1, 2025
02b10f3
packages: document pirania system
luandro Jan 19, 2026
ce0a2b2
docs: add agents instructions
luandro Jan 19, 2026
3db74cf
packages: add pirania implementation notes
luandro Jan 19, 2026
fe002a1
Adiciona doc extensa (gerada por ia)
vractal Jan 20, 2026
aaef623
Merge pull request #1 from vractal/doc-atualizada
luandro Jan 20, 2026
b48754d
Update nft rules to block all protocols when no voucher
vractal Jan 20, 2026
9c5a632
fix(pirania): correct nftables table name typo and add logging
luandro Jan 20, 2026
dda82aa
Merge pull request #2 from vractal/fix-nft-rules
luandro Jan 20, 2026
bbe3b1e
Merge branch 'libremesh:master' into hotfix/pirania
luandro Jan 21, 2026
a8c5aad
packages: allowlist destinations in forward
luandro Jan 21, 2026
31a02d4
feat(pirania): add Tranca Redes scheduled access control
luandro Jan 22, 2026
2bce427
fix(pirania): replace lucihttp with pure Lua URL utilities
luandro Jan 22, 2026
13f5351
pirania: disable nftables per-packet logs
luandro Jan 22, 2026
3b05ba5
packages: guard pirania updates when disabled
luandro Jan 23, 2026
c163aea
packages: pirania switch to nftables
luandro Jan 23, 2026
eef46ef
feat(pirania): add nftables interface scoping for catch_interfaces
luandro Jan 23, 2026
49ca86c
docs(pirania): update interface scoping plan with implementation notes
luandro Jan 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Repository Guidelines

## Communication
- Always write responses in English, even if the prompt is in Portuguese or another language.

## Project Structure & Module Organization
- `packages/`: OpenWrt package definitions and payload files. Runtime Lua code typically lives under `packages/<pkg>/files/usr/lib/lua/`, and package-level tests live under `packages/<pkg>/tests/`.
- Scope: always and only work with code under `packages/pirania/`; ignore all other items inside `packages/`.
- `tests/`: shared test utilities, fakes, and integration tests.
- `captive-portal-v0` … `captive-portal-v3`: captive portal assets by version.
- `Dockerfiles/`: container definitions (notably unit test image).
- `tools/`: helper scripts (e.g., `tools/dockertestshell`).
- `run_tests`: test runner script.
- `libremesh.mk`, `libremesh.sdk.config`: build/SDK integration files for OpenWrt.

## Build, Test, and Development Commands
- `./run_tests`: run Lua unit tests inside Docker using `busted` and generate coverage.
- `LUA_ENABLE_LOGGING=1 ./run_tests`: enable verbose Lua logging during tests.
- `./tools/dockertestshell`: open a shell inside the test container to iterate quickly.
- Only run or modify workflows that target `packages/pirania/`.
- Image building is done via OpenWrt Buildroot/ImageBuilder; see `README.md` for full workflows. Example ImageBuilder usage (run inside the ImageBuilder directory):
```sh
make image PROFILE=<device_profile> PACKAGES="lime-system lime-proto-babeld ..." FILES=files
```

## Coding Style & Naming Conventions
- Preserve existing style within each file; there is no repo-wide formatter.
- Lua: follow current indentation in the file (tabs/spaces vary); keep module-level tables and `return` at end.
- Makefiles: use tabs for recipe lines (required by `make`).
- Shell: scripts such as `run_tests` use bash; avoid bashisms in `sh` scripts unless the file already uses bash.

## Testing Guidelines
- Framework: `busted` with coverage via `luacov` (run by `./run_tests`).
- Test locations:
- Package tests: `packages/<pkg>/tests/test_*.lua`
- Shared/integration tests: `tests/test_*.lua`
- Focus tests on `packages/pirania/` only; do not add or modify tests for other packages.
- When code uses UCI, prefer `lime.config.get_uci_cursor()` and the helpers in `tests/utils` (see `TESTING.md`).

## Commit & Pull Request Guidelines
- Branch from `master` and target `master` for PRs. Recommended branch format: `<type>/<name>` (e.g., `feature/new-ui`, `fix/bug-123`).
- Commit subjects in this repo are short and lowercase, often prefixed by area (`packages: ...`, `lime-system: ...`, or `fix(scope): ...`). Follow that pattern.
- PRs should include a clear description, reference issues when applicable, and mention test results (e.g., `./run_tests`).

## Developer Notes
- Unit tests require Docker running and a non-root user; see `TESTING.md` for setup details.
- Changes and investigations should stay within `packages/pirania/` unless explicitly requested otherwise.
- For deeper context, consult `CONTRIBUTING.md`, `TESTING.md`, and `HACKING.md`.
852 changes: 852 additions & 0 deletions packages/pirania/ARQUITETURA.md

Large diffs are not rendered by default.

186 changes: 186 additions & 0 deletions packages/pirania/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# IMPLEMENTATION - itens faltando ou quebrados

Este documento responde: **quais itens precisam ser implementados para o Pirania funcionar como esperado** e detalha o que falta em cada um.

Resumo rapido:

- **Para o portal funcionar no basico (voucher e/ou ler-para-acesso):** nada aqui e obrigatorio.
- **Para cumprir o que a configuracao promete ou para compatibilidade com integracoes antigas:** os itens abaixo precisam de implementacao ou ajuste.

---

## 1) Regras por interface (catch_interfaces / catch_bridged_interfaces)

**Status atual:** configuracao existe, mas nao e aplicada nas regras nftables.

**Onde esta o problema:**

- `packages/pirania/files/etc/config/pirania` define `catch_interfaces` e `catch_bridged_interfaces`.
- `packages/pirania/files/usr/bin/captive-portal` le `catch_bridged_interfaces` mas nao usa no nftables.

**Impacto:**

- O portal captura trafego de todas as interfaces, mesmo quando o UCI define quais interfaces deveriam ser capturadas.
- Quem configura isso espera limitar a captura apenas para interfaces especificas.

**O que implementar:**

Opcoes possiveis (escolher uma abordagem consistente):

1) **Aplicar filtro diretamente nas regras** (mais simples):
- Criar um set `pirania-catch-ifaces` (tipo `ifname`).
- Carregar interfaces de `catch_interfaces` e/ou `catch_bridged_interfaces` no set.
- Adicionar `iifname @pirania-catch-ifaces` nas regras de redirect (DNS/HTTP/HTTPS).

2) **Separar o fluxo com `jump`** (mais limpo para manter):
- Criar um chain principal e um chain `pirania_capture`.
- No chain principal, fazer `jump` para `pirania_capture` apenas se `iifname` estiver no set.
- Colocar as regras DNS/HTTP/HTTPS no chain `pirania_capture`.

**Decisao de semantica:**

- Definir se `catch_interfaces` e `catch_bridged_interfaces` somam ou se um sobrescreve o outro.
- Documentar claramente no README e no UCI.

**Criterio de pronto (aceitacao):**

- Se a interface nao estiver na lista, o trafego nao passa pelas regras do Pirania.
- Se estiver, o comportamento continua o mesmo de hoje.

---

## 2) Opcao append_nft_rules

**Status atual:** opcao existe, mas a logica esta comentada e o comportamento nao muda.

**Onde esta o problema:**

- `packages/pirania/files/etc/config/pirania` tem `append_nft_rules`.
- `packages/pirania/files/usr/bin/captive-portal` tem codigo comentado para decidir entre add/insert.
- O script sempre recria a tabela, entao **append vs insert nao faz diferenca**.

**Impacto:**

- Quem tenta usar `append_nft_rules` nao ve efeito algum.
- A opcao passa a ser enganosa.

**O que implementar (duas possibilidades):**

A) **Remover a opcao** (se ela nao faz sentido no desenho atual).

B) **Tornar a opcao funcional** (mais trabalho):

- Parar de apagar a tabela inteira a cada start/update.
- Se `append_nft_rules=0`, inserir regras no inicio do chain (ex.: `nft insert rule ... position 0`).
- Se `append_nft_rules=1`, adicionar regras no fim (`nft add rule ...`).
- Garantir que as regras de Pirania nao sejam duplicadas (verificar antes de inserir).

**Criterio de pronto (aceitacao):**

- Ao alternar a opcao, a ordem de regras muda e o efeito e observavel.
- Documentacao atualizada explicando quando usar.

---

## 3) portal_url via ubus/rpcd

**Status atual:** API existe, mas a configuracao `portal_url` nao aparece no UCI e nao e usada pelo fluxo real.

**Onde esta o problema:**

- `packages/pirania/files/usr/libexec/rpcd/pirania` expoe `show_url` e `change_url` para `pirania.base_config.portal_url`.
- Essa chave nao existe em `packages/pirania/files/etc/config/pirania`.
- O redirecionamento real usa `portal_domain` + `url_auth`/`url_portal`.

**Impacto:**

- Ferramentas que usam `show_url/change_url` nao conseguem alterar o comportamento real do portal.

**O que implementar (escolher um caminho):**

A) **Remover a API legacy** (se nao e usada).

B) **Reativar `portal_url`** (compatibilidade retro):

- Adicionar `option portal_url` no UCI.
- Atualizar `packages/pirania/files/www/pirania-redirect/redirect` para usar `portal_url` quando definido.
- Definir prioridade clara: `portal_url` sobrescreve `portal_domain + url_*` ou apenas complementa.

C) **Migrar API para o modelo atual**:

- Substituir `show_url/change_url` por getters/setters de `portal_domain` + `url_auth`/`url_portal`.
- Manter nomes antigos mas implementar dentro da nova logica, se houver dependencia de compatibilidade.

**Criterio de pronto (aceitacao):**

- Alterar via ubus reflete no redirect do portal.
- UCI e README documentam o comportamento final.

---

## 4) CGI `client_ip` legado

**Status atual:** endpoint referenciado no pacote, mas depende de modulos que nao existem.

**Onde esta o problema:**

- `packages/pirania/files/www/cgi-bin/pirania/client_ip` usa `voucher.logic` e `voucher.db`, que nao existem.

**Impacto:**

- O endpoint esta quebrado se for chamado.
- Pode gerar erros 500 e confundir integracoes antigas.

**O que implementar:**

A) **Atualizar para as bibliotecas atuais**:

- Trocar para `voucher.utils` e `voucher.vouchera`.
- Usar `utils.getIpv4AndMac(os.getenv('REMOTE_ADDR'))`.
- Determinar `valid` com `portal.get_authorized_macs()` ou `vouchera.is_mac_authorized` (dependendo de `with_vouchers`).
- Manter o mesmo formato JSON: `{ ip, mac, valid }`.

B) **Remover o endpoint** se nao houver consumo real.

**Criterio de pronto (aceitacao):**

- O CGI responde JSON valido com `ip`, `mac`, `valid`.
- Nao depende de modulos inexistentes.

---

## 5) Hooks para sincronizacao de vouchers

**Status atual:** o mecanismo existe no Pirania, mas o pacote nao inclui scripts de hook.

**Contexto:**

- `packages/pirania/files/usr/lib/lua/voucher/hooks.lua` executa scripts em `hooks_path`.
- O `hooks_path` default e `/etc/pirania/hooks/`.
- O pacote `shared-state-pirania` (dependencia declarada) costuma prover os scripts reais.

**Impacto:**

- Se `shared-state-pirania` nao estiver instalado ou nao configurar hooks, os vouchers nao sao sincronizados entre nos.
- O portal funciona, mas os vouchers ficam locais.

**O que implementar (se a sincronizacao for esperada):**

- Garantir que o pacote `shared-state-pirania` instale scripts em `/etc/pirania/hooks/`.
- Confirmar que o `hooks_path` do UCI aponta para esse local.
- Documentar claramente essa dependencia no README.

**Criterio de pronto (aceitacao):**

- Ao criar/invalidar voucher em um no, a mudanca aparece nos demais (via shared-state).

---

## O que e realmente necessario para o Pirania funcionar

**Funciona no basico sem implementar nada acima**, porque:

- O portal captura trafego com nftables e redireciona corretamente.
- O modo voucher e o modo ler-para-acesso funcionam.

Os itens acima sao **complementos esperados** por configuracoes, integracoes ou uso legado. Se a expectativa do projeto inclui esses comportamentos, eles precisam de implementacao.
10 changes: 5 additions & 5 deletions packages/pirania/Leeme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Estas son las características implementadas hasta ahora:

## Requisitos previos

Este software corre sobre la distribución OpenWrt (ya que utiliza [UCI](https://openwrt.org/docs/techref/uci) para su configuración). Los paquetes `ip6tables-mod-nat` y `ipset` deben estar instalados.
Este software corre sobre la distribución OpenWrt (ya que utiliza [UCI](https://openwrt.org/docs/techref/uci) para su configuración). Debe estar instalado el paquete `nftables` (provee el comando `nft` y los módulos del kernel necesarios).

## Instalar

Expand All @@ -26,7 +26,7 @@ Este software corre sobre la distribución OpenWrt (ya que utiliza [UCI](https:/

# Cómo funciona

Utiliza las reglas de iptables para filtrar el tráfico hacia fuera de la red mesh.
Utiliza las reglas de nftables para filtrar el tráfico hacia fuera de la red mesh.

## Vista general de la jerarquía y funciones de los archivos

Expand All @@ -40,7 +40,7 @@ La siguiente lista tiene como objetivo explicar qué funcionalidad de Pirania es

* `/usr/lib/lua/voucher/` contiene bibliotecas lua que son utilizadas por /usr/bin/voucher
* `/usr/bin/voucher``/usr/bin/voucher` es una interfaz de línea de comandos (CLI) que maneja una base de datos (que incluye funciones de muestra como `show_active, show_authorized_macs, add, activate, deactivate e is_mac_authorized)`
* `/usr/bin/captive-portal` configura las reglas de iptables para la captura de tráfico
* `/usr/bin/captive-portal` configura las reglas de nftables para la captura de tráfico

* `/usr/libexec/rpcd/pirania` ubus de pirania (utilizada por el frontend web)
* `/usr/share/rpcd/acl.d/pirania.json` Lista de control de accesos (ACL) para la API de pirania
Expand All @@ -49,8 +49,8 @@ La siguiente lista tiene como objetivo explicar qué funcionalidad de Pirania es
* `/usr/lib/lua/read_for_access` contiene la librería que usa `/usr/lib/lua/portal` para manejar el modo "leer para acceder" (es decir, sin vouchers)
### Captura de tráfico

`/usr/bin/captive-portal` configura las reglas de iptables para captura de tráfico.
Crea un grupo de reglas que se aplican a tres grupos de direcciones IPs (usando el módulo ipset de iptables) habilitados:
`/usr/bin/captive-portal` configura las reglas de nftables para captura de tráfico.
Crea un grupo de reglas que se aplican a tres conjuntos nativos de nftables habilitados:
* `pirania-auth-macs`: la lista de mac autorizadas. comienza vacía.
* `pirania-allowlist-ipv4`: contiene los miembros de clientes permitidos `allowlist` en el archivo de configuración (`10.0.0.0/8`, `192.168.0.0/16`, `172.16.0.0/12``172.16.0.0/12`)
* `pirania-allowlist-ipv6`: lo mismo que la lista anterior pero para ipv6
Expand Down
4 changes: 2 additions & 2 deletions packages/pirania/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ define Package/$(PKG_NAME)
CATEGORY:=Network
MAINTAINER:=Asociación Civil AlterMundi <info@altermundi.net>
TITLE:=Captive portal with vouchers.
DEPENDS:=+ip6tables-mod-nat +ipset +shared-state +shared-state-pirania \
DEPENDS:=+nftables +kmod-nft-bridge +shared-state +shared-state-pirania \
+uhttpd-mod-lua +lime-system +luci-lib-jsonc \
+liblucihttp-lua +luci-lib-nixio +libubus-lua +libuci-lua
+luci-lib-nixio +libubus-lua +libuci-lua
PKGARCH:=all
endef

Expand Down
93 changes: 93 additions & 0 deletions packages/pirania/PIRANIA_FLUXO_SIMPLIFICADO.pt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Pirania: como funciona (bem simples)

Este texto explica o Pirania como se fosse para uma crianca pequena, mas sem perder o caminho real das pecas do sistema.

## A ideia geral (bem simples)

Pense no Pirania como um **porteiro** de um predio:

- Se voce **nao tem permissao**, o porteiro te leva para a recepcao (o portal).
- La voce **mostra seu voucher** ou **espera um tempinho** (ler-para-acesso).
- Depois disso, o porteiro **coloca seu nome na lista** e voce pode entrar.

## As pecas principais (quem faz o que)

- **Capturador de trafego (nftables)**: o porteiro que decide quem pode passar.
- **DNS local (pirania-dnsmasq)**: o guia que responde “o portal fica aqui”.
- **Redirecionador HTTP (pirania-uhttpd + redirect)**: o guia que aponta a porta certa.
- **Portal (paginas em /www/portal/)**: o lugar onde a pessoa digita o voucher ou espera o tempo.
- **CGI handlers**: os ajudantes que escrevem na lista de permitidos.
- **Banco de vouchers (arquivos JSON)**: a caixinha onde os vouchers ficam guardados.
- **Lista de MACs autorizados**: a lista que libera os dispositivos.

## Fluxo de um pacote (o que acontece quando um pacote chega)

1. **Chega um pacote do dispositivo da pessoa**.
2. O **nftables** pergunta: “Esse MAC esta autorizado?”
3. Se **nao** estiver autorizado:
- DNS vai para **porta 59053** (pirania-dnsmasq).
- HTTP vai para **porta 59080** (pirania-uhttpd).
- HTTPS e bloqueado.
4. O **pirania-uhttpd** redireciona a pessoa para o portal.
5. A pessoa **digita o voucher** ou **espera o tempo**.
6. O CGI **autoriza o MAC**.
7. O Pirania **atualiza o nftables**.
8. O proximo pacote **passa normalmente**.

## Diagrama Mermaid (fluxo simples)

```mermaid
flowchart TD
A[Dispositivo envia pacote] --> B{MAC autorizado?}

B -- sim --> C[Pacote passa<br/>Internet normal]

B -- nao --> D[Captura no nftables]
D --> E[DNS -> 59053<br/>pirania-dnsmasq]
D --> F[HTTP -> 59080<br/>pirania-uhttpd]
D --> G[HTTPS bloqueado]

F --> H[Redirect para portal<br/>/portal/*]
H --> I{Modo de acesso}

I -- voucher --> J[Pessoa digita voucher]
I -- ler-para-acesso --> K[Pessoa espera tempo]

J --> L[CGI ativa voucher<br/>associa MAC]
K --> M[CGI autoriza MAC<br/>por tempo]

L --> N[Atualiza nftables<br/>captive-portal update]
M --> N
N --> C
```

## O mesmo fluxo, so que com palavras super simples

- O Pirania olha quem chegou.
- Se a pessoa **nao esta na lista**, ele mostra o portal.
- A pessoa faz a “tarefa” (voucher ou esperar).
- O Pirania coloca o MAC na lista.
- Pronto: agora o acesso passa livre.

## Diferencas entre os dois modos

- **Voucher**: precisa de um codigo. O MAC fica autorizado enquanto o voucher estiver ativo.
- **Ler-para-acesso**: so espera um tempo. O MAC fica autorizado por alguns minutos.

## Onde cada parte vive no projeto (referencia)

- Captura de trafego: `packages/pirania/files/usr/bin/captive-portal`
- DNS local: `packages/pirania/files/etc/init.d/pirania-dnsmasq`
- Redirect HTTP: `packages/pirania/files/etc/init.d/pirania-uhttpd`
- Script de redirect: `packages/pirania/files/www/pirania-redirect/redirect`
- Portal (paginas): `packages/pirania/files/www/portal/`
- CGI handlers:
- `packages/pirania/files/www/cgi-bin/pirania/preactivate_voucher`
- `packages/pirania/files/www/cgi-bin/pirania/activate_voucher`
- `packages/pirania/files/www/cgi-bin/pirania/authorize_mac`
- Logica de vouchers: `packages/pirania/files/usr/lib/lua/voucher/`
- Logica ler-para-acesso: `packages/pirania/files/usr/lib/lua/read_for_access/`

---

Se quiser, posso adicionar um diagrama mais tecnico (com portas, processos e arquivos) ou um diagrama separado so para o modo voucher.
Loading