wifidog源码http.c文件分析

来源:互联网 发布:阿秋秋的淘宝店 编辑:程序博客网 时间:2024/06/08 03:04

wifidog源码中的http.c文件,该文件是实现认证和页面跳转操作:

#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <string.h>#include <unistd.h>#include <syslog.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include "httpd.h"#include "safe.h"#include "debug.h"#include "conf.h"#include "auth.h"#include "firewall.h"#include "http.h"#include "client_list.h"#include "common.h"#include "centralserver.h"#include "util.h"#include "wd_util.h"#include "../config.h"/** The 404 handler is also responsible for redirecting to the auth server */void             //web页面404操作http_callback_404(httpd * webserver, request * r, int error_code){    char tmp_url[MAX_BUF], *url, *mac;    s_config *config = config_get_config();           //获取配置文件中的数据    t_auth_serv *auth_server = get_auth_server();         //连接到服务器,    memset(tmp_url, 0, sizeof(tmp_url));    /*      * XXX Note the code below assumes that the client's request is a plain     * http request to a standard port. At any rate, this handler is called only     * if the internet/auth server is down so it's not a huge loss, but still.     */    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);         //对url进程encode操作    if (!is_online()) {                   //连接不到服务器,服务器状态为down        /* The internet connection is down at the moment  - apologize and do not redirect anywhere */        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);   //发送状态页面及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()) {             //连接到服务器,但是服务器不提供重定向服务        /* The auth server is down at the moment - apologize and do not redirect anywhere */        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 {                 //服务器端运行正常,提供重定向服务        /* Re-direct them to auth server */        char *urlFragment;        if (!(mac = arp_get(r->clientAddr))) {    //获取客户端的mac地址            /* We could not get their MAC address */            debug(LOG_INFO, "Failed to retrieve MAC address for ip %s, so not putting in the login request",                  r->clientAddr);            safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&ip=%s&url=%s",                          auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port,                          config->gw_id, r->clientAddr, url);        } else {            debug(LOG_INFO, "Got client MAC address for ip %s: %s", r->clientAddr, mac);            safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&ip=%s&mac=%s&url=%s",                          auth_server->authserv_login_script_path_fragment,                          config->gw_address, config->gw_port, config->gw_id, r->clientAddr, mac, url);            free(mac);        }        // if host is not in whitelist, maybe not in conf or domain'IP changed, it will go to here.                //如果客户端主机不再白名单中,则进行下面的操作        debug(LOG_INFO, "Check host %s is in whitelist or not", r->request.host);       // e.g. www.example.com        t_firewall_rule *rule;        //e.g. example.com is in whitelist        // if request http://www.example.com/, it's not equal example.com.        for (rule = get_ruleset("global"); rule != NULL; rule = rule->next) {            debug(LOG_INFO, "rule mask %s", rule->mask);            if (strstr(r->request.host, rule->mask) == NULL) {                debug(LOG_INFO, "host %s is not in %s, continue", r->request.host, rule->mask);                continue;            }                         //分析客户端主机            int host_length = strlen(r->request.host);               int mask_length = strlen(rule->mask);            if (host_length != mask_length) {                char prefix[1024] = { 0 };                // must be *.example.com, if not have ".", maybe Phishing. e.g. phishingexample.com                strncpy(prefix, r->request.host, host_length - mask_length - 1);        // e.g. www                strcat(prefix, ".");    // www.                strcat(prefix, rule->mask);     // www.example.com                if (strcasecmp(r->request.host, prefix) == 0) {                    debug(LOG_INFO, "allow subdomain");                    fw_allow_host(r->request.host);                    http_send_redirect(r, tmp_url, "allow subdomain"); //执行重定向                    free(url);                    free(urlFragment);                    return;                }            } else {                // e.g. "example.com" is in conf, so it had been parse to IP and added into "iptables allow" when wifidog start. but then its' A record(IP) changed, it will go to here.                                                        debug(LOG_INFO, "allow domain again, because IP changed");                fw_allow_host(r->request.host);                http_send_redirect(r, tmp_url, "allow domain"); //执行重定向                free(url);                free(urlFragment);                return;            }        }        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"); //向服务器端申请重定向的登录页面        free(urlFragment);    }    free(url);}voidhttp_callback_wifidog(httpd * webserver, request * r)      // wifidog callback{    send_http_page(r, "WiFiDog", "Please use the menu to navigate the features of this WiFiDog installation.");}voidhttp_callback_about(httpd * webserver, request * r)     // wifidog about {    send_http_page(r, "About WiFiDog", "This is WiFiDog version <strong>" VERSION "</strong>");}voidhttp_callback_status(httpd * webserver, request * r)    //获取运行状态函数{    const s_config *config = config_get_config();    char *status = NULL;    char *buf;    if (config->httpdusername &&               //验证用户,并决定是否授权        (strcmp(config->httpdusername, r->request.authUser) ||         strcmp(config->httpdpassword, r->request.authPassword))) {        debug(LOG_INFO, "Status page requested, forcing authentication");        httpdForceAuthenticate(r, config->httpdrealm);                return;    }    status = get_status_text();          //获取状态数据    safe_asprintf(&buf, "<pre>%s</pre>", status);    send_http_page(r, "WiFiDog Status", buf);        //发送状态数据     free(buf);    free(status);}/** @brief Convenience function to redirect the web browser to the auth server * @param r The request * @param urlFragment The end of the auth server URL to redirect to (the part after path) * @param text The text to include in the redirect header ant the mnual redirect title */void                  //重定向web browser到服务器函数http_send_redirect_to_auth(request * r, const char *urlFragment, const char *text){    char *protocol = NULL;    int port = 80;    t_auth_serv *auth_server = get_auth_server();    if (auth_server->authserv_use_ssl) {        protocol = "https";        port = auth_server->authserv_ssl_port;    } else {        protocol = "http";        port = auth_server->authserv_http_port;    }    char *url = NULL;    safe_asprintf(&url, "%s://%s:%d%s%s",                  protocol, auth_server->authserv_hostname, port, auth_server->authserv_path, urlFragment);    http_send_redirect(r, url, text);    free(url);}/** @brief Sends a redirect to the web browser  * @param r The request * @param url The url to redirect to * @param text The text to include in the redirect header and the manual redirect link title.  NULL is acceptable */void                    //发送重定向信息到客户端http_send_redirect(request * r, const char *url, const char *text){    char *message = NULL;    char *header = NULL;    char *response = NULL;    /* Re-direct them to auth server */    debug(LOG_DEBUG, "Redirecting client browser to %s", url);    safe_asprintf(&header, "Location: %s", url);    safe_asprintf(&response, "302 %s\n", text ? text : "Redirecting");    httpdSetResponse(r, response);     //设置http请求的响应    httpdAddHeader(r, header);         //添加http请求头    free(response);    free(header);    safe_asprintf(&message, "Please <a href='%s'>click here</a>.", url);    send_http_page(r, text ? text : "Redirection to message", message);      free(message);}voidhttp_callback_auth(httpd * webserver, request * r)      //登录授权函数{    t_client *client;    httpVar *token;    char *mac;    httpVar *logout = httpdGetVariableByName(r, "logout");    if ((token = httpdGetVariableByName(r, "token"))) {        /* They supplied variable "token" */        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 */      //mac和token对比,并增加到客户列表            LOCK_CLIENT_LIST();            if ((client = client_list_find(r->clientAddr, mac)) == NULL) {                debug(LOG_DEBUG, "New client for %s", r->clientAddr);                client_list_add(r->clientAddr, mac, token->value);            } else if (logout) {                logout_client(client);            } else {                debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip);            }            UNLOCK_CLIENT_LIST();            if (!logout) { /* applies for case 1 and 3 from above if */                authenticate_client(r);            }            free(mac);        }    } else {        /* They did not supply variable "token" */        send_http_page(r, "WiFiDog error", "Invalid token");    }}voidhttp_callback_disconnect(httpd * webserver, request * r)   //断开服务连接{    const s_config *config = config_get_config();    /* XXX How do you change the status code for the response?? */    httpVar *token = httpdGetVariableByName(r, "token");    httpVar *mac = httpdGetVariableByName(r, "mac");    if (config->httpdusername &&        (strcmp(config->httpdusername, r->request.authUser) ||         strcmp(config->httpdpassword, r->request.authPassword))) {        debug(LOG_INFO, "Disconnect requested, forcing authentication");        httpdForceAuthenticate(r, config->httpdrealm);        return;    }    if (token && mac) {        t_client *client;        LOCK_CLIENT_LIST();        client = client_list_find_by_mac(mac->value);        if (!client || strcmp(client->token, token->value)) {            UNLOCK_CLIENT_LIST();            debug(LOG_INFO, "Disconnect %s with incorrect token %s", mac->value, token->value);            httpdOutput(r, "Invalid token for MAC");            return;        }                                   //验证用户,查找用户列表,除名        /* TODO: get current firewall counters */        logout_client(client);        UNLOCK_CLIENT_LIST();    } else {        debug(LOG_INFO, "Disconnect called without both token and MAC given");        httpdOutput(r, "Both the token and MAC need to be specified");        return;    }    return;}void                 //对http信息反馈message信息send_http_page(request * r, const char *title, const char *message){    s_config *config = config_get_config();    char *buffer;    struct stat stat_info;    int fd;    ssize_t written;    fd = open(config->htmlmsgfile, O_RDONLY);    if (fd == -1) {        debug(LOG_CRIT, "Failed to open HTML message file %s: %s", config->htmlmsgfile, strerror(errno));        return;    }    if (fstat(fd, &stat_info) == -1) {        debug(LOG_CRIT, "Failed to stat HTML message file: %s", strerror(errno));        close(fd);        return;    }    // Cast from long to unsigned int    buffer = (char *)safe_malloc((size_t) stat_info.st_size + 1);    written = read(fd, buffer, (size_t) stat_info.st_size);    if (written == -1) {        debug(LOG_CRIT, "Failed to read HTML message file: %s", strerror(errno));        free(buffer);        close(fd);        return;    }    close(fd);    buffer[written] = 0;    httpdAddVariable(r, "title", title);    httpdAddVariable(r, "message", message);    httpdAddVariable(r, "nodeID", config->gw_id);    httpdOutput(r, buffer);      //输出buffer中的web信息到客户端    free(buffer);}
0 0
原创粉丝点击