2015年2月

wifidog 整体代码分析

Wifidog将ping协议作为心跳机制向认证服务器发送当前状态信息,过程如下:

Ping线程的创建

/* Start heartbeat thread */

result =pthread_create(&tid_ping, NULL, (void *)thread_ping, NULL);

if (result != 0) {

    debug(LOG_ERR, "FATAL: Failed tocreate a new thread (ping) - exiting");

    termination_handler(0);

}

pthread_detach(tid_ping);

上面的过程创建子线程后,将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源。并且是非阻塞的。

Thread_ping实现:

void    
thread_ping(void *arg)  
{
       pthread_cond_t             cond = PTHREAD_COND_INITIALIZER;    
       pthread_mutex_t           cond_mutex =PTHREAD_MUTEX_INITIALIZER;    
       struct      timespec  timeout;    

       while (1) {    
              /* Make sure wecheck the servers at the very begining */    
              debug(LOG_DEBUG,"Running ping()");    
              ping();                 

              /* Sleep for config.checkinterval seconds... */

              timeout.tv_sec= time(NULL) + config_get_config()->checkinterval;

              timeout.tv_nsec= 0;    

              /*Mutex must be locked for pthread_cond_timedwait... */

              pthread_mutex_lock(&cond_mutex);

              /*Thread safe "sleep" */

              pthread_cond_timedwait(&cond,&cond_mutex, &timeout);

              /*No longer needs to be locked */

              pthread_mutex_unlock(&cond_mutex);

       }    
}

红色部分为非常优雅的线程休眠,想下为什么不用sleep?用sleep会导致整个进程陷入休眠,不建议使用。

ping的过程:

a. 连接auth服务器
获取auth服务器的个数,wifidog支持备用auth服务器
进行auth服务器尝试计数
进行dns解析、会尝试按顺序对每个auth服务器进行解析,直到解析成功。
dns解析失败,则尝试对www.google.com、"www.yahoo.com"、进行解析,如果解析成功代表网络时通的,如果失败则代表网络不通,直接退出。网络是通的则会进行下一个auth服务器解析
dns解析成功,将auth服务器ip地址记录到auth_server->last_ip中,并进行socket连接
b. 获取本机设备的uptime(系统总运行时间与系统空闲时间)、meminfo、loadavg()信息
/*
loadavg
监控CPU的平均负载、这里的平均负载也就是可运行的进程的平均数
cat /proc/loadavg
前三个值分别对应系统在5分钟、10分钟、15分钟内的平均负载
第四个值的分子是正在运行的进程数,分母是进程总数,最后一个是最近运行的进程ID号
*/
c. 进行请求数据填充,格式如下:

snprintf(request,sizeof(request) - 1,                         "GET%s%sgw_id=%s&sys_uptime=%lu&sys_memfree=%u&sys_load=%.2f&wifidog_uptime=%luHTTP/1.0\r\n"    
                     "User-Agent:WiFiDog %s\r\n"    
                     "Host:%s\r\n"    
                     "\r\n",    
                     auth_server->authserv_path,    
                     auth_server->authserv_ping_script_path_fragment,    
                     config_get_config()->gw_id,   
                     sys_uptime,    
                     sys_memfree,    
                     sys_load,
                         (longunsigned int)((long unsigned int)time(NULL) - (long unsigned int)started_time),    
                     VERSION,    
                     auth_server->authserv_hostname);

Auth服务器在收到‘ping’包后只需要回复PONG字符串即可,这有点像supplicant的回复。
但即使这个过程有问题,也不妨碍wifidog重定向的使用,貌似这个模块的功能仅仅是把设备的状态发送给auth服务器。

流量控制

线程的创建:

