(iptables) 自制简单Wi-Fi Captive Portal(无线认证门户),支持树莓派

Posted by

on

Introduction

本文的研究成果是在 Captive Portal Using PHP and iptables Firewall on Linux 的基础上完成的。适用于任何使用 iptables 来共享上网的 Linux 软路由,因此,本迷你 Portal 也支援在树莓派上搭建。使用的原料:一台认证服务器(装有 PHP + MySQL),一台 Linux 接入路由。

Improvements on original plan

  • 提供多帐号认证功能与用户数据库认证方案
  • 认证端与接入端隔离(当然,如果搭建在树莓派等迷你平台上,不需要这样麻烦)
  • 在原方案中,认证代码直接调用系统 shell,具有一定危险性,本方案改进为使用回调接口来通知上下线功能
  • 更友好的 UI
  • 原方案仅仅重定向 80 端口用于验证,在登录验证之前,其他端口依然畅通无阻,可以上网通信。在本方案中,未认证用户无法上网。
  • 支持多个接入端统一共享一个认证端认证上网

Basic Concepts

警告:本文章操作具有一定危险性,您的电脑极有可能因为网络操作而断开连接。因此请您后果自负。请将本文章仅仅用在实验或教学目的,因为本文只是用以探讨 Captive Portal 的工作原理,而不是开发和搭建一个可以生产和公开使用的认证系统。如果您觉得本文对您有所帮助,我会非常感激 🙂

首先,我们介绍几点 Wi-Fi Portal 认证工作的基本原理:

  1. 本文假定每位无线用户连接到一个可以访问互联网的网关热点。
  2. 本文假定您已使用 iptables 做好 NAT 网络分享,接入设备的用户现在可以直接访问互联网。
  3. 本文在 Debian 系列系统上测试通过,其他发行版暂未测试。
  4. 用户的接入点本身就是网关。
  5. 每个未认证用户发给互联网的 HTTP 数据包都被使防火墙(iptables)用特殊的代码标记以便我们进一步处理将其重定向到 Portal 页面。
  6. Portal Web 服务器透明地给每位接入用户提供认证页面并识别他们电脑的 MAC 地址。
  7. 通过认证的用户的设备 MAC 将被加入防火墙(iptables)的白名单,因此可以无限制地上网,他们的数据包不会被继续做标记。

Set-up a captive portal

1. 安装 conntrack

sudo apt-get install conntrack

2. 新建并编辑文件 /usr/bin/rmtrack (用于删除用户连接跟踪轨迹),并设置权限

nano /usr/bin/rmtrack

#!/bin/bash
/usr/sbin/conntrack -L |grep $1 |grep ESTAB |grep 'dport=80' |awk"{ system("conntrack -D --orig-src $1 --orig-dst " substr($6,5) " -p tcp --orig-port-src " substr($7,7) " --orig-port-dst 80"); }"

chmod 755 /usr/bin/rmtrack

3. 为 Web 服务器的执行用户开放免密码 sudo 权限

sudo visudo

插入以下内容并保存(假定 www-data 为 Web 服务器的执行用户)
www-data ALL=NOPASSWD: /usr/sbin/arp
www-data ALL=NOPASSWD: /sbin/iptables
www-data ALL=NOPASSWD: /usr/bin/rmtrack [0-9]*.[0-9]*.[0-9]*.[0-9]*

4. 实现开机自动设置 iptables 规则,插入如下代码(假定 100.64.0.1 为接入端,172.31.254.100 为 Web Portal 认证端,eth0 为 LAN 网卡接口名称,如果不需要将认证端与接入端分离,请直接将认证端 IP 与接入端 IP 设置为相同内容)

###################################################################
#增加 iptables 规则,创建 portal 认证链
/sbin/iptables -t mangle -N portal
/sbin/iptables -t mangle -A PREROUTING -i eth0 -p tcp -m tcp --dport 1:65534 -j portal
/sbin/iptables -t mangle -A PREROUTING -i eth0 -p udp -m udp --dport 1:65534 -j portal
/sbin/iptables -t nat -A PREROUTING -i eth0 -p tcp -m mark --mark 99 -m tcp --dport 1:65534 -j DNAT --to-destination 100.64.0.1
/sbin/iptables -t mangle -A portal -j MARK --set-mark 99
/sbin/iptables -t mangle -I portal 1 -d 172.31.254.100 -p tcp -m tcp -j RETURN
/sbin/iptables -t mangle -I portal 1 -d 100.64.0.1 -p tcp -m tcp -j RETURN
/sbin/iptables -t mangle -I portal 1 -d 100.64.0.1 -p udp --dport 1:52 -j DROP
/sbin/iptables -t mangle -I portal 1 -d 100.64.0.1 -p udp --dport 54:65534 -j DROP
#未验证用户禁止上网,但排除第三方认证 portal(在 FORWARD 链进行)
/sbin/iptables -t filter -A FORWARD -m mark --mark 99 -j DROP
/sbin/iptables -t filter -A FORWARD -m mark --mark 99 -d 172.31.254.100 -j ACCEPT
#未验证用户禁止上网,但排除第三方认证 portal(在 INPUT 链进行,以防用户使用 squid 等代理上网)
/sbin/iptables -t filter -A INPUT -p tcp --dport 80 -j ACCEPT
/sbin/iptables -t filter -A INPUT -p udp --dport 53 -j ACCEPT
/sbin/iptables -t filter -A INPUT -m mark --mark 99 -j DROP
/sbin/iptables -t filter -A INPUT -m mark --mark 99 -d 172.31.254.100 -j ACCEPT
###################################################################

