ipfilter.cpp

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 //! @file ipfilter.cpp Implementation of IpFilterBase and IpFilter classes
00020 
00021 #include <hn/hnprec.h>
00022 #include <hn/ipfilter.h>
00023 #include <hn/bind_placeholders.h>
00024 #include <hn/log.h>
00025 #include <hn/utils.h>
00026 #include <hn/rangelist.h>
00027 #include <boost/lexical_cast.hpp>
00028 #include <boost/bind.hpp>
00029 #include <boost/spirit.hpp>
00030 
00031 // IpFilterBase class
00032 // ------------------
00033 IpFilterBase::IpFilterBase() {}
00034 IpFilterBase::~IpFilterBase() {}
00035 
00036 // IpFilter class
00037 // --------------
00038 IpFilter::IpFilter() : m_list(new RangeList32) {}
00039 IpFilter::~IpFilter() {}
00040 void IpFilter::load(const std::string &file) {
00041         std::ifstream ifs(file.c_str());
00042         if (!ifs) {
00043                 boost::format fmt(
00044                         "[IpFilter] Unable to open file %s for reading."
00045                 );
00046                 logError(fmt % file);
00047                 return;
00048         }
00049         std::string buf;
00050 
00051         getline(ifs, buf);
00052         ParseFunc parseFunc = getParseFunc(buf);
00053         ifs.seekg(0);
00054 
00055         uint32_t line = 0;
00056         uint32_t read = 0;
00057         Utils::StopWatch s1;
00058         while (getline(ifs, buf)) {
00059                 if (buf.empty()) {
00060                         continue;
00061                 }
00062                 try {
00063                         parseFunc(buf);
00064                         ++read;
00065                 } catch (const ParseError &e) {
00066                         boost::format fmt("%s:%s: Parse error: %s");
00067                         logWarning(fmt % file % line % e.what());
00068                         throw;
00069                 }
00070                 ++line;
00071         }
00072         logDebug(
00073                 boost::format("[IpFilter] %d lines read, %d failed (%f%%)")
00074                 % read % (line - read) % ((line - read) * 100.0 / line)
00075         );
00076         boost::format fmt("IpFilter loaded in %fms, %d ranges blocked.");
00077         logMsg(fmt % s1 % m_list->size());
00078 }
00079 IpFilter::ParseFunc IpFilter::getParseFunc(const std::string &buf) try {
00080         CHECK_THROW(buf.size() >= 4);
00081         boost::lexical_cast<uint32_t>(buf.substr(0, 3));
00082         return boost::bind(&IpFilter::parseMuleLine, this, _b1);
00083 } catch (boost::bad_lexical_cast&) {
00084         return boost::bind(&IpFilter::parseMldonkeyLine, this, _b1);
00085 }
00086 
00087 using namespace boost::spirit;
00088 static uint32_t one = 0, two = 0;
00089 static uint_parser<unsigned, 10, 1, 3> uint3_p;
00090 static rule<> parse_one =
00091         uint3_p[assign_a((reinterpret_cast<char*>(&one))[3])] >> '.' >>
00092         uint3_p[assign_a((reinterpret_cast<char*>(&one))[2])] >> '.' >>
00093         uint3_p[assign_a((reinterpret_cast<char*>(&one))[1])] >> '.' >>
00094         uint3_p[assign_a((reinterpret_cast<char*>(&one))[0])];
00095 static rule<> parse_two =
00096         uint3_p[assign_a((reinterpret_cast<char*>(&two))[3])] >> '.' >>
00097         uint3_p[assign_a((reinterpret_cast<char*>(&two))[2])] >> '.' >>
00098         uint3_p[assign_a((reinterpret_cast<char*>(&two))[1])] >> '.' >>
00099         uint3_p[assign_a((reinterpret_cast<char*>(&two))[0])];
00100 
00101 void IpFilter::parseMldonkeyLine(const std::string &buf) {
00102         size_t i = buf.find_last_of(':');
00103         if (i == std::string::npos) {
00104                 throw ParseError("Expected ':' token.");
00105         }
00106         std::string tmp(buf.substr(i + 1, buf.size() - i - 2));
00107         if (parse(tmp.c_str(), parse_one >> '-' >> parse_two).full) {
00108                 m_list->push(one, two);
00109         } else {
00110                 throw ParseError("unknown error");
00111         }
00112 }
00113 
00114 void IpFilter::parseMuleLine(const std::string &buf) {
00115         if (parse(
00116                 buf.substr(0, 33).c_str(), parse_one >> " - " >> parse_two
00117         ).full) {
00118                 m_list->push(one, two);
00119         } else {
00120                 throw ParseError("unknown error");
00121         }
00122 }
00123 
00124 bool IpFilter::isAllowed(uint32_t ip) {
00125         return !m_list->contains(SWAP32_ON_LE(ip));
00126 }