/*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 tocreate a new thread (fw_counter) - exiting");

   termination_handler(0);

}

pthread_detach(tid_fw_counter);

这地方和上面讲解的一样,不在重复。

主要函数:fw_sync_with_authserver,改函数的流程如下:

a. 调用iptables_fw_counters_update更新所有client的流程出入统计(利用iptable规则)

b. 遍历clinet list,该list是之前所有登入过的客户端

c. 如果有auth server,将每个client的ip、mac、token、incoming、outgoing发给auth server

d. 进行客户端流量更新超时检测,检测的规则如下:

p1->counters.last_updated+(config->checkinterval * config->clienttimeout)<= current_time

如果满足上面规则,则认为该client是不活动用户,会在iptable规则中删除该用户,清除在client list的记录,并通知auth server 该client REQUEST_TYPE_LOGOUT。

e. 如果上面一些条件不满足,则依据authresponse.authcode返回值进行处理
case AUTH_DENIED:
在iptable规则中删除该用户,清除在client list的记录
case AUTH_VALIDATION_FAILED:
验证超时,在iptable规则中删除该用户,清除在client list的记录
case AUTH_ALLOWED:
将改client fw_connection_state 置为FW_MARK_KNOWN,并将改client添加到允许上网的规则当中
case AUTH_VALIDATION:
不做任何事
case AUTH_ERROR:
不做任何事

认证流程

wifidog-flow-2009.png

用户连接WIFI会跳转到以下地址:

http://auth_server/login?gw_id=[GatewayID, default: "default"]gw_address=[GatewayAddress, internal IP of router]gw_port=[GatewayPort, port that wifidog Gateway is listening on]

url=[user requested url]

auth_server #即认证的域名

gw_id #配置的网关名称

gw_address #回调的内网地址

gw_port #回调的端口

在这个阶段需要返回登录的页面,即授权的首页,并且需要将所有涉及跳转的第三方地址加入白名单
当验证用户身份之后,即用户登录成功之后重定向到网关地址
http://GatewayIP:GatewayPort/wifidog/auth?token=[auth token]
auth token #系统为用户生成的token

网关地址接受到消息后,会周期的发送用户信息,并确认是不是允许继续网络访问请求地址

http://auth_server/auth/index.php?   
stage=counters   
ip=    
mac=    
token=    
incoming=    
outgoing=

ip,mac,token为用户的基本信息,incoming/outgoing为用户的连接计数信息,用来限定用户是否可以继续连接
此时auth_server需要返回该请求:
0——拒绝,删除防火墙内用户以及用户的信息
6——用户验证失败,超时,会删除防火墙内信息(即会重新要求登录)
1——用户验证通过,并跳转到http://auth_server/portal/?gw_id=%s
5——用户需要验证,允许规则内的访问进行验证
-1——用户验证出错,用户可以继续访问网络

返回数据格式:
Auth:
如Auth: 1 #中间有个空格

系统会周期性发送心跳包,用来确认网关验证和认证服务器的正常工作请求地址

http://auth_sever/ping/?
gw_id=%s
sys_uptime=%lu
sys_memfree=%u
sys_load=%.2f
wifidog_uptime=%lu

auth_server此时需要返回“Pong”

可以通过该心跳包来监控整个认证的工作

本文章由 http://www.wifidog.pro/2015/02/13/wifidog%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90-2.html 整理编辑,转载请注明出处

wifidog认证流程及相关重要函数调用

1、The client does his initial request, as if he was already connected, (e.g.: http://www.google.ca)
2、The Gateway’s firewall rules mangle the request to redirect it to a local port on the Gateway. When that’s the done, the Gateway provides an HTTP Redirect reply that contains the Gateway ID, Gateway FQDN and other informations
3、The Client does his request to the Auth Server as specified by the Gateway, see Login Protocol
4、The Gateway replies with a (potentially custom) splash (login) page
5、The Client provides his identification informations (username and password)
6、Upon succesful authentication, the client gets an HTTP Redirect to the Gateway’s own web server with his authentication proof (a one-time token), http://GatewayIP:GatewayPort/wifidog/auth?token=[auth token]
7、The Client then connects to the Gateway and thus gives it his token
8、The Gateway requests validation of the token from the Auth Server, see Client Protocol
9、The Auth Server confirms the token
10、The Gateway then sends a redirect to the Client to obtain the Success Page from the Auth Server, redirects to http://auth_server/portal/
12、The Auth Server notifies the Client that his request was successful

代码:

http_callback_404:
将未认证的请求重定向到Auth Server的登录界面:login页面

http_callback_auth:
客户端登陆成功后,Auth Server将客户端重定向到Gateway,形式如下:http://GatewayIP:GatewayPort/wifidog/auth?token=[auth token]

authenticate_client:
Gateway将拿到的token传给Auth Server,验证客户端,如果客户端被允许,将客户端重定向到Auth Server的portal界面Firewall.c中包含了对iptables相关的操作

本文章由 http://www.wifidog.pro/2015/02/13/wifidog%E8%AE%A4%E8%AF%81%E6%B5%81%E7%A8%8B.html 整理编辑,转载请注明出处

wifidog 工作接口及其特点

portal认证方式有多重,我们选择了十分普遍额开源项目wifidog,支持openwrt,用户群体大,资料较完善,中文资料多。
主要优点:

  1. 开源(https://github.com/wifidog github,上提供了源码及基于php的认证网关源码)
  2. 国内使用wifidog的情况比较普遍,二次开发更容易。

(总结:低成本,易上手。)

目前也存在一定的缺点

  1. 通过实际抓包发现,心跳包不断的检查用户在线情况,网关服务器性能开销较大。
  2. 基于iptables,协议繁琐。
  3. 隐私问题,url直接传递含隐私的信息。

工作机制

/ping 心跳接口

"GET /ping/?gw_id=网关id&sys_uptime=1183&sys_memfree=105884&sys_load=0.14&wifidog_uptime=1169 HTTP/1.0"

/login 新用户认证跳转页面

GET /login/?gw_address=111&gw_port=111&gw_id=111&mac=88:72:0d:f2:88:29&url=url HTTP/1.1

/auth 用户检测

/auth/?stage=counters&ip=192.168.10.81&mac=88:72:0d:f2:a8:29&token=85ea71f2484b2c52fee&incoming=5638570&outgoing=722214&gw_id=111 HTTP/1.0

本文章由 http://www.wifidog.pro/2015/02/13/wifidog%E7%AE%80%E4%BB%8B-2.html 整理编辑,转载请注明出处

wifidog如何判断用户在不在线?

wifidog是如何判断用户在不在线的?
首先说明一下,用户下线的机制,是在用户经过一定时间没上网时,wifidog 线程将用户踢下线,再次上网需要重新认证。这个时间就是在wifidog.conf里面设置的CheckInterval * timeout的时间,单位为秒。

那么wifidog怎么判断用户在不在线?这个概念和上面提到的不同,这里wifidog 使用的是arp_get 通过IP获取mac,如果获取不到就不会把这个客户端信息添加到wifidog的client 链表里。详见http_callback_auth函数实现。

本文章由 http://www.wifidog.pro/2015/02/13/wifidog%E5%88%A4%E6%96%AD%E7%94%A8%E6%88%B7%E5%9C%A8%E4%B8%8D%E5%9C%A8%E7%BA%BF.html 整理编辑,转载请注明出处