00001
00002
00003
00004
00005
00006
00007
00008 #include "module.h"
00009
00010 struct ProxyCheck
00011 {
00012 std::set<Anope::string, ci::less> types;
00013 std::vector<unsigned short> ports;
00014 time_t duration;
00015 Anope::string reason;
00016 };
00017
00018 static Anope::string ProxyCheckString;
00019 static Anope::string target_ip;
00020 static unsigned short target_port;
00021 static bool add_to_akill;
00022
00023 class ProxyCallbackListener : public ListenSocket
00024 {
00025 class ProxyCallbackClient : public ClientSocket, public BufferedSocket
00026 {
00027 public:
00028 ProxyCallbackClient(ListenSocket *l, int f, const sockaddrs &a) : Socket(f, l->IsIPv6()), ClientSocket(l, a), BufferedSocket()
00029 {
00030 }
00031
00032 void OnAccept() anope_override
00033 {
00034 this->Write(ProxyCheckString);
00035 }
00036
00037 bool ProcessWrite() anope_override
00038 {
00039 return !BufferedSocket::ProcessWrite() || this->write_buffer.empty() ? false : true;
00040 }
00041 };
00042
00043 public:
00044 ProxyCallbackListener(const Anope::string &b, int p) : Socket(-1, b.find(':') != Anope::string::npos), ListenSocket(b, p, false)
00045 {
00046 }
00047
00048 ClientSocket *OnAccept(int fd, const sockaddrs &addr) anope_override
00049 {
00050 return new ProxyCallbackClient(this, fd, addr);
00051 }
00052 };
00053
00054 class ProxyConnect : public ConnectionSocket
00055 {
00056 static ServiceReference<XLineManager> akills;
00057
00058 public:
00059 static std::set<ProxyConnect *> proxies;
00060
00061 ProxyCheck proxy;
00062 unsigned short port;
00063 time_t created;
00064
00065 ProxyConnect(ProxyCheck &p, unsigned short po) : Socket(-1), ConnectionSocket(), proxy(p),
00066 port(po), created(Anope::CurTime)
00067 {
00068 proxies.insert(this);
00069 }
00070
00071 ~ProxyConnect()
00072 {
00073 proxies.erase(this);
00074 }
00075
00076 virtual void OnConnect() anope_override = 0;
00077 virtual const Anope::string GetType() const = 0;
00078
00079 protected:
00080 void Ban()
00081 {
00082 Anope::string reason = this->proxy.reason;
00083
00084 reason = reason.replace_all_cs("%t", this->GetType());
00085 reason = reason.replace_all_cs("%i", this->conaddr.addr());
00086 reason = reason.replace_all_cs("%p", stringify(this->conaddr.port()));
00087
00088 Log(OperServ) << "PROXYSCAN: Open " << this->GetType() << " proxy found on " << this->conaddr.addr() << ":" << this->conaddr.port() << " (" << reason << ")";
00089 XLine *x = new XLine("*@" + this->conaddr.addr(), Config->OperServ, Anope::CurTime + this->proxy.duration, reason, XLineManager::GenerateUID());
00090 if (add_to_akill && akills)
00091 {
00092 akills->AddXLine(x);
00093 akills->Send(NULL, x);
00094 }
00095 else
00096 {
00097 if (IRCD->CanSZLine)
00098 IRCD->SendSZLine(NULL, x);
00099 else
00100 IRCD->SendAkill(NULL, x);
00101 delete x;
00102 }
00103 }
00104 };
00105 ServiceReference<XLineManager> ProxyConnect::akills("XLineManager", "xlinemanager/sgline");
00106 std::set<ProxyConnect *> ProxyConnect::proxies;
00107
00108 class HTTPProxyConnect : public ProxyConnect, public BufferedSocket
00109 {
00110 public:
00111 HTTPProxyConnect(ProxyCheck &p, unsigned short po) : Socket(-1), ProxyConnect(p, po), BufferedSocket()
00112 {
00113 }
00114
00115 void OnConnect() anope_override
00116 {
00117 this->Write("CONNECT %s:%d HTTP/1.0", target_ip.c_str(), target_port);
00118 this->Write("Content-length: 0");
00119 this->Write("Connection: close");
00120 this->Write("");
00121 }
00122
00123 const Anope::string GetType() const anope_override
00124 {
00125 return "HTTP";
00126 }
00127
00128 bool ProcessRead() anope_override
00129 {
00130 BufferedSocket::ProcessRead();
00131 if (this->GetLine() == ProxyCheckString)
00132 {
00133 this->Ban();
00134 return false;
00135 }
00136 return true;
00137 }
00138 };
00139
00140 class SOCKS5ProxyConnect : public ProxyConnect, public BinarySocket
00141 {
00142 public:
00143 SOCKS5ProxyConnect(ProxyCheck &p, unsigned short po) : Socket(-1), ProxyConnect(p, po), BinarySocket()
00144 {
00145 }
00146
00147 void OnConnect() anope_override
00148 {
00149 sockaddrs target_addr;
00150 char buf[4 + sizeof(target_addr.sa4.sin_addr.s_addr) + sizeof(target_addr.sa4.sin_port)];
00151 int ptr = 0;
00152 try
00153 {
00154 target_addr.pton(AF_INET, target_ip, target_port);
00155 }
00156 catch (const SocketException &)
00157 {
00158 return;
00159 }
00160
00161 buf[ptr++] = 5;
00162 buf[ptr++] = 1;
00163 buf[ptr++] = 0;
00164
00165 this->Write(buf, ptr);
00166
00167 ptr = 1;
00168 buf[ptr++] = 1;
00169 buf[ptr++] = 0;
00170 buf[ptr++] = 1;
00171 memcpy(buf + ptr, &target_addr.sa4.sin_addr.s_addr, sizeof(target_addr.sa4.sin_addr.s_addr));
00172 ptr += sizeof(target_addr.sa4.sin_addr.s_addr);
00173 memcpy(buf + ptr, &target_addr.sa4.sin_port, sizeof(target_addr.sa4.sin_port));
00174 ptr += sizeof(target_addr.sa4.sin_port);
00175
00176 this->Write(buf, ptr);
00177 }
00178
00179 const Anope::string GetType() const anope_override
00180 {
00181 return "SOCKS5";
00182 }
00183
00184 bool Read(const char *buffer, size_t l) anope_override
00185 {
00186 if (l >= ProxyCheckString.length() && !strncmp(buffer, ProxyCheckString.c_str(), ProxyCheckString.length()))
00187 {
00188 this->Ban();
00189 return false;
00190 }
00191 return true;
00192 }
00193 };
00194
00195 class ModuleProxyScan : public Module
00196 {
00197 Anope::string listen_ip;
00198 unsigned short listen_port;
00199 Anope::string con_notice, con_source;
00200 std::vector<ProxyCheck> proxyscans;
00201
00202 ProxyCallbackListener *listener;
00203
00204 class ConnectionTimeout : public CallBack
00205 {
00206 public:
00207 ConnectionTimeout(Module *creator, long timeout) : CallBack(creator, timeout, Anope::CurTime, true)
00208 {
00209 }
00210
00211 void Tick(time_t) anope_override
00212 {
00213 for (std::set<ProxyConnect *>::iterator it = ProxyConnect::proxies.begin(), it_end = ProxyConnect::proxies.end(); it != it_end; ++it)
00214 {
00215 ProxyConnect *p = *it;
00216
00217 if (p->created + this->GetSecs() < Anope::CurTime)
00218 p->flags[SF_DEAD] = true;
00219 }
00220 }
00221 } connectionTimeout;
00222
00223 public:
00224 ModuleProxyScan(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED),
00225 connectionTimeout(this, 5)
00226 {
00227 this->SetAuthor("Anope");
00228
00229 Implementation i[] = { I_OnReload, I_OnUserConnect };
00230 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00231
00232 this->listener = NULL;
00233
00234 try
00235 {
00236 OnReload();
00237 }
00238 catch (const ConfigException &ex)
00239 {
00240 throw ModuleException(ex.GetReason());
00241 }
00242 }
00243
00244 ~ModuleProxyScan()
00245 {
00246 for (std::set<ProxyConnect *>::iterator it = ProxyConnect::proxies.begin(), it_end = ProxyConnect::proxies.end(); it != it_end;)
00247 {
00248 ProxyConnect *p = *it;
00249 ++it;
00250 delete p;
00251 }
00252
00253 for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
00254 {
00255 Socket *s = it->second;
00256 ++it;
00257
00258 ClientSocket *cs = dynamic_cast<ClientSocket *>(s);
00259 if (cs != NULL && cs->ls == this->listener)
00260 delete s;
00261 }
00262
00263 delete this->listener;
00264 }
00265
00266 void OnReload() anope_override
00267 {
00268 ConfigReader config;
00269
00270 Anope::string s_target_ip = config.ReadValue("m_proxyscan", "target_ip", "", 0);
00271 if (s_target_ip.empty())
00272 throw ConfigException("m_proxyscan:target_ip may not be empty");
00273
00274 int s_target_port = config.ReadInteger("m_proxyscan", "target_port", "-1", 0, true);
00275 if (s_target_port <= 0)
00276 throw ConfigException("m_proxyscan:target_port may not be empty and must be a positive number");
00277
00278 Anope::string s_listen_ip = config.ReadValue("m_proxyscan", "listen_ip", "", 0);
00279 if (s_listen_ip.empty())
00280 throw ConfigException("m_proxyscan:listen_ip may not be empty");
00281
00282 int s_listen_port = config.ReadInteger("m_proxyscan", "listen_port", "-1", 0, true);
00283 if (s_listen_port <= 0)
00284 throw ConfigException("m_proxyscan:listen_port may not be empty and must be a positive number");
00285
00286 target_ip = s_target_ip;
00287 target_port = s_target_port;
00288 this->listen_ip = s_listen_ip;
00289 this->listen_port = s_listen_port;
00290 this->con_notice = config.ReadValue("m_proxyscan", "connect_notice", "", 0);
00291 this->con_source = config.ReadValue("m_proxyscan", "connect_source", "", 0);
00292 add_to_akill = config.ReadFlag("m_proxyscan", "add_to_akill", "true", 0);
00293 this->connectionTimeout.SetSecs(config.ReadInteger("m_proxyscan", "timeout", "5", 0, true));
00294
00295 ProxyCheckString = Config->NetworkName + " proxy check";
00296 delete this->listener;
00297 this->listener = NULL;
00298 try
00299 {
00300 this->listener = new ProxyCallbackListener(this->listen_ip, this->listen_port);
00301 }
00302 catch (const SocketException &ex)
00303 {
00304 throw ConfigException("m_proxyscan: " + ex.GetReason());
00305 }
00306
00307 this->proxyscans.clear();
00308 for (int i = 0; i < config.Enumerate("proxyscan"); ++i)
00309 {
00310 ProxyCheck p;
00311 Anope::string token;
00312
00313 commasepstream sep(config.ReadValue("proxyscan", "type", "", i));
00314 while (sep.GetToken(token))
00315 {
00316 if (!token.equals_ci("HTTP") && !token.equals_ci("SOCKS5"))
00317 continue;
00318 p.types.insert(token);
00319 }
00320 if (p.types.empty())
00321 continue;
00322
00323 commasepstream sep2(config.ReadValue("proxyscan", "port", "", i));
00324 while (sep2.GetToken(token))
00325 {
00326 try
00327 {
00328 unsigned short port = convertTo<unsigned short>(token);
00329 p.ports.push_back(port);
00330 }
00331 catch (const ConvertException &) { }
00332 }
00333 if (p.ports.empty())
00334 continue;
00335
00336 p.duration = Anope::DoTime(config.ReadValue("proxyscan", "time", "4h", i));
00337 p.reason = config.ReadValue("proxyscan", "reason", "", i);
00338 if (p.reason.empty())
00339 continue;
00340
00341 this->proxyscans.push_back(p);
00342 }
00343 }
00344
00345 void OnUserConnect(User *user, bool &exempt) anope_override
00346 {
00347 if (exempt || user->Quitting() || !Me->IsSynced() || !user->server->IsSynced())
00348 return;
00349
00350
00351 sockaddrs user_ip;
00352 try
00353 {
00354 user_ip.pton(AF_INET, user->ip);
00355 }
00356 catch (const SocketException &)
00357 {
00358
00359 return;
00360 }
00361
00362 if (!this->con_notice.empty() && !this->con_source.empty())
00363 {
00364 const BotInfo *bi = BotInfo::Find(this->con_source);
00365 if (bi)
00366 user->SendMessage(bi, this->con_notice);
00367 }
00368
00369 for (unsigned i = this->proxyscans.size(); i > 0; --i)
00370 {
00371 ProxyCheck &p = this->proxyscans[i - 1];
00372
00373 for (std::set<Anope::string, ci::less>::iterator it = p.types.begin(), it_end = p.types.end(); it != it_end; ++it)
00374 {
00375 for (unsigned k = 0; k < p.ports.size(); ++k)
00376 {
00377 try
00378 {
00379 ProxyConnect *con = NULL;
00380 if (it->equals_ci("HTTP"))
00381 con = new HTTPProxyConnect(p, p.ports[k]);
00382 else if (it->equals_ci("SOCKS5"))
00383 con = new SOCKS5ProxyConnect(p, p.ports[k]);
00384 else
00385 continue;
00386 con->Connect(user->ip, p.ports[k]);
00387 }
00388 catch (const SocketException &ex)
00389 {
00390 Log(LOG_DEBUG) << "m_proxyscan: " << ex.GetReason();
00391 }
00392 }
00393 }
00394 }
00395 }
00396 };
00397
00398 MODULE_INIT(ModuleProxyScan)
00399