📄 connectionhandler.cpp
字号:
//Please refer to http://dansguardian.org/?page=copyright2//for the license for this code.//Written by Daniel Barron (daniel@jadeb//.com).//For support go to http://groups.yahoo.com/group/dansguardian// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA#include "autoconf/platform.h"#include <syslog.h>#include "ImageContainer.hpp"#include "ConnectionHandler.hpp"#include "DataBuffer.hpp"#include "Socket.hpp"#include "UDSocket.hpp"#include "Ident.hpp"#ifdef __BSD #include <sys/wait.h>#else #include <wait.h>#endif#include "FDTunnel.hpp"#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <cstdio>#include <algorithm>#include <iostream>#include <netdb.h>#include <cstdlib>#include <unistd.h>#include <sys/time.h>#ifdef __GCCVER3 #include <istream>#else #include <istream.h>#endifextern OptionContainer o;void ConnectionHandler::handleConnection(int peerfd, String ip, int port) { Socket peerconn; peerconn.close(); peerconn.setFD(peerfd); struct timeval thestart; struct timezone notused; gettimeofday(&thestart, ¬used); peerconn.setTimeout(10); HTTPHeader header; // to hold the incoming client request header header.setTimeout(10); // set a timeout as we don't want blocking 4 eva HTTPHeader docheader; // to hold the returned page header from proxy docheader.setTimeout(20); DataBuffer docbody; // to hold the returned page docbody.setTimeout(120); bool waschecked = false; // flags bool wasrequested = false; bool isexception = false; bool isourwebserver = false; bool wasclean = false; bool cachehit = false; bool forceauthrequest = false; bool isbypass = false; bool iscookiebypass = false; int bypasstimestamp = 0; bool ispostblock = false; bool pausedtoobig = false; if (o.preemptive_banning == 0) { forceauthrequest = true; } std::string mimetype = "-"; String url; String urld; String urldomain; std::string exceptionreason; // to hold the reason for not blocking int docsize = 0; // to store the size of the returned document for loggin Ident ident; // for holding std::string clientip = ip.toCharArray(); // hold the clients ip #ifdef DGDEBUG // debug stuff surprisingly enough std::cout << "got connection" << std::endl; std::cout << clientip << std::endl; #endif Socket proxysock; // to hold connection to proxy try { // connect to proxy int rc = proxysock.connect(o.proxy_ip, o.proxy_port); if (rc) { #ifdef DGDEBUG std::cerr << "Error connecting to proxy" << std::endl; #endif syslog(LOG_ERR, "%s","Error connecting to proxy"); return; // if we can't connect to the proxy, there is no point // in continuing } header.in(&peerconn); // get header from client url = header.url(); urld = header.decode(url); if (url.after("://").contains("/")) { urldomain = url.after("//").before("/"); } else { urldomain = url.after("//"); } if (header.malformedURL(url)) { // checks for bad URLs to prevent security hole try { // writestring throws exception on error/timeout peerconn.writeString("HTTP/1.0 400 Bad Request\n"); peerconn.writeString("Content-Type: text/html\n\n"); peerconn.writeString("<HTML><HEAD><TITLE>DansGuardian - 400 Bad Request</TITLE></HEAD><BODY><H1>DansGuardian - 400 Bad Request</H1> "); peerconn.writeString(o.language_list.getTranslation(200)); // The requested URL is malformed. peerconn.writeString("</BODY></HTML>\n"); } catch (exception& e) {} try { proxysock.close(); // close connection to proxy } catch (exception& e) {} return; } if (o.use_xforwardedfor == 1) { std::string xforwardip = header.getXForwardedForIP(); if (xforwardip.length() > 6) { clientip = xforwardip; } #ifdef DGDEBUG std::cout << "using x-forwardedfor:" << clientip << std::endl; #endif } std::string clientuser = ident.getUsername(&header, &clientip, port); // extract username #ifdef DGDEBUG std::cout << "About to determine group" << std::endl; #endif int filtergroup = determineGroup(&clientuser); if (filtergroup < 0) { filtergroup = determineGroup(&clientip); } if (filtergroup < 0) { filtergroup = 0; //default group - one day configurable? } #ifdef DGDEBUG std::cout << "filtergroup:" << filtergroup << std::endl; #endif if (o.forwarded_for == 1) { header.addXForwardedFor(clientip); // add squid-like entry } if ((*o.fg[filtergroup]).bypass_mode != 0) { #ifdef DGDEBUG std::cout << "About to check for bypass..." << std::endl; #endif bypasstimestamp = header.isBypassURL(&url, (*o.fg[filtergroup]).magic.c_str(), clientip.c_str()); if (bypasstimestamp > 0) { #ifdef DGDEBUG std::cout << "Bypass URL match" << std::endl; #endif header.chopBypass(url); url = header.url(); urld = header.decode(url); if (bypasstimestamp > 1) { // not expired isbypass = true; exceptionreason = o.language_list.getTranslation(606); } } else if (header.isBypassCookie(&urldomain, (*o.fg[filtergroup]).cookie_magic.c_str(), clientip.c_str())) { #ifdef DGDEBUG std::cout << "Bypass cookie match" << std::endl; #endif iscookiebypass = true; isbypass = true; exceptionreason = o.language_list.getTranslation(607); } #ifdef DGDEBUG std::cout << "Finished bypass checks." << std::endl; #endif } if (isbypass) { #ifdef DGDEBUG std::cout << "Bypass activated!" << std::endl; #endif } else if (o.inipexceptions(&clientip)) { // admin pc isexception = true; exceptionreason = o.language_list.getTranslation(600); // Exception client IP match. } else if (o.inuserexceptions(&clientuser)) { // admin user isexception = true; exceptionreason = o.language_list.getTranslation(601); // Exception client user match. } else if ((*o.fg[filtergroup]).inexceptions(urld)) { // allowed site if ((*o.fg[0]).iswebserver(url)) { isourwebserver = true; } else { isexception = true; exceptionreason = o.language_list.getTranslation(602); // Exception site match. } } else if ((*o.fg[filtergroup]).inurlexceptions(urld)) { // allowed url isexception = true; exceptionreason = o.language_list.getTranslation(603); // Exception url match. } #ifdef DGDEBUG std::cout << "extracted url:" << urld << std::endl; #endif if ( (isourwebserver || isexception || iscookiebypass) // don't filter exception and local web server // Cookie bypass so don't need to add cookie so just CONNECT && !o.inBannedIPList(&clientip) // bad users pc && !o.inBannedUserList(&clientuser) ) { // bad user proxysock.readyForOutput(10); // exception on timeout or error header.out(&proxysock); // send proxy the request try { FDTunnel fdt; // make a tunnel object // tunnel from client to proxy and back fdt.tunnel(proxysock.getFD(), peerconn.getFD()); // not expected to exception docsize = fdt.throughput; if (!isourwebserver) { // don't log requests to the web server decideHowToLog(clientuser, clientip, url.toCharArray(), header.port, exceptionreason, header.requesttype().toCharArray(), docsize, o.ll, false, isexception, o.log_exception_hits, false, &thestart, cachehit, 200, mimetype); } } catch (exception& e) {} try { proxysock.close(); // close connection to proxy } catch (exception& e) {} return; // connection dealt with so exit } NaughtyFilter checkme; // our filter object checkme.filtergroup = filtergroup; char* i; // Improved IF structure as suggested by AFN if ((!forceauthrequest || header.requesttype().startsWith("CONNECT")) && !isbypass) { // if its a connect and we don't do filtering on it now then // it will get tunneled and not filtered. We can't tunnel later // as its ssl so we can't see the return header etc // So preemptive banning is forced on with ssl unfortunately. // It is unlikely to cause many problems though. requestChecks(&header, &checkme, &urld, &clientip, &clientuser, filtergroup, &ispostblock); } if (!checkme.isItNaughty && header.requesttype().startsWith("CONNECT")) { // can't filter content of CONNECT proxysock.readyForOutput(10); // exception on timeout or error header.out(&proxysock); // send proxy the request try { FDTunnel fdt; // make a tunnel object // tunnel from client to proxy and back
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -