65 lines
1.6 KiB
Python
Executable file
65 lines
1.6 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""
|
|
check_captive_users.py -- Expire captive portal sessions.
|
|
|
|
Runs every 5 minutes (systemd timer installed by core.py --apply).
|
|
Queries .client-credentials for sessions past their expiry time,
|
|
deletes them, and appends disallow commands to .captive-queue so
|
|
do_captive_queue.sh removes the corresponding nftables entries.
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
import sqlite3
|
|
from pathlib import Path
|
|
|
|
SCRIPT_DIR = Path(__file__).parent
|
|
DB_FILE = SCRIPT_DIR / ".client-credentials"
|
|
QUEUE_FILE = SCRIPT_DIR / ".captive-queue"
|
|
|
|
|
|
def main():
|
|
if not DB_FILE.exists():
|
|
return
|
|
|
|
try:
|
|
conn = sqlite3.connect(DB_FILE)
|
|
conn.row_factory = sqlite3.Row
|
|
except Exception as e:
|
|
print(f"check_captive_users: cannot open {DB_FILE}: {e}", file=sys.stderr)
|
|
return
|
|
|
|
now = int(time.time())
|
|
|
|
try:
|
|
expired_ips = [
|
|
row["ip"]
|
|
for row in conn.execute(
|
|
"SELECT ip FROM sessions WHERE expires_at IS NOT NULL AND expires_at <= ?",
|
|
(now,),
|
|
)
|
|
]
|
|
except sqlite3.OperationalError:
|
|
conn.close()
|
|
return
|
|
|
|
if not expired_ips:
|
|
conn.close()
|
|
return
|
|
|
|
conn.execute(
|
|
"DELETE FROM sessions WHERE expires_at IS NOT NULL AND expires_at <= ?",
|
|
(now,),
|
|
)
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
lines = "".join(f"disallow {ip}\n" for ip in expired_ips)
|
|
with open(QUEUE_FILE, "a") as f:
|
|
f.write(lines)
|
|
|
|
print(f"check_captive_users: queued disallow for {len(expired_ips)} expired session(s).")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|