5. 搭建好 Web 服务器与 PHP 运行环境 ,这里假定使用 nginx。注意 Web 服务器应该仅保留一个默认网站,建议不使用虚拟主机与多站点。因为在用户未认证前,他们的各式各色的 HTTP 请求将会被本 Web 服务器接管。如果仅绑定一个域名,那么其他域名可能会发生 400 Bad Request 错误)在 nginx 的配置文件中,加入一个 URL 重写规则,以将所有页面的请求重写至 index.php 处理。

################################# 核心 URL 重写规则 #####################################
# 将所有 Web 请求都强行重写给 index.php 处理,导向到 Web Portal,并排除 Web Portal 的地址
if ( $remote_addr != "172.31.254.100" )
{

       rewrite /. /index.php last;

}
########################################################################################

6. 分别部署好认证端与接入端的 PHP 页面,如果想让认证与接入同时在一个设备进行,请将认证端页面与接入端页面部署在同一台服务器上。修改 config.php 中的配置:
接入端:

<?php

/*
 iEdon Mini Portal System
*/

// 定义 Web Portal 认证端URL
define('PORTAL_URL', 'http://xxxx');
// 定义本接入端ID
define('NAS_ID', 'iedon-net-access-point');

?>

认证端:

<?php

/*
iEdon Mini Portal System
*/

// 定义 portal 站点名称
define('PORTAL_NAME', 'iEdon-Net');

// 定义底部文字
define('FOOTER_TEXT', '使用 Internet 前请先验证身份');

// 底部版权信息
define('COPYRIGHT', '&copy; 2012-2017 iEdon');

// 定义默认的跳转URL
define('DEFAULT_REDIRECT_URL', 'http://iedon.com');

// MySQL
define('MYSQL_SERVER', '127.0.0.1');
define('MYSQL_USERNAME', 'root');
define('MYSQL_PASSWORD', 'root');
define('MYSQL_DATABASE_NAME', 'iedon_mini_portal');

// 分支接入路由器配置,支持多分支机构。不同的分支机构调用不同的回调接口。
/*  eg:
       define('传递过来的nas参数_URL', '接入分支路由的回调URL');
       define('传递过来的nas参数_NAME', '接入分支路由的友好描述');
*/
define('iedon-net-access-point_URL', 'http://接入端地址/callback.php');
define('iedon-net-access-point_NAME', '办公室网');

?>

7. 导入认证端中的 sql 文件至 MySQL 数据库。确认接入端 config.php 中的连接信息正确无误。

Previews

iEdon Mini Portal Preview

GitHub

https://github.com/iedon/mini-iptables-wifi-portal


14 responses to “(iptables) 自制简单Wi-Fi Captive Portal(无线认证门户),支持树莓派”

  1. 这么说来安卓手机也可以了,建个免费WiFi热点,打个广告,或者做点什么其他用途,貌似不错

    1. 安卓上面可以使用 iptables?而且 iptables 有部分模块是需要加载到内核里面的。

  2. 可以使用哇,很早的时候,安卓2.x的时代好像就有了
    曾经在安卓机上搭过WordPress博客,这样的话条件都具备了

    1. 你的博客怎么打不开了

  3. 我路由器用的老毛子的固件,也是很容易实现

  4. 这个技术难度有点高,感觉搞不来……

  5. 会不会存在折那么漏洞啊?

  6. […] 支持多节点的 Web 认证服务(由于笔者的实验网络在学校有多个接入节点,并且与一些朋友进行了共享,因此研究了一下简易的 Portal 认证系统。具体可以参考笔者 2017 年发布的文章): […]

  7. 您好,您所用的接入端地址是否是eth0 LAN 网卡的地址?Web Server 所在的地址,是无线的地址?

    1. 您好,接入端地址为 LAN 网卡地址。Web Server 所在地址为 portal 地址,只要网络内部可以通达就行。

  8. […] 这里主要介绍第一种,HTTP重定向,通过对防火墙进行设置,来将用户导向认证页面,在用户认证完成后,将用户mac地址添加进防火墙的允许访问列表中。英语好的参考这一篇;中文好的参考这一篇 […]

  9. 未验证用户禁止上网,但排除第三方认证 portal(在 FORWARD 链进行)
    /sbin/iptables -t filter -A FORWARD -m mark –mark 99 -j DROP
    /sbin/iptables -t filter -A FORWARD -m mark –mark 99 -d 172.31.254.100 -j ACCEPT
    感觉上面这两条的顺序应该调换过来吧,如果是发往172.31.254.100的就先接受,否则,就丢弃。

Leave a Reply to 老何 Cancel reply

Your email address will not be published. Required fields are marked *