wifidog的做法是先全部黑名单,然后再放行白名单的做法。
1. wifidog流程
wifidog由两部分组成,一个是运行在路由器上的程序,另一部分是运行在认证服务器上的程序。
wifidog的认证流程大致是:
- 1.首先,用户的终端可以连接上wifi,然后发起访问网站的请求,如www.baidu.com;
- 2.网关根据防火墙规则,将用户的请求重定向到本地端口(wifidog的监听端口2060);
- 3.网关将用户的访问重定向到认证服务器上的认证页面;
- 4.认证服务器返回登录页面至用户;
- 5.用户再向认证服务器提供凭据,如用户名和密码;
- 6.认证服务器根据用户提供的凭据来确定用户是否符合要求,是否可以上网;
- 7.如果符合要求,认证服务器将用户的访问重定向至路由器的网关并携带标识token;
- 8.网关向认证服务器确认用户信息;
- 9.如果符合要求,服务器向用户返回登录成功页面;
- 10.用户就可以上网了。
wifidog监听2060端口
用户的请求会被重定向2060端口,所以wifidog里面的http会使用socket绑定2060端口并监听,挂载一个回调函数。
回调函数主要用于根据用户http报文执行不同的操作,其原理就是分析http报文请求中有没有关键路径,若有,则执行关键路径对应的回调函数,若没有,则返回一个重定向到认证服务器的包给用户。一次典型的流程为
用户连接无线AP,访问某网站(比如http://www.baidu.com)
wifidog获取到此http报文,检查是否包含关键路径,没有则返回重定向包给用户,将其重定向到认证服务器
用户认证成功,认证服务器将用户重定向到无线AP网关,并包含关键路径"/wifidog/auth"和token
wifidog接收到用户重定向后访问的报文,检测到关键路径"/wifidog/auth",然后访问认证服务器进行token认证
认证成功,wifidog修改iptables放行此用户(根据mac和ip进行放行)
2. wifidog-gateway代码流程
从gw_main()函数开始看
int main(int argc, char **argv)
{
return gw_main(argc, argv);
}
先读取/etc/wifidog.conf里面的配置信息
config_read("/etc/wifidog.conf")
然后就是下面两个函数了
append_x_restartargv();
main_loop();
main_loop里面第一个就是http对于2060端口的监听,iptable转发是要把数据转到这个端口。
if ((webserver = httpdCreate(config->gw_address, config->gw_port)) == NULL) {
debug(LOG_ERR, "Could not create web server: %s", strerror(errno));
exit(1);
}
然后根据请求的各个消息添加对应的回调函数
debug(LOG_DEBUG, "Assigning callbacks to web server");
httpdAddCContent(webserver, "/", "wifidog", 0, NULL, http_callback_wifidog);
httpdAddCContent(webserver, "/wifidog", "", 0, NULL, http_callback_wifidog);
httpdAddCContent(webserver, "/wifidog", "about", 0, NULL, http_callback_about);
httpdAddCContent(webserver, "/wifidog", "status", 0, NULL, http_callback_status);
httpdAddCContent(webserver, "/wifidog", "auth", 0, NULL, http_callback_auth);
httpdAddCContent(webserver, "/wifidog", "disconnect", 0, NULL, http_callback_disconnect);
httpdSetErrorFunction(webserver, 404, http_callback_404);
匹配到的则直接到对应的回调函数里面处理。
接下去创建了三个线程
第一个thread_client_timeout_check
,根据wifidog.conf配置文件里面的ClientTimeout定时发送每个客户端的流量、在线离线等信息给服务器,对于流量限制的服务商可以做进一步控制作用。
/* Start clean up thread */
result = pthread_create(&tid_fw_counter, NULL, (void *)thread_client_timeout_check, NULL);
if (result != 0) {
debug(LOG_ERR, "FATAL: Failed to create a new thread (fw_counter) - exiting");
termination_handler(0);
}
https://www.jianshu.com/p/8214553218b1
第二个thread_wdctl
/* Start control thread */
result = pthread_create(&tid, NULL, (void *)thread_wdctl, (void *)safe_strdup(config->wdctl_sock));
if (result != 0) {
debug(LOG_ERR, "FATAL: Failed to create a new thread (wdctl) - exiting");
termination_handler(0);
}
pthread_detach(tid);
第三个thread_ping
,会根据wifidog.conf配置文件里面的CheckInterval定时发送网关的uptime、meminfo、meminfo等信息给服务器
/* Start heartbeat thread */
result = pthread_create(&tid_ping, NULL, (void *)thread_ping, NULL);
if (result != 0) {
debug(LOG_ERR, "FATAL: Failed to create a new thread (ping) - exiting");
termination_handler(0);
}
pthread_detach(tid_ping);
https://www.jianshu.com/p/973e22bac26a
最后就是while循环,里面监听http端口的信息,然后处理,
3. iptables三个表各自做什么功能
wifidog操作了三个表,
3.1 filter表
对于filter表在FORWARD的转发规则上面加了WiFiDog_br-lan_Internet规则
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
12717 772K WiFiDog_br-lan_Internet all -- br-lan * 0.0.0.0/0 0.0.0.0/0
0 0 delegate_forward all -- * * 0.0.0.0/0 0.0.0.0/0
用做wifidog.conf里面的FirewallRuleSet使用,会将转发的数据包做白名单allow,黑名单block。比如对于外部设备的dns,icmp,dhcp等协议放行。
3.2 nat表
在入口PREROUTING链上面做了两件事情,一个就是重定向规则,另一个就是设置mark标记位,用来给magle表使用
Chain WiFiDog_br-lan_Unknown (1 references)
pkts bytes target prot opt in out source destination
8779 551K WiFiDog_br-lan_AuthServers all -- * * 0.0.0.0/0 0.0.0.0/0
8779 551K WiFiDog_br-lan_Global all -- * * 0.0.0.0/0 0.0.0.0/0
916 54972 REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 redir ports 2060
Chain WiFiDog_br-lan_Internet (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 mark match 0x2
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 mark match 0x1
8779 551K WiFiDog_br-lan_Unknown all -- * * 0.0.0.0/0 0.0.0.0/0
3.3 mangle表
在nat表里面说到设置mark标志位的使用,当授权通过的外部设备,这时候就会在调用fw_allow
函数,然后在mangle表里面,对PREROUTING和POSTROUTING链做放行规则。
手机:
iptables -t mangle -A WiFiDog_br-lan_Outgoing -s 192.168.18.145 -m mac --mac-source 20:ab:37:8d:c2:f6 -j MARK --set-mark 2
iptables -t mangle -A WiFiDog_br-lan_Incoming -d 192.168.18.145 -j ACCEPT
电脑:
iptables -t mangle -A WiFiDog_br-lan_Outgoing -s 192.168.18.233 -m mac --mac-source d0:17:c2:9a:b7:d1 -j MARK --set-mark 2
iptables -t mangle -A WiFiDog_br-lan_Incoming -d 192.168.18.233 -j ACCEPT
4. 服务器放行
我们在wifidog.conf里面添加了服务器的地址/url,这时候连接服务器函数_connect_auth_server
会去判断是域名还是IP,如果是域名则先获取到IP,然后把访问成功的IP保存在last_ip里面
if (!auth_server->last_ip || strcmp(auth_server->last_ip, ip) != 0) {
/*
* But the IP address is different from the last one we knew
* Update it
*/
debug(LOG_DEBUG, "Level %d: Updating last_ip IP of server [%s] to [%s]", level, hostname, ip);
if (auth_server->last_ip)
free(auth_server->last_ip);
auth_server->last_ip = ip;
/* Update firewall rules */
fw_clear_authservers();
fw_set_authservers();
}
然后fw_set_authservers
函数会将服务器的ip地址放行
Setting the authservers list:
iptables -t filter -A WiFiDog_br-lan_AuthServers -d 192.168.3.185 -j ACCEPT
iptables -t nat -A WiFiDog_br-lan_AuthServers -d 192.168.3.185 -j ACCEPT
可以看到重定向REDIRECT的规则是在lan_AuthServers之后的,lan_AuthServers的操作是ACCEPT,则直接接受,跳出,不会执行后面的重定向规则了。
Chain WiFiDog_br-lan_Unknown (1 references)
pkts bytes target prot opt in out source destination
8779 551K WiFiDog_br-lan_AuthServers all -- * * 0.0.0.0/0 0.0.0.0/0
8779 551K WiFiDog_br-lan_Global all -- * * 0.0.0.0/0 0.0.0.0/0
916 54972 REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 redir ports 2060
这时候外部设备就可以重定向服务器的地址才可以访问成功,否则外部设备是访问不了服务器地址的。
5.本地账号密码登录查看状态
thread_httpd任务
Auth server added
Parsing token: GatewayPort, value: 2060
Parsing token: ProxyPort, value: 0
Parsing token: HTTPDMaxConn, value: 10
Parsing token: HTTPDRealm, value: WiFiDog
Parsing token: HTTPDUserName, value: admin
Parsing token: HTTPDPassword, value: secret
Parsing token: CheckInterval, value: 60
Parsing token: ClientTimeout, value: 5