上一篇分析了接入設備的首次瀏覽器訪問請求如何通過 防火牆過濾規則 重定向到 wifidog 的 HTTP 服務中,本篇主要分析了 wifidog 在接收到 接入設備的 HTTP 訪問請求後,如何將此 HTTP 請求重定向到 認證服務器(auth-server) 上。
通過上面的防火牆規則,會將通過上面的防火牆規則,會將HTTP請求的外部IP地址和端口通過NAT方式重定向至本地wifidog內嵌HTTP服務器的地址和端口上,並由內嵌HTTP服務器進行服務,而內嵌HTTP服務器的路徑和回調處理如下:
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); httpdAddC404Content(webserver, http_callback_404);
客戶端首次訪問時回調客戶端首次訪問時回調http_callback_404函數,在該函數中根據獲取的客戶端信息來配置重定向的URL fragment,如下:
void http_callback_404(httpd *webserver, request *r) { 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. */ /* 用戶需要訪問的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()) { /* 路由器都接入不到 internet */ char * buf; send_http_page(r, "Uh oh! Internet access unavailable!", buf); free(buf); } else if (!is_auth_online()) { /* auth server 掛起 */ char * buf; send_http_page(r, "Uh oh! Login screen unavailable!", buf); free(buf); } else { /* 配置重定向到 auth server 的 url 參數 */ char *urlFragment; if (!(mac = arp_get(r->clientAddr))) { /* 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&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, 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&mac=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, mac, url); } /* 調用該函數將用戶請求重定向到 auth server 的登錄頁面 */ http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); free(urlFragment); } free(url); }
上面代碼基本不用解釋,具體重定向至auth server的消息在下面的 http_send_redirect_to_auth 函數中實現:
void http_send_redirect_to_auth(request *r, char *urlFragment, 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); }
具體的重定向URL給個實例:
POST /login/?gw_address=192.168.1.1&gw_port=2060&gw_id=default&mac=44:94:fc:ef:28:40&url=http%3A//www.baidu.com/ HTTP/1.1 |
可以看到這裏有這幾個參數信息:
2gw_address,路由器的LAN地址
2gw_port:爲wifidog的監聽端口
2gw_id:路由器的標識名
2mac:客戶端設備的MAC地址
2url:爲客戶端訪問的原URL(以便於重定向)