用户连接启动线程(void thread_httpd(void * args))
代码片段1.3分析
此段代码表示wifidog是如何通过http 404回调函数实现客户端重定向了,实际上就是在404回调函数中封装了一个307状态的http报头,http的307状态在http协议中就是用于重定向的,封装完成后通过已经与客户端连接的socket返回给客户端。步骤流程为
- 判断本机是否处于离线状态
- 判断认证服务器是否在线
- 封装http 307报文
- 发送于目标客户端
代码片段1.3:
void
http_callback_404(httpd *webserver, request *r)
{
char tmp_url[MAX_BUF],
*url;
s_config *config = config_get_config();
t_auth_serv *auth_server = get_auth_server();
memset(tmp_url, 0, sizeof(tmp_url));
snprintf(tmp_url, (sizeof(tmp_url) - 1), "http://%s%s%s%s",
r->request.host,
r->request.path,
r->request.query[0] ? "?" : "",
r->request.query);
url = httpdUrlEncode(tmp_url);
if (!is_online()) {
/* 本机处于离线状态,此函数调用结果由认证服务器检测线程设置 */
char * buf;
safe_asprintf(&buf,
"<p>We apologize, but it seems that the internet connection that powers this hotspot is temporarily unavailable.</p>"
"<p>If at all possible, please notify the owners of this hotspot that the internet connection is out of service.</p>"
"<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>"
"<p>In a while please <a href='%s'>click here</a> to try your request again.</p>", tmp_url);
send_http_page(r, "Uh oh! Internet access unavailable!", buf);
free(buf);
debug(LOG_INFO, "Sent %s an apology since I am not online - no point sending them to auth server", r->clientAddr);
}
else if (!is_auth_online()) {
/* 认证服务器处于离线状态 */
char * buf;
safe_asprintf(&buf,
"<p>We apologize, but it seems that we are currently unable to re-direct you to the login screen.</p>"
"<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>"
"<p>In a couple of minutes please <a href='%s'>click here</a> to try your request again.</p>", tmp_url);
send_http_page(r, "Uh oh! Login screen unavailable!", buf);
free(buf);
debug(LOG_INFO, "Sent %s an apology since auth server not online - no point sending them to auth server", r->clientAddr);
}
else {
/* 本机与认证服务器都在线,返回重定向包于客户端 */
char *urlFragment;
safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&url=%s",
auth_server->authserv_login_script_path_fragment,
config->gw_address,
config->gw_port,
config->gw_id,
url);
debug(LOG_INFO, "Captured %s requesting [%s] and re-directing them to login page", r->clientAddr, url);
http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); /* 实际上此函数中通过socket返回一个307状态的http报头给客户端,里面包含有认证服务器地址 */
free(urlFragment);
}
free(url);
}
代码片段1.4分析
此段表明当客户端已经在认证服务器确认登陆,认证服务器将客户端重新重定向回网关,并在重定向包中包含关键路径"/wifidog/auth"和token,认证服务器所执行的操作。
代码片段1.4
void
http_callback_auth(httpd *webserver, request *r)
{
t_client *client;
httpVar * token;
char *mac;
/* 判断http报文是否包含登出logout */
httpVar *logout = httpdGetVariableByName(r, "logout");
if ((token = httpdGetVariableByName(r, "token"))) {
/* 获取http报文中的token */
if (!(mac = arp_get(r->clientAddr))) {
/* 获取客户端mac地址失败 */
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 {
LOCK_CLIENT_LIST();
/* 判断客户端是否存在于列表中 */
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) {
/* http报文为登出 */
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();
/* 修改iptables禁止客户端访问外网 */
fw_deny(client->ip, client->mac, client->fw_connection_state);
/* 从客户端列表中删除此客户端 */
client_list_delete(client);
debug(LOG_DEBUG, "Got logout from %s", client->ip);
if (config->auth_servers != NULL) {
UNLOCK_CLIENT_LIST();
/* 发送登出认证包给认证服务器 */
auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token->value,
incoming, outgoing);
LOCK_CLIENT_LIST();
/* 将客户端重定向到认证服务器 */
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 {
debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip);
}
UNLOCK_CLIENT_LIST();
if (!logout) {
/* 通过认证服务器认证此客户端token */
authenticate_client(r);
}
free(mac);
}
} else {
send_http_page(r, "WiFiDog error", "Invalid token");
}
}
/* 此函数用于提交token到认证服务器进行认证 */
void
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();
client = client_list_find_by_ip(r->clientAddr);
/* 判断此客户端是否在列表中 */
if (client == NULL) {
debug(LOG_ERR, "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();
/* 提交token、客户端ip、客户端mac至认证服务器 */
auth_server_request(&auth_response, REQUEST_TYPE_LOGIN, r->clientAddr, mac, token, 0, 0);
LOCK_CLIENT_LIST();
/*再次判断客户端是否存在于列表中,保险起见,因为有可能在于认证服务器认证过程中,客户端检测线程把此客户端下线 */
client = client_list_find(r->clientAddr, mac);
if (client == NULL) {
debug(LOG_ERR, "Could not find client node for %s (%s)", r->clientAddr, mac);
UNLOCK_CLIENT_LIST();
free(token);
free(mac);
return;
}
free(token);
free(mac);
config = config_get_config();
auth_server = get_auth_server();
/* 判断认证服务器认证结果 */
switch(auth_response.authcode) {
case AUTH_ERROR:
/* 认证错误 */
debug(LOG_ERR, "Got %d from central server authenticating token %s from %s at %s", auth_response, client->token, client->ip, client->mac);
send_http_page(r, "Error!", "Error: We did not get a valid answer from the central server");
break;
case AUTH_DENIED:
/* 认证服务器拒绝此客户端 */
debug(LOG_INFO, "Got DENIED from central server authenticating token %s from %s at %s - redirecting them to denied message", client->token, client->ip, client->mac);
safe_asprintf(&urlFragment, "%smessage=%s",
auth_server->authserv_msg_script_path_fragment,
GATEWAY_MESSAGE_DENIED
);
http_send_redirect_to_auth(r, urlFragment, "Redirect to denied message");
free(urlFragment);
break;
case AUTH_VALIDATION:
/* 认证服务器处于等待此客户端电子邮件确认回执状态 */
debug(LOG_INFO, "Got VALIDATION from central server authenticating token %s from %s at %s"
"- adding to firewall and redirecting them to activate message", client->token,
client->ip, client->mac);
client->fw_connection_state = FW_MARK_PROBATION;
fw_allow(client->ip, client->mac, FW_MARK_PROBATION);
safe_asprintf(&urlFragment, "%smessage=%s",
auth_server->authserv_msg_script_path_fragment,
GATEWAY_MESSAGE_ACTIVATE_ACCOUNT
);
http_send_redirect_to_auth(r, urlFragment, "Redirect to activate message");
free(urlFragment);
break;
case AUTH_ALLOWED:
/* 认证通过 */
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;
case AUTH_VALIDATION_FAILED:
/* 电子邮件确认回执超时 */
debug(LOG_INFO, "Got VALIDATION_FAILED from central server authenticating token %s from %s at %s "
"- redirecting them to failed_validation message", client->token, client->ip, client->mac);
safe_asprintf(&urlFragment, "%smessage=%s",
auth_server->authserv_msg_script_path_fragment,
GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED
);
http_send_redirect_to_auth(r, urlFragment, "Redirect to failed validation message");
free(urlFragment);
break;
default:
debug(LOG_WARNING, "I don't know what the validation code %d means for token %s from %s at %s - sending error message", auth_response.authcode, client->token, client->ip, client->mac);
send_http_page(r, "Internal Error", "We can not validate your request at this time");
break;
}
UNLOCK_CLIENT_LIST();
return;
}
本文章由 http://www.wifidog.pro/2015/02/03/wifidog%E7%94%A8%E6%88%B7%E8%BF%9E%E6%8E%A5_2.html 整理编辑,转载请注明出处