Anope IRC Services  Version 2.0
m_proxyscan.cpp
Go to the documentation of this file.
1 /*
2  * (C) 2003-2014 Anope Team
3  * Contact us at team@anope.org
4  *
5  * Please read COPYING and README for further details.
6  */
7 
8 #include "module.h"
9 
10 struct ProxyCheck
11 {
12  std::set<Anope::string, ci::less> types;
13  std::vector<unsigned short> ports;
14  time_t duration;
16 };
17 
20 static unsigned short target_port;
21 static bool add_to_akill;
22 
24 {
26  {
27  public:
29  {
30  }
31 
33  {
34  this->Write(ProxyCheckString);
35  }
36 
38  {
39  return !BufferedSocket::ProcessWrite() || this->write_buffer.empty() ? false : true;
40  }
41  };
42 
43  public:
44  ProxyCallbackListener(const Anope::string &b, int p) : Socket(-1, b.find(':') != Anope::string::npos), ListenSocket(b, p, false)
45  {
46  }
47 
49  {
50  return new ProxyCallbackClient(this, fd, addr);
51  }
52 };
53 
55 {
57 
58  public:
59  static std::set<ProxyConnect *> proxies;
60 
62  unsigned short port;
63  time_t created;
64 
65  ProxyConnect(ProxyCheck &p, unsigned short po) : Socket(-1), ConnectionSocket(), proxy(p),
66  port(po), created(Anope::CurTime)
67  {
68  proxies.insert(this);
69  }
70 
72  {
73  proxies.erase(this);
74  }
75 
76  virtual void OnConnect() anope_override = 0;
77  virtual const Anope::string GetType() const = 0;
78 
79  protected:
80  void Ban()
81  {
82  Anope::string reason = this->proxy.reason;
83 
84  reason = reason.replace_all_cs("%t", this->GetType());
85  reason = reason.replace_all_cs("%i", this->conaddr.addr());
86  reason = reason.replace_all_cs("%p", stringify(this->conaddr.port()));
87 
88  BotInfo *OperServ = Config->GetClient("OperServ");
89  Log(OperServ) << "PROXYSCAN: Open " << this->GetType() << " proxy found on " << this->conaddr.addr() << ":" << this->conaddr.port() << " (" << reason << ")";
90  XLine *x = new XLine("*@" + this->conaddr.addr(), OperServ ? OperServ->nick : "", Anope::CurTime + this->proxy.duration, reason, XLineManager::GenerateUID());
91  if (add_to_akill && akills)
92  {
93  akills->AddXLine(x);
94  akills->Send(NULL, x);
95  }
96  else
97  {
98  if (IRCD->CanSZLine)
99  IRCD->SendSZLine(NULL, x);
100  else
101  IRCD->SendAkill(NULL, x);
102  delete x;
103  }
104  }
105 };
106 ServiceReference<XLineManager> ProxyConnect::akills("XLineManager", "xlinemanager/sgline");
107 std::set<ProxyConnect *> ProxyConnect::proxies;
108 
110 {
111  public:
112  HTTPProxyConnect(ProxyCheck &p, unsigned short po) : Socket(-1), ProxyConnect(p, po), BufferedSocket()
113  {
114  }
115 
117  {
118  this->Write("CONNECT %s:%d HTTP/1.0", target_ip.c_str(), target_port);
119  this->Write("Content-length: 0");
120  this->Write("Connection: close");
121  this->Write("");
122  }
123 
125  {
126  return "HTTP";
127  }
128 
130  {
131  bool b = BufferedSocket::ProcessRead();
132  if (this->GetLine() == ProxyCheckString)
133  {
134  this->Ban();
135  return false;
136  }
137  return b;
138  }
139 };
140 
142 {
143  public:
144  SOCKS5ProxyConnect(ProxyCheck &p, unsigned short po) : Socket(-1), ProxyConnect(p, po), BinarySocket()
145  {
146  }
147 
149  {
150  sockaddrs target_addr;
151  char buf[4 + sizeof(target_addr.sa4.sin_addr.s_addr) + sizeof(target_addr.sa4.sin_port)];
152  int ptr = 0;
153  target_addr.pton(AF_INET, target_ip, target_port);
154  if (!target_addr.valid())
155  return;
156 
157  buf[ptr++] = 5; // Version
158  buf[ptr++] = 1; // # of methods
159  buf[ptr++] = 0; // No authentication
160 
161  this->Write(buf, ptr);
162 
163  ptr = 1;
164  buf[ptr++] = 1; // Connect
165  buf[ptr++] = 0; // Reserved
166  buf[ptr++] = 1; // IPv4
167  memcpy(buf + ptr, &target_addr.sa4.sin_addr.s_addr, sizeof(target_addr.sa4.sin_addr.s_addr));
168  ptr += sizeof(target_addr.sa4.sin_addr.s_addr);
169  memcpy(buf + ptr, &target_addr.sa4.sin_port, sizeof(target_addr.sa4.sin_port));
170  ptr += sizeof(target_addr.sa4.sin_port);
171 
172  this->Write(buf, ptr);
173  }
174 
176  {
177  return "SOCKS5";
178  }
179 
180  bool Read(const char *buffer, size_t l) anope_override
181  {
182  if (l >= ProxyCheckString.length() && !strncmp(buffer, ProxyCheckString.c_str(), ProxyCheckString.length()))
183  {
184  this->Ban();
185  return false;
186  }
187  return true;
188  }
189 };
190 
191 class ModuleProxyScan : public Module
192 {
194  unsigned short listen_port;
196  std::vector<ProxyCheck> proxyscans;
197 
199 
200  class ConnectionTimeout : public Timer
201  {
202  public:
203  ConnectionTimeout(Module *c, long timeout) : Timer(c, timeout, Anope::CurTime, true)
204  {
205  }
206 
207  void Tick(time_t) anope_override
208  {
209  for (std::set<ProxyConnect *>::iterator it = ProxyConnect::proxies.begin(), it_end = ProxyConnect::proxies.end(); it != it_end;)
210  {
211  ProxyConnect *p = *it;
212  ++it;
213 
214  if (p->created + this->GetSecs() < Anope::CurTime)
215  delete p;
216  }
217  }
219 
220  public:
221  ModuleProxyScan(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR),
222  connectionTimeout(this, 5)
223  {
224 
225 
226  this->listener = NULL;
227  }
228 
230  {
231  for (std::set<ProxyConnect *>::iterator it = ProxyConnect::proxies.begin(), it_end = ProxyConnect::proxies.end(); it != it_end;)
232  {
233  ProxyConnect *p = *it;
234  ++it;
235  delete p;
236  }
237 
238  for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
239  {
240  Socket *s = it->second;
241  ++it;
242 
243  ClientSocket *cs = dynamic_cast<ClientSocket *>(s);
244  if (cs != NULL && cs->ls == this->listener)
245  delete s;
246  }
247 
248  delete this->listener;
249  }
250 
252  {
253  Configuration::Block *config = Config->GetModule(this);
254 
255  Anope::string s_target_ip = config->Get<const Anope::string>("target_ip");
256  if (s_target_ip.empty())
257  throw ConfigException(this->name + " target_ip may not be empty");
258 
259  int s_target_port = config->Get<int>("target_port", "-1");
260  if (s_target_port <= 0)
261  throw ConfigException(this->name + " target_port may not be empty and must be a positive number");
262 
263  Anope::string s_listen_ip = config->Get<const Anope::string>("listen_ip");
264  if (s_listen_ip.empty())
265  throw ConfigException(this->name + " listen_ip may not be empty");
266 
267  int s_listen_port = config->Get<int>("listen_port", "-1");
268  if (s_listen_port <= 0)
269  throw ConfigException(this->name + " listen_port may not be empty and must be a positive number");
270 
271  target_ip = s_target_ip;
272  target_port = s_target_port;
273  this->listen_ip = s_listen_ip;
274  this->listen_port = s_listen_port;
275  this->con_notice = config->Get<const Anope::string>("connect_notice");
276  this->con_source = config->Get<const Anope::string>("connect_source");
277  add_to_akill = config->Get<bool>("add_to_akill", "true");
278  this->connectionTimeout.SetSecs(config->Get<time_t>("timeout", "5s"));
279 
280  ProxyCheckString = Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname") + " proxy check";
281  delete this->listener;
282  this->listener = NULL;
283  try
284  {
285  this->listener = new ProxyCallbackListener(this->listen_ip, this->listen_port);
286  }
287  catch (const SocketException &ex)
288  {
289  throw ConfigException("m_proxyscan: " + ex.GetReason());
290  }
291 
292  this->proxyscans.clear();
293  for (int i = 0; i < config->CountBlock("proxyscan"); ++i)
294  {
295  Configuration::Block *block = config->GetBlock("proxyscan", i);
296  ProxyCheck p;
297  Anope::string token;
298 
299  commasepstream sep(block->Get<const Anope::string>("type"));
300  while (sep.GetToken(token))
301  {
302  if (!token.equals_ci("HTTP") && !token.equals_ci("SOCKS5"))
303  continue;
304  p.types.insert(token);
305  }
306  if (p.types.empty())
307  continue;
308 
309  commasepstream sep2(block->Get<const Anope::string>("port"));
310  while (sep2.GetToken(token))
311  {
312  try
313  {
314  unsigned short port = convertTo<unsigned short>(token);
315  p.ports.push_back(port);
316  }
317  catch (const ConvertException &) { }
318  }
319  if (p.ports.empty())
320  continue;
321 
322  p.duration = block->Get<time_t>("time", "4h");
323  p.reason = block->Get<const Anope::string>("reason");
324  if (p.reason.empty())
325  continue;
326 
327  this->proxyscans.push_back(p);
328  }
329  }
330 
331  void OnUserConnect(User *user, bool &exempt) anope_override
332  {
333  if (exempt || user->Quitting() || !Me->IsSynced() || !user->server->IsSynced())
334  return;
335 
336  /* At this time we only support IPv4 */
337  if (!user->ip.valid() || user->ip.sa.sa_family != AF_INET)
338  /* User doesn't have a valid IPv4 IP (ipv6/spoof/etc) */
339  return;
340 
341  if (!this->con_notice.empty() && !this->con_source.empty())
342  {
343  BotInfo *bi = BotInfo::Find(this->con_source, true);
344  if (bi)
345  user->SendMessage(bi, this->con_notice);
346  }
347 
348  for (unsigned i = this->proxyscans.size(); i > 0; --i)
349  {
350  ProxyCheck &p = this->proxyscans[i - 1];
351 
352  for (std::set<Anope::string, ci::less>::iterator it = p.types.begin(), it_end = p.types.end(); it != it_end; ++it)
353  {
354  for (unsigned k = 0; k < p.ports.size(); ++k)
355  {
356  try
357  {
358  ProxyConnect *con = NULL;
359  if (it->equals_ci("HTTP"))
360  con = new HTTPProxyConnect(p, p.ports[k]);
361  else if (it->equals_ci("SOCKS5"))
362  con = new SOCKS5ProxyConnect(p, p.ports[k]);
363  else
364  continue;
365  con->Connect(user->ip.addr(), p.ports[k]);
366  }
367  catch (const SocketException &ex)
368  {
369  Log(LOG_DEBUG) << "m_proxyscan: " << ex.GetReason();
370  }
371  }
372  }
373  }
374  }
375 };
376 
378 
Definition: bots.h:24
void OnUserConnect(User *user, bool &exempt) anope_override
bool CanSZLine
Definition: protocol.h:61
ModuleProxyScan(const Anope::string &modname, const Anope::string &creator)
Anope::string name
Definition: modules.h:221
int CountBlock(const Anope::string &name)
Definition: config.cpp:35
void pton(int type, const Anope::string &address, int pport=0)
Definition: sockets.cpp:121
Definition: timers.h:18
bool IsSynced() const
Definition: servers.cpp:298
virtual void Write(const char *buffer, size_t l)
ClientSocket * OnAccept(int fd, const sockaddrs &addr) anope_override
Definition: m_proxyscan.cpp:48
static unsigned short target_port
Definition: m_proxyscan.cpp:20
const Anope::string GetType() const anope_override
Anope::string con_notice
void OnConnect() anope_override
const Anope::string GetLine()
sockaddr_in sa4
Definition: sockets.h:31
void push_back(char c)
Definition: anope.h:142
SOCKS5ProxyConnect(ProxyCheck &p, unsigned short po)
bool ProcessRead() anope_override
Anope::string addr() const
Definition: sockets.cpp:73
ProxyCallbackClient(ListenSocket *l, int f, const sockaddrs &a)
Definition: m_proxyscan.cpp:28
bool IsIPv6() const
Definition: sockets.cpp:479
static Anope::string ProxyCheckString
Definition: m_proxyscan.cpp:18
Anope::string con_source
ProxyCallbackListener(const Anope::string &b, int p)
Definition: m_proxyscan.cpp:44
Anope::string write_buffer
Definition: sockets.h:275
Definition: users.h:34
virtual void SendAkill(User *, XLine *)=0
static std::map< int, Socket * > Sockets
Definition: socketengine.h:24
ModuleProxyScan::ConnectionTimeout connectionTimeout
void OnConnect() anope_override
std::vector< unsigned short > ports
Definition: m_proxyscan.cpp:13
bool Read(const char *buffer, size_t l) anope_override
bool equals_ci(const char *_str) const
Definition: anope.h:78
time_t created
Definition: m_proxyscan.cpp:63
CoreExport time_t CurTime
Definition: main.cpp:41
Anope::string reason
Definition: m_proxyscan.cpp:15
static Anope::string target_ip
Definition: m_proxyscan.cpp:19
ProxyCallbackListener * listener
std::set< Anope::string, ci::less > types
Definition: m_proxyscan.cpp:12
void Connect(const Anope::string &TargetHost, int Port)
size_type length() const
Definition: anope.h:131
bool ProcessRead() anope_override
Block * GetBlock(const Anope::string &name, int num=0)
Definition: config.cpp:43
sockaddrs conaddr
Definition: sockets.h:391
Definition: Config.cs:26
bool valid() const
Definition: sockets.cpp:99
ListenSocket * ls
Definition: sockets.h:424
int port() const
Definition: sockets.cpp:58
static bool add_to_akill
Definition: m_proxyscan.cpp:21
string replace_all_cs(const string &_orig, const string &_repl) const
Definition: anope.h:229
unsigned short listen_port
virtual void Write(const char *buffer, size_t l)
virtual void OnConnect() anope_override=0
void OnReload(Configuration::Conf *conf) anope_override
ProxyCheck proxy
Definition: m_proxyscan.cpp:61
#define anope_override
Definition: services.h:56
bool empty() const
Definition: anope.h:126
bool ProcessWrite() anope_override
static std::set< ProxyConnect * > proxies
Definition: m_proxyscan.cpp:59
CoreExport IRCDProto * IRCD
Definition: protocol.cpp:23
std::basic_string< char, ci_char_traits, std::allocator< char > > string
Definition: hashcomp.h:133
#define MODULE_INIT(x)
Definition: modules.h:45
static Timer * timeout
Definition: os_defcon.cpp:106
virtual void SendSZLine(User *u, const XLine *)
Definition: protocol.h:116
Anope::string stringify(const T &x)
Definition: anope.h:710
Anope::string nick
Definition: users.h:62
HTTPProxyConnect(ProxyCheck &p, unsigned short po)
Anope::string listen_ip
ProxyConnect(ProxyCheck &p, unsigned short po)
Definition: m_proxyscan.cpp:65
void SetSecs(time_t t)
Definition: timers.cpp:64
Definition: xline.h:18
bool GetToken(Anope::string &token)
Definition: hashcomp.cpp:99
static ServiceReference< XLineManager > akills
Definition: m_proxyscan.cpp:56
virtual const Anope::string GetType() const =0
CoreExport Server * Me
Definition: servers.cpp:24
virtual const Anope::string & GetReason() const
Definition: anope.h:672
ConnectionTimeout(Module *c, long timeout)
const Anope::string GetType() const anope_override
const char * c_str() const
Definition: anope.h:117
Definition: logger.h:53
T Get(const Anope::string &tag)
Definition: config.h:44
unsigned short port
Definition: m_proxyscan.cpp:62
static Anope::string GenerateUID()
Definition: xline.cpp:234
void Tick(time_t) anope_override
time_t duration
Definition: m_proxyscan.cpp:14
static BotInfo * Find(const Anope::string &nick, bool nick_only=false)
Definition: bots.cpp:249
Definition: anope.h:20
std::vector< ProxyCheck > proxyscans
Definition: modules.h:163