如何实现强制门户的登录/授权?

如何实现强制门户的登录/授权?

我已经让强制门户正常工作了。现在我遇到的问题是“授权/登录”,我希望客户端在通过门户页面/条件后访问互联网。如何让连接的客户端获得授权并能够访问连接?我使用 NodeJs 作为 Web 服务器。hostapd 和 dnsmasq

配置文件

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
        inet6 fe80::a00:27ff:fe64:8d48  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:64:8d:48  txqueuelen 1000  (Ethernet)
        RX packets 795  bytes 149308 (145.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 841  bytes 153133 (149.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 20  bytes 1200 (1.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 20  bytes 1200 (1.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 10.0.0.1  netmask 255.255.255.0  broadcast 10.0.0.255
        ether ee:1f:08:9a:91:d0  txqueuelen 1000  (Ethernet)
        RX packets 684  bytes 140824 (137.5 KiB)
        RX errors 0  dropped 3  overruns 0  frame 0
        TX packets 1120  bytes 188344 (183.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

主机

interface=wlan0
driver=nl80211
ssid=test
channel=5
hw_mode=g
macaddr_acl=0
ignore_broadcast_ssid=0
dnsmasq

interface=wlan0
dhcp-range=10.0.0.10,10.0.0.25,255.255.255.0,12h
dhcp-option=3,10.0.0.1
dhcp-option=6,10.0.0.1
server=8.8.8.8
log-queries
log-dhcp
listen-address=10.0.0.1
address=/#/10.0.0.1
bogus-priv
domain-needed

Nodejs 服务器

const express = require("express")
const app = express();
const morgan = require("morgan");
const path = require("path");


app.use(morgan("dev"))

const indexPath = path.join(__dirname+"/index.html");

app.get('/generate_204', (req, res)=> { 
    console.log('generate 204 hit'); 
    res.statusCode = 302; 
    res.setHeader("Location", "/");
    res.end();
});

app.get("/", (req,res)=>{
    res.sendFile(indexPath);
    res.status(200);
});

app.listen("80",()=>{
    console.log("Server listen on ",80)
});

iptables 目录

# Generated by iptables-save v1.8.8 (nf_tables) on Sun Sep 11 18:09:51 

2022
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A FORWARD -i wlan0 -j ACCEPT
COMMIT
# Completed on Sun Sep 11 18:09:51 2022
# Generated by iptables-save v1.8.8 (nf_tables) on Sun Sep 11 18:09:51 2022
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Completed on Sun Sep 11 18:09:51 2022

抱歉,我的英文不好,我正在使用谷歌翻译

答案1

要启动并运行强制门户,需要经过多个步骤。

在您开始之前,我建议您在您的机器上设置一个名称服务器,以便您可以在那里处理名称解析(一个仅转发的服务器就足够了),并且您还需要在 wlan0 上设置和运行一个 DHCP 服务器(最好根据 RFC 8910 进行设置以避免潜在的问题,特别是如果您的强制门户要使用 HTTPS)。

首先,确保ipset系统上安装了该程序(您将需要它来授予授权站点访问网络的权限)。接下来,您需要创建一个包含所有授权站点 IP 地址的表。这将达到目的(最好来自/etc/rc.local或者你的发行版中提供的任何早期启动脚本):

/usr/sbin/ipset create AUTHORIZED hash:ip family inet timeout 7200

这将创建一个存储 IP 地址最多两小时(7200 秒)的集合。这些是您的授权地址。

接下来,您需要一个后端脚本,该脚本获取站点的 IP 地址(NodeJS 中应该有一个函数可以执行此操作),该脚本旨在获取对网络的访问权限并将其存储在上述集合中。使用 Perl 我会这样做(这里$station获取请求权限的站点的 IP 地址)- 您必须将其调整为 NodeJS:

system("/usr/sbin/ipset AUTHORIZED $station");

警告:如果你的 NodeJS 没有特权(即没有以),你需要向 sudoers 添加一个条目,以使你的脚本能够根据ipset需要调用此命令权限才能工作。然后您需要确保注册此命令正如你将要调用它一样并在其前面加上无密码:(这样,当您尝试将 IP 地址添加到集合中时,sudo 就不会抱怨缺少密码)。另外,请确保将其放在/usr/bin/sudo字符串的前面!

进入sudoers应该看起来像这样(用于visudo编辑):

nodejs ALL=(ALL) NOPASSWD: /usr/sbin/ipset add AUTHORIZED *

你需要更换nodejs以运行 NodeJS 服务器的用户名称命名,否则命令也不会起作用。此外,由于脚本自行获取注册站的 IP 地址,不依赖任何用户输入,因此可以安全地在此处使用通配符。

然后将这些添加到您的防火墙脚本:

/usr/sbin/iptables -N captive_portal

# In the next statement change the port number to 443 if your captive portal is using HTTPS!
/usr/sbin/iptables -A INPUT -i wlan0 -p tcp --dport 80 -j ACCEPT
# The following line also requires a configured and running name server!
/usr/sbin/iptables -A INPUT -i wlan0 -p udp --dport 53 -j ACCEPT

/usr/sbin/iptables -A FORWARD -i wlan0 -j captive_portal

# If an IP address is not found in the set, refuse to forward it.
/usr/sbin/iptables -A captive_portal -m set ! --match-set AUTHORIZED src -j REJECT --reject-with icmp-admin-prohibited
# The following line is necessary to reset the timeout of a particular entry in the set so that active IP addresses aren't expired.
/usr/sbin/iptables -A captive_portal -j SET --add-set AUTHORIZED src --exist
/usr/sbin/iptables -A captive_portal -j ACCEPT

此后您的强制门户就可以正常运行了。

您还可以通过添加注销页面来扩展此功能,这样电台就有明确的选项可以立即注销,而不必等待最多两个小时后条目过期。

在 Perl 中,这将像这样调用(再次$station包含注销站的 IP 地址):

system("/usr/sbin/ipset del AUTHORIZED $station");

再次,您可能需要在 sudoers 中输入才能从脚本调用此命令。

nodejs ALL=(ALL) NOPASSWD: /usr/sbin/ipset del AUHORIZED *

一旦一切准备就绪,您就可以开始了。

关于 sudo 的附注:

如果你必须将任何用户输入传递给需要无论出于何种原因,请确保通过适当的条目缩小权限范围sudoers或者,如果你在这种情况下必须使用通配符,请确保彻底消毒任何和所有用户输入并过滤任何可能存在潜在危险的内容(保留已批准输入的白名单是最可行的选择)。否则,您将面临严重的安全漏洞,甚至导致您的系统完全无法运行!

相关内容