]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_geoip.cpp
Fix m_alias not initialising 'active' before use.
[user/henk/code/inspircd.git] / src / modules / extra / m_geoip.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /// $CompilerFlags: find_compiler_flags("geoip" "")
21 /// $LinkerFlags: find_linker_flags("geoip" "-lGeoIP")
22
23 /// $PackageInfo: require_system("centos" "7.0") GeoIP-devel pkgconfig
24 /// $PackageInfo: require_system("darwin") geoip pkg-config
25 /// $PackageInfo: require_system("debian") libgeoip-dev pkg-config
26 /// $PackageInfo: require_system("ubuntu") libgeoip-dev pkg-config
27
28 #include "inspircd.h"
29 #include "xline.h"
30 #include "modules/stats.h"
31 #include "modules/whois.h"
32
33 // Fix warnings about the use of commas at end of enumerator lists on C++03.
34 #if defined __clang__
35 # pragma clang diagnostic ignored "-Wc++11-extensions"
36 #elif defined __GNUC__
37 # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8))
38 #  pragma GCC diagnostic ignored "-Wpedantic"
39 # else
40 #  pragma GCC diagnostic ignored "-pedantic"
41 # endif
42 #endif
43
44 #include <GeoIP.h>
45
46 #ifdef _WIN32
47 # pragma comment(lib, "GeoIP.lib")
48 #endif
49
50 enum
51 {
52         // InspIRCd-specific.
53         RPL_WHOISCOUNTRY = 344
54 };
55
56 class ModuleGeoIP : public Module, public Stats::EventListener, public Whois::EventListener
57 {
58         StringExtItem ext;
59         bool extban;
60         GeoIP* ipv4db;
61         GeoIP* ipv6db;
62
63         std::string* SetExt(User* user)
64         {
65                 const char* code = NULL;
66                 switch (user->client_sa.family())
67                 {
68                         case AF_INET:
69                                 code = GeoIP_country_code_by_addr(ipv4db, user->GetIPString().c_str());
70                                 break;
71
72                         case AF_INET6:
73                                 code = GeoIP_country_code_by_addr_v6(ipv6db, user->GetIPString().c_str());
74                                 break;
75                 }
76
77                 ext.set(user, code ? code : "UNK");
78                 return ext.get(user);
79         }
80
81  public:
82         ModuleGeoIP()
83                 : Stats::EventListener(this)
84                 , Whois::EventListener(this)
85                 , ext("geoip_cc", ExtensionItem::EXT_USER, this)
86                 , extban(true)
87                 , ipv4db(NULL)
88                 , ipv6db(NULL)
89         {
90         }
91
92         void init() CXX11_OVERRIDE
93         {
94                 ipv4db = GeoIP_open_type(GEOIP_COUNTRY_EDITION, GEOIP_STANDARD);
95                 if (!ipv4db)
96                         throw ModuleException("Unable to load the IPv4 GeoIP database. Are you missing GeoIP.dat?");
97
98                 ipv6db = GeoIP_open_type(GEOIP_COUNTRY_EDITION_V6, GEOIP_STANDARD);
99                 if (!ipv6db)
100                         throw ModuleException("Unable to load the IPv6 GeoIP database. Are you missing GeoIPv6.dat?");
101
102                 const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
103                 for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
104                 {
105                         LocalUser* user = *i;
106                         if ((user->registered == REG_ALL) && (!ext.get(user)))
107                         {
108                                 SetExt(user);
109                         }
110                 }
111         }
112
113         ~ModuleGeoIP()
114         {
115                 if (ipv4db)
116                         GeoIP_delete(ipv4db);
117
118                 if (ipv6db)
119                         GeoIP_delete(ipv6db);
120         }
121
122         void ReadConfig(ConfigStatus&) CXX11_OVERRIDE
123         {
124                 ConfigTag* tag = ServerInstance->Config->ConfValue("geoip");
125                 extban = tag->getBool("extban");
126         }
127
128         Version GetVersion() CXX11_OVERRIDE
129         {
130                 return Version("Provides a way to assign users to connect classes by country using GeoIP lookup", VF_OPTCOMMON|VF_VENDOR);
131         }
132
133         void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
134         {
135                 if (extban)
136                         tokens["EXTBAN"].push_back('G');
137         }
138
139         ModResult OnCheckBan(User* user, Channel*, const std::string& mask) CXX11_OVERRIDE
140         {
141                 if (extban && (mask.length() > 2) && (mask[0] == 'G') && (mask[1] == ':'))
142                 {
143                         std::string* cc = ext.get(user);
144                         if (!cc)
145                                 cc = SetExt(user);
146
147                         if (InspIRCd::Match(*cc, mask.substr(2)))
148                                 return MOD_RES_DENY;
149                 }
150                 return MOD_RES_PASSTHRU;
151         }
152
153         ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) CXX11_OVERRIDE
154         {
155                 std::string* cc = ext.get(user);
156                 if (!cc)
157                         cc = SetExt(user);
158
159                 std::string geoip = myclass->config->getString("geoip");
160                 if (geoip.empty())
161                         return MOD_RES_PASSTHRU;
162                 irc::commasepstream list(geoip);
163                 std::string country;
164                 while (list.GetToken(country))
165                         if (country == *cc)
166                                 return MOD_RES_PASSTHRU;
167                 return MOD_RES_DENY;
168         }
169
170         void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE
171         {
172                 // If user has sent NICK/USER, re-set the ExtItem as this is likely CGI:IRC changing the IP
173                 if (user->registered == REG_NICKUSER)
174                         SetExt(user);
175         }
176
177         void OnWhois(Whois::Context& whois) CXX11_OVERRIDE
178         {
179                 // If the extban is disabled we don't expose users location.
180                 if (!extban)
181                         return;
182
183                 std::string* cc = ext.get(whois.GetTarget());
184                 if (!cc)
185                         cc = SetExt(whois.GetTarget());
186
187                 whois.SendLine(RPL_WHOISCOUNTRY, *cc, "is located in this country");
188         }
189
190         ModResult OnStats(Stats::Context& stats) CXX11_OVERRIDE
191         {
192                 if (stats.GetSymbol() != 'G')
193                         return MOD_RES_PASSTHRU;
194
195                 unsigned int unknown = 0;
196                 std::map<std::string, unsigned int> results;
197
198                 const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
199                 for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
200                 {
201                         std::string* cc = ext.get(*i);
202                         if (cc)
203                                 results[*cc]++;
204                         else
205                                 unknown++;
206                 }
207
208                 for (std::map<std::string, unsigned int>::const_iterator i = results.begin(); i != results.end(); ++i)
209                 {
210                         stats.AddRow(801, "GeoIPSTATS " + i->first + " " + ConvToStr(i->second));
211                 }
212
213                 if (unknown)
214                         stats.AddRow(801, "GeoIPSTATS Unknown " + ConvToStr(unknown));
215
216                 return MOD_RES_DENY;
217         }
218 };
219
220 MODULE_INIT(ModuleGeoIP)