mirror of
https://github.com/archr-linux/Arch-R.git
synced 2026-07-12 18:19:42 -07:00
wifictl: corrigir trava de conexão com senha/SSID especiais
Vários edge cases no fluxo de conexão WiFi com caracteres não-ASCII / metacaracteres causavam o sintoma reportado "trava ao conectar": 1. iwd codifica caracteres não ([A-Za-z0-9._-]) no nome do .psk como =XX (man iwd.network "Network file names"). wifictl gravava o profile como /var/lib/iwd/<SSID literal>.psk — quando o SSID tinha espaço, ç, +, /, etc. iwd não encontrava o arquivo, o iwctl station connect caía em prompt interativo aguardando passphrase via stdin e ficava preso até o autoconnect timeout (30+s). encode_iwd_ name aplica a transformação canônica byte-a-byte (validado com "Café" -> "Caf=C3=A9", "DIRECT-17-HP Douglas" -> "DIRECT-17-HP=20 Douglas"). 2. Senhas fora do intervalo válido (WPA-PSK: 8..63 bytes printable ou 64 hex chars) também faziam iwd rejeitar o profile e cair no mesmo trava-no-prompt-stdin. wifictl agora rejeita cedo com retorno 2 e mensagem em stderr, dando feedback útil para a UI. 3. Profile órfão de tentativa anterior podia conflitar: ao trocar entre rede aberta e WPA, ou ao mudar a senha, o iwd preferia o profile antigo (.open / .psk). Agora wifictl remove os dois antes de regravar. 4. O check de pós-conexão era frouxo: "state=connected" sozinho retornava sucesso quando a estação já estava em outra rede, mesmo que a conexão solicitada falhasse silenciosamente. Adicionado match contra "Connected network" do iwctl show. 5. O heredoc do create_adhoc usava <<EOF (não-quoted) — um $ literal na passphrase disparava expansão de variável bash. Substituído por printf %s para preservar a senha byte-a-byte. 6. /var/lib/iwd/*.psk passa a ser criado com umask 077 — a passphrase está em texto claro no arquivo e não deveria ser legível por nada além do iwd (rodando como root). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -66,13 +66,57 @@ connect_wifi() {
|
||||
iwctl device ${WIFI_DEV} set-property Mode station 2>/dev/null
|
||||
sleep 1
|
||||
|
||||
# Validar a passphrase. WPA-PSK exige 8..63 bytes de printable ASCII
|
||||
# ou exatamente 64 hex chars. Um PSK fora desse intervalo faz iwd
|
||||
# rejeitar o profile e o iwctl connect ficar esperando passphrase via
|
||||
# stdin — wifictl não tem TTY, então o iwctl trava até o timeout do
|
||||
# autoconnect (30+s). Falhar cedo dá feedback útil para a UI no ES.
|
||||
if [ -n "${PSK}" ]; then
|
||||
PSK_LEN=$(printf '%s' "${PSK}" | wc -c)
|
||||
if [ "${PSK_LEN}" -lt 8 ] || [ "${PSK_LEN}" -gt 63 ]; then
|
||||
if [ "${PSK_LEN}" -ne 64 ] || ! printf '%s' "${PSK}" | grep -qE '^[0-9a-fA-F]{64}$'; then
|
||||
echo "wifictl: passphrase has ${PSK_LEN} bytes; WPA-PSK accepts 8-63 printable bytes or 64 hex chars" >&2
|
||||
return 2
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# iwd codifica caracteres não-imprimíveis e alguns metacaracteres do
|
||||
# SSID como =XX no nome do .psk (man iwd.network "Network file names").
|
||||
# Sem isso, redes com espaços, +, /, etc. no SSID têm o arquivo
|
||||
# gravado em um nome que iwd não procura, e o iwctl cai em prompt
|
||||
# interativo aguardando a passphrase — sintoma visível como "trava".
|
||||
# encode_iwd_name implementa a transformação canônica.
|
||||
encode_iwd_name() {
|
||||
printf '%s' "$1" | awk '
|
||||
BEGIN { for (i = 0; i < 256; i++) byteToChar[sprintf("%c", i)] = sprintf("%02x", i) }
|
||||
{
|
||||
out = ""
|
||||
n = length($0)
|
||||
for (i = 1; i <= n; i++) {
|
||||
c = substr($0, i, 1)
|
||||
# iwd allows: letters, digits, ".", "-", "_". Outros = hex.
|
||||
if (c ~ /[A-Za-z0-9._-]/) out = out c
|
||||
else out = out "=" toupper(byteToChar[c])
|
||||
}
|
||||
print out
|
||||
}'
|
||||
}
|
||||
IWD_NAME=$(encode_iwd_name "${SSID}")
|
||||
|
||||
# Create iwd network profile for persistent connection
|
||||
IWD_DIR="/var/lib/iwd"
|
||||
mkdir -p "${IWD_DIR}"
|
||||
# Limpa qualquer perfil antigo para o mesmo SSID antes de regravar
|
||||
# (caso usuário mude entre rede aberta e PSK, ou troque a senha — sem
|
||||
# o rm o iwd pode preferir o profile antigo conflitante).
|
||||
rm -f "${IWD_DIR}/${IWD_NAME}.psk" "${IWD_DIR}/${IWD_NAME}.open" 2>/dev/null
|
||||
if [ -n "${PSK}" ]; then
|
||||
printf '[Security]\nPassphrase=%s\n' "${PSK}" > "${IWD_DIR}/${SSID}.psk"
|
||||
# umask 077 antes do printf garante que o profile (com a senha em
|
||||
# texto) não fique world-readable em /var/lib/iwd.
|
||||
( umask 077; printf '[Security]\nPassphrase=%s\n' "${PSK}" > "${IWD_DIR}/${IWD_NAME}.psk" )
|
||||
else
|
||||
printf '[Security]\n' > "${IWD_DIR}/${SSID}.open"
|
||||
printf '[Security]\n' > "${IWD_DIR}/${IWD_NAME}.open"
|
||||
fi
|
||||
|
||||
# Scan and connect
|
||||
@@ -80,10 +124,19 @@ connect_wifi() {
|
||||
sleep 2
|
||||
iwctl station ${WIFI_DEV} connect "${SSID}" 2>/dev/null
|
||||
|
||||
# Wait for connection
|
||||
# Wait for connection. O "state=connected" sozinho não basta: se a
|
||||
# estação já estava em outra rede o teste retornaria sucesso falso.
|
||||
# Comparar também o "Connected network" com o SSID solicitado.
|
||||
for i in $(seq 1 15); do
|
||||
STATE=$(iwctl station ${WIFI_DEV} show 2>/dev/null | grep -i "state" | awk '{print $NF}')
|
||||
[ "${STATE}" = "connected" ] && return 0
|
||||
SHOW=$(iwctl station ${WIFI_DEV} show 2>/dev/null)
|
||||
STATE=$(printf '%s\n' "${SHOW}" | awk '/^[[:space:]]*State[[:space:]]/ {print $NF}')
|
||||
NET=$(printf '%s\n' "${SHOW}" | sed -n 's/^[[:space:]]*Connected network[[:space:]]*//p')
|
||||
# Trim espaços ao redor do nome da rede
|
||||
NET="${NET#"${NET%%[![:space:]]*}"}"
|
||||
NET="${NET%"${NET##*[![:space:]]}"}"
|
||||
if [ "${STATE}" = "connected" ] && [ "${NET}" = "${SSID}" ]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
return 1
|
||||
@@ -92,20 +145,30 @@ connect_wifi() {
|
||||
create_adhoc() {
|
||||
wait_for_wifi
|
||||
|
||||
# Create an iwd AP profile file
|
||||
cat <<EOF >"${IWD_AP_CFG_DIR}/${SSID}.ap"
|
||||
[General]
|
||||
Channel=${ADHOC_CHAN}
|
||||
DisableHT=true
|
||||
# Heredoc com EOF não-quoted permitia que um $ na senha disparasse
|
||||
# expansão de variável bash; agora montamos o profile com printf %s
|
||||
# para preservar a passphrase byte-a-byte. AP filename usa o mesmo
|
||||
# encoding de connect_wifi.
|
||||
IWD_NAME=$(printf '%s' "${SSID}" | awk '
|
||||
BEGIN { for (i = 0; i < 256; i++) bc[sprintf("%c", i)] = sprintf("%02x", i) }
|
||||
{ out=""; n=length($0)
|
||||
for (i = 1; i <= n; i++) {
|
||||
c = substr($0, i, 1)
|
||||
if (c ~ /[A-Za-z0-9._-]/) out = out c
|
||||
else out = out "=" toupper(bc[c])
|
||||
}
|
||||
print out }')
|
||||
|
||||
[Security]
|
||||
Passphrase=${PSK}
|
||||
|
||||
[IPv4]
|
||||
Address=${NETWORK_ADDRESS}.${ADHOC_CLIENT_ID}
|
||||
Netmask=255.255.255.0
|
||||
Gateway=${NETWORK_ADDRESS}.${ADHOC_CLIENT_ID}
|
||||
EOF
|
||||
mkdir -p "${IWD_AP_CFG_DIR}"
|
||||
( umask 077
|
||||
{
|
||||
printf '[General]\nChannel=%s\nDisableHT=true\n\n' "${ADHOC_CHAN}"
|
||||
printf '[Security]\nPassphrase=%s\n\n' "${PSK}"
|
||||
printf '[IPv4]\nAddress=%s.%s\nNetmask=255.255.255.0\nGateway=%s.%s\n' \
|
||||
"${NETWORK_ADDRESS}" "${ADHOC_CLIENT_ID}" \
|
||||
"${NETWORK_ADDRESS}" "${ADHOC_CLIENT_ID}"
|
||||
} > "${IWD_AP_CFG_DIR}/${IWD_NAME}.ap"
|
||||
)
|
||||
|
||||
iwctl device ${WIFI_DEV} set-property Mode ap
|
||||
# Start the AP profile
|
||||
@@ -114,7 +177,19 @@ EOF
|
||||
|
||||
destroy_adhoc() {
|
||||
iwctl ap ${WIFI_DEV} stop 2>/dev/null
|
||||
# Apaga ambos os possíveis nomes (versão antiga sem encoding + nova
|
||||
# com encoding) para não deixar profile órfão depois do upgrade.
|
||||
rm -f "${IWD_AP_CFG_DIR}/${SSID}.ap" 2>/dev/null
|
||||
IWD_NAME=$(printf '%s' "${SSID}" | awk '
|
||||
BEGIN { for (i = 0; i < 256; i++) bc[sprintf("%c", i)] = sprintf("%02x", i) }
|
||||
{ out=""; n=length($0)
|
||||
for (i = 1; i <= n; i++) {
|
||||
c = substr($0, i, 1)
|
||||
if (c ~ /[A-Za-z0-9._-]/) out = out c
|
||||
else out = out "=" toupper(bc[c])
|
||||
}
|
||||
print out }')
|
||||
rm -f "${IWD_AP_CFG_DIR}/${IWD_NAME}.ap" 2>/dev/null
|
||||
}
|
||||
|
||||
has_ap_mode() {
|
||||
|
||||
Reference in New Issue
Block a user