原创作品,允许转载,转载时请务必以超链接形式标明文章
原始出处 、作者信息和本声明。否则将追究法律责任。
http://quietmadman.blog.51cto.com/3269500/1386291
1
2
3
4
|
httpdAddCContent(webserver,
"/wifidog"
,
"about"
, 0, NULL, http_callback_about);
httpdAddCContent(webserver,
"/wifidog"
,
"status"
, 0, NULL, http_callback_status);
// 注册了针对 /wifidog/auth 的访问回调 http_callback_auth
httpdAddCContent(webserver,
"/wifidog"
,
"auth"
, 0, NULL, http_callback_auth);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
http_callback_auth(httpd *webserver, request *r)
{
t_client *client;
httpVar * token;
char
*mac;
// 1, 获取条件参数中的 logout 值
httpVar *logout = httpdGetVariableByName(r,
"logout"
);
// 2, 获取条件参数中的 token 值
if
((token = httpdGetVariableByName(r,
"token"
))) {
/* They supplied variable "token" */
// 3, 可以看到, 这里要求必须能够通过 ARP 协议获取到 接入设备 的 MAC 地址
if
(!(mac = arp_get(r->clientAddr))) {
/* We could not get their MAC address */
debug(LOG_ERR,
"Failed to retrieve MAC address for ip %s"
, r->clientAddr);
send_http_page(r,
"WiFiDog Error"
,
"Failed to retrieve your MAC address"
);
}
else
{
/* We have their MAC address */
LOCK_CLIENT_LIST();
// 4, 检查该客户端(接入设备)是否已经在 wifidog 维护的接入客户端列表中
if
((client = client_list_find(r->clientAddr, mac)) == NULL) {
debug(LOG_DEBUG,
"New client for %s"
, r->clientAddr);
client_list_append(r->clientAddr, mac, token->value);
}
else
if
(logout) {
// 5, 退出处理
t_authresponse authresponse;
s_config *config = config_get_config();
unsigned
long
long
incoming = client->counters.incoming;
unsigned
long
long
outgoing = client->counters.outgoing;
char
*ip = safe_strdup(client->ip);
char
*urlFragment = NULL;
t_auth_serv *auth_server = get_auth_server();
fw_deny(client->ip, client->mac, client->fw_connection_state);
client_list_delete(client);
debug(LOG_DEBUG,
"Got logout from %s"
, client->ip);
/* Advertise the logout if we have an auth server */
if
(config->auth_servers != NULL) {
UNLOCK_CLIENT_LIST();
auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token->value,
incoming, outgoing);
LOCK_CLIENT_LIST();
/* Re-direct them to auth server */
debug(LOG_INFO,
"Got manual logout from client ip %s, mac %s, token %s"
"- redirecting them to logout message"
, client->ip, client->mac, client->token);
safe_asprintf(&urlFragment,
"%smessage=%s"
,
auth_server->authserv_msg_script_path_fragment,
GATEWAY_MESSAGE_ACCOUNT_LOGGED_OUT
);
http_send_redirect_to_auth(r, urlFragment,
"Redirect to logout message"
);
free
(urlFragment);
}
free
(ip);
}
else
{
// 6, 已经登录校验通过
debug(LOG_DEBUG,
"Client for %s is already in the client list"
, client->ip);
}
UNLOCK_CLIENT_LIST();
if
(!logout) {
// 7, 到 auth server 上进一步校验 token
authenticate_client(r);
}
free
(mac);
}
}
else
{
/* They did not supply variable "token" */
// 8, 未携带 token, 直接拒绝
send_http_page(r,
"WiFiDog error"
,
"Invalid token"
);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
authenticate_client(request *r)
{
t_client *client;
t_authresponse auth_response;
char
*mac,
*token;
char
*urlFragment = NULL;
s_config *config = NULL;
t_auth_serv *auth_server = NULL;
LOCK_CLIENT_LIST();
// 根据 IP 地址获取 客户端的 MAC 地址以及本次会话分配的 token
// 主要用于 token 校验过程
client = client_list_find_by_ip(r->clientAddr);
if
(client == NULL) {
debug(LOG_ERR,
"authenticate_client(): Could not find client for %s"
, r->clientAddr);
UNLOCK_CLIENT_LIST();
return
;
}
mac = safe_strdup(client->mac);
token = safe_strdup(client->token);
UNLOCK_CLIENT_LIST();
/*
* At this point we've released the lock while we do an HTTP request since it could
* take multiple seconds to do and the gateway would effectively be frozen if we
* kept the lock.
*/
// 通过 "login" 到 认证服务器 上进行客户端的 token 校验
auth_server_request(&auth_response, REQUEST_TYPE_LOGIN, r->clientAddr, mac, token, 0, 0);
LOCK_CLIENT_LIST();
/* can't trust the client to still exist after n seconds have passed */
// 这里主要防止在到 认证服务器 上进行 token 校验的过程中
// 该客户端已经退出的情形, 此时就不需要再进行处理
client = client_list_find(r->clientAddr, mac);
if
(client == NULL) {
debug(LOG_ERR,
"authenticate_client(): Could not find client node for %s (%s)"
, r->clientAddr, mac);
UNLOCK_CLIENT_LIST();
free
(token);
free
(mac);
return
;
}
free
(token);
free
(mac);
/* Prepare some variables we'll need below */
config = config_get_config();
auth_server = get_auth_server();
// 根据返回的校验结果做不同的处理
switch
(auth_response.authcode) {
case
AUTH_ERROR:
case
AUTH_DENIED:
case
AUTH_VALIDATION:
case
AUTH_VALIDATION_FAILED:
... ...
break
;
case
AUTH_ALLOWED:
/* Logged in successfully as a regular account */
debug(LOG_INFO,
"Got ALLOWED from central server authenticating token %s from %s at %s - "
"adding to firewall and redirecting them to portal"
, client->token, client->ip, client->mac);
client->fw_connection_state = FW_MARK_KNOWN;
fw_allow(client->ip, client->mac, FW_MARK_KNOWN);
served_this_session++;
safe_asprintf(&urlFragment,
"%sgw_id=%s"
,
auth_server->authserv_portal_script_path_fragment,
config->gw_id
);
http_send_redirect_to_auth(r, urlFragment,
"Redirect to portal"
);
free
(urlFragment);
break
;
}
UNLOCK_CLIENT_LIST();
return
;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/** Set if a specific client has access through the firewall */
// 针对上面的流程,这里的输入参数
// type 为 FW_ACCESS_ALLOW,tag 为 FW_MARK_KNOWN
int
iptables_fw_access(fw_access_t type,
const
char
*ip,
const
char
*mac,
int
tag)
{
int
rc;
fw_quiet = 0;
switch
(type) {
case
FW_ACCESS_ALLOW:
iptables_do_command(
"-t mangle -A "
TABLE_WIFIDOG_OUTGOING
" -s %s -m mac --mac-source %s -j MARK --set-mark %d"
, ip, mac, tag);
rc = iptables_do_command(
"-t mangle -A "
TABLE_WIFIDOG_INCOMING
" -d %s -j ACCEPT"
, ip);
break
;
case
FW_ACCESS_DENY:
iptables_do_command(
"-t mangle -D "
TABLE_WIFIDOG_OUTGOING
" -s %s -m mac --mac-source %s -j MARK --set-mark %d"
, ip, mac, tag);
rc = iptables_do_command(
"-t mangle -D "
TABLE_WIFIDOG_INCOMING
" -d %s -j ACCEPT"
, ip);
break
;
default
:
rc = -1;
break
;
}
return
rc;
}
|
iptables –t mangle –AWiFiDog_$ID$_Outgoing -s 客户端IP地址 -m mac --mac-source 客户端MAC地址 -j MARK --set-markFW_MARK_KNOWN |
iptables -t mangle -AWiFiDog_$ID$_Incoming -d 客户端IP地址 -j ACCEPT |