root/trunk/whisperlib/net/util/ipclassifier.cc

Revision 7, 6.4 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Catalin Popescu
31
32 #include <pthread.h>
33 #include "net/util/ipclassifier.h"
34 #include "common/io/file/file_input_stream.h"
35
36 //////////////////////////////////////////////////////////////////////
37
38 DEFINE_string(ip2location_classifier_db,
39               "",
40               "Where the file ip2location database file is placed");
41
42 //////////////////////////////////////////////////////////////////////
43
44 namespace {
45 template <class C>
46 void SplitClassifiers(C* c, const char* members) {
47   vector<string> components;
48   CHECK(strutil::SplitBracketedString(members, ',', '(', ')',  &components))
49         << " Invalid classifier spec: [" << members << "]";
50   for ( int i = 0; i < components.size(); ++i ) {
51     c->Add(net::IpClassifier::CreateClassifier(components[i]));
52   }
53 }
54 }
55
56 namespace net {
57 IpClassifier* IpClassifier::CreateClassifier(const string& spec) {
58   size_t pos_open = spec.find("(");
59   size_t pos_close = spec.rfind(")");
60   CHECK_NE(pos_open, string::npos)
61     << " Invalid IpClassifier specication (missing '(') : ["
62     << spec << "]";
63   CHECK_NE(pos_close, string::npos)
64     << " Invalid IpClassifier specication (missing ')') : ["
65     << spec << "]";
66   CHECK_GT(pos_close, pos_open);
67   const string name = strutil::StrTrim(spec.substr(0, pos_open));
68   const string arg = strutil::StrTrim(spec.substr(pos_open + 1,
69                                                   pos_close - pos_open - 1));
70   LOG_INFO << "Creating " << name << " classifier w/ arg: [" << arg << "]";
71   if ( name == "NONE" ) {
72     return new IpNoneClassifier();
73   } else if ( name == "AND" ) {
74     return new IpAndClassifier(arg);
75   } else if ( name == "OR" ) {
76     return new IpOrClassifier(arg);
77   } else if ( name == "NOT" ) {
78     return new IpNotClassifier(arg);
79   } else if ( name == "IPLOC" ) {
80     return new IpLocationClassifier(arg);
81   } else if ( name == "IPFILTER" ) {
82     return new IpFilterStringClassifier(arg);
83   } else if ( name == "IPFILTERFILE" ) {
84     return new IpFilterFileClassifier(arg);
85   }
86   LOG_FATAL << " Invalid classifier type: [" << name << "]";
87   return NULL;
88 }
89
90 //////////////////////////////////////////////////////////////////////
91
92 // Logical classifiers
93
94 IpOrClassifier::IpOrClassifier(const string& members)
95   : IpClassifier() {
96   SplitClassifiers<IpOrClassifier>(this, members.c_str());
97 }
98 IpAndClassifier::IpAndClassifier(const string& members)
99   : IpClassifier() {
100   SplitClassifiers<IpAndClassifier>(this, members.c_str());
101 }
102 IpNotClassifier::IpNotClassifier(const string& member)
103   : IpClassifier(),
104     member_(IpClassifier::CreateClassifier(member)) {
105 }
106
107 //////////////////////////////////////////////////////////////////////
108
109 // IP location classifier
110
111 static pthread_once_t resolver_control;
112 net::Ip2Location* IpLocationClassifier::resolver_ = NULL;
113
114 IpLocationClassifier::IpLocationClassifier(const string& spec) {
115   CHECK_SYS_FUN(
116     pthread_once(&resolver_control, &IpLocationClassifier::InitResolver), 0);
117   vector< pair<string, string> > conditions;
118   strutil::SplitPairs(spec, ",", ":", &conditions);
119   for ( int i = 0; i < conditions.size(); ++i ) {
120     const string& key = conditions[i].first;
121     const string& val = conditions[i].second;
122     if ( key == "C" ) {
123       countries_.insert(val);
124     } else if ( key == "CS" ) {
125       countries_short_.insert(val);
126     } else if ( key == "REG" ) {
127       regions_.insert(val);
128     } else if ( key == "CITY" ) {
129       cities_.insert(val);
130     } else if ( key == "ISP" ) {
131       isps_.insert(val);
132     } else {
133       LOG_ERROR << "===> UNRECOGNIZED IpLocationClassifier key: " << key;
134     }
135   }
136 }
137 bool IpLocationClassifier::IsInClass(const IpAddress& ip) const {
138   Ip2Location::Record record;
139   if ( !resolver_->LookupAll(ip, &record) ) {
140     return false;
141   }
142   if ( !countries_.empty() &&
143        countries_.find(record.country_long_) ==
144        countries_.end() ) {
145     return false;
146   }
147   if ( !countries_short_.empty() &&
148        countries_short_.find(record.country_short_) ==
149        countries_short_.end() ) {
150     return false;
151   }
152   if ( !regions_.empty() && regions_.find(record.region_) == regions_.end() ) {
153     return false;
154   }
155   if ( !cities_.empty() && cities_.find(record.city_) == cities_.end() ) {
156     return false;
157   }
158   if ( !isps_.empty() && isps_.find(record.isp_) == isps_.end() ) {
159     return false;
160   }
161   return true;
162 }
163
164 void IpLocationClassifier::InitResolver() {
165   CHECK(resolver_ == NULL);
166   resolver_ = new Ip2Location(FLAGS_ip2location_classifier_db.c_str());
167 }
168
169
170 IpFilterFileClassifier::IpFilterFileClassifier(const string& spec) {
171   const string content(io::FileInputStream::ReadFileOrDie(spec.c_str()));
172   vector<string> ips;
173   strutil::SplitString(string(content), "\n", &ips);
174   for ( int i = 0; i < ips.size(); ++i ) {
175     filter_.Add(strutil::StrTrim(ips[i]).c_str());
176   }
177 }
178
179 IpFilterStringClassifier::IpFilterStringClassifier(const string& spec) {
180   vector<string> ips;
181   strutil::SplitString(spec, ",", &ips);
182   for ( int i = 0; i < ips.size(); ++i ) {
183     filter_.Add(strutil::StrTrim(ips[i]).c_str());
184   }
185 }
186
187 }
Note: See TracBrowser for help on using the browser.