summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2010-09-09 23:43:11 -0400
committerAdam <Adam@anope.org>2010-09-09 23:43:11 -0400
commit46813ccb8c6ab572b8a9ff0a39afb1d92dc4482b (patch)
tree562da502a102230ce207bbe921fdc978ee71e20c
parentfdd196e50b4616ac377bd0ee0ae5ce6c57b657ee (diff)
Added an asynchronous DNS system and m_dnsbl, which checks clients against DNS blacklists.
Rewrote internal handling of IPs, we now properly support users using IPv6. Fixed a few problems with the UnrealIRCd protocol module.
-rw-r--r--CMakeLists.txt1
-rw-r--r--data/example.conf79
-rw-r--r--docs/Changes.conf2
-rw-r--r--include/config.h5
-rw-r--r--include/dns.h181
-rw-r--r--include/extern.h6
-rw-r--r--include/services.h7
-rw-r--r--include/socketengine.h4
-rw-r--r--include/sockets.h76
-rw-r--r--include/sysconf.h.cmake1
-rw-r--r--include/users.h8
-rw-r--r--modules/core/os_defcon.cpp2
-rw-r--r--modules/extra/m_dnsbl.cpp123
-rw-r--r--modules/protocol/bahamut.cpp5
-rw-r--r--modules/protocol/inspircd11.cpp7
-rw-r--r--modules/protocol/inspircd12.cpp5
-rw-r--r--modules/protocol/inspircd20.cpp5
-rw-r--r--modules/protocol/ratbox.cpp5
-rw-r--r--modules/protocol/unreal32.cpp21
-rw-r--r--modules/socketengines/m_socketengine_epoll.cpp20
-rw-r--r--modules/socketengines/m_socketengine_select.cpp16
-rw-r--r--src/actions.cpp19
-rw-r--r--src/base64.cpp14
-rw-r--r--src/channels.cpp24
-rw-r--r--src/config.cpp32
-rw-r--r--src/dns.cpp550
-rw-r--r--src/init.cpp9
-rw-r--r--src/logger.cpp2
-rw-r--r--src/main.cpp5
-rw-r--r--src/misc.cpp63
-rw-r--r--src/operserv.cpp20
-rw-r--r--src/servers.cpp9
-rw-r--r--src/sockets.cpp288
-rw-r--r--src/users.cpp39
34 files changed, 1304 insertions, 349 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f3c1e26df..a92086489 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -322,7 +322,6 @@ check_include_file(sys/select.h HAVE_SYS_SELECT_H)
check_include_file(sys/eventfd.h HAVE_SYS_EVENTFD_H)
# Check for the existance of the following functions
-check_function_exists(gethostbyname HAVE_GETHOSTBYNAME)
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
check_function_exists(setgrent HAVE_SETGRENT)
check_function_exists(strcasecmp HAVE_STRCASECMP)
diff --git a/data/example.conf b/data/example.conf
index d7c7c9372..b98595ef7 100644
--- a/data/example.conf
+++ b/data/example.conf
@@ -820,6 +820,29 @@ mail
}
/*
+ * [OPTIONAL] DNS Config
+ *
+ * This section is used to configure DNS.
+ * At this time DNS is only used by a few modules (m_dnsbl)
+ * and is not required by the core to function.
+ */
+dns
+{
+ /*
+ * The nameserver to use for resolving hostnames, must be an IP or a resolver configuration file.
+ * The below should work fine on all nix like systems. Windows users will have to find their nameservers
+ * from ipconfig /all and put the IP here
+ */
+ nameserver = "/etc/resolv.conf"
+ #nameserver = "127.0.0.1"
+
+ /*
+ * How long to wait before a DNS query has timed out
+ */
+ timeout = 5
+}
+
+/*
* [REQUIRED] NickServ Config
*
* This section is used to set up the Nickname Registration Service pseudo-client.
@@ -1585,7 +1608,13 @@ module { name = "os_ignore" }
module { name = "cs_appendtopic" }
module { name = "cs_enforce" }
module { name = "ns_maxemail" }
-module { name = "hs_request" }
+
+/*
+ * [OPTIONAL] Module-Specific Options
+ *
+ * The following blocks are used for options pertaining to modules and are not part of the core.
+ * Unless otherwise stated, most of the options are optional.
+ */
/*
* m_ssl
@@ -1595,10 +1624,9 @@ module { name = "hs_request" }
module { name = "m_ssl" }
/*
- * [OPTIONAL] Module-Specific Options
+ * db_plain
*
- * The following blocks are used for options pertaining to modules and are not part of the core.
- * Unless otherwise stated, most of the options are optional.
+ * This is the default flatfile database format
*/
db_plain
{
@@ -1608,11 +1636,20 @@ db_plain
database = "anope.db"
}
+/*
+ * cs_set_misc
+ *
+ * Allows you to create misc /chanserv set commands, and have the data
+ * show up in /chanserv info
+ */
module { name = "cs_set_misc" }
cs_set_misc
{
+ /* The name of the command */
name = "OINFO"
+ /* A short description of the command */
desc = "Associate oper only information to this channel"
+ /* Set to yes if only opers can set it and see it */
operonly = yes
}
cs_set_misc
@@ -1654,6 +1691,7 @@ m_helpchan
helpchannel = "#help"
}
+module { name = "hs_request" }
hs_request
{
/*
@@ -1683,3 +1721,36 @@ ns_maxemail
#maxemails = 1
}
+module { name = "m_dnsbl" }
+m_dnsbl
+{
+ /*
+ * If set, Services will check clients against the DNSBLs when services connect to its uplink.
+ * This is not recommended, and on large networks will open a very large amount of DNS queries.
+ * While services are not drastically affected by this, your nameserver/DNSBL might care.
+ */
+ check_on_connect = no;
+
+ /*
+ * If set, Services will check clients when coming back from a netsplit. This can cause a large number
+ * of DNS queries open at once. While services are not drastically affected by this, your nameserver/DNSBL
+ * might care.
+ */
+ check_on_netburst = no;
+}
+blacklist
+{
+ /* Name of the blacklist */
+ name = "rbl.efnetrbl.org";
+ /* How long to set the akill for */
+ time = 4h;
+ /* Reason for akill, %h is replaced with the hostname of the user, and %i with the IP */
+ reason = "You are listed in the efnet RBL, visit http://rbl.efnetrbl.org/?i=%i for info"
+}
+blacklist
+{
+ name = "dnsbl.dronebl.org";
+ time = 4h;
+ reason = "You have a host listed in the DroneBL. For more information, visit http://dronebl.org/lookup.do?ip=%i"
+}
+
diff --git a/docs/Changes.conf b/docs/Changes.conf
index c49953e6d..992624d63 100644
--- a/docs/Changes.conf
+++ b/docs/Changes.conf
@@ -12,6 +12,8 @@ options:socketengine added to choose what socket engine to use
module:cs_set_misc and module:ns_set_misc added to replace the old set url/icq/email modules
options:hideprivilegedcommands added to hide privileged commands from normal users
log block added to customize logging
+dns block added to configure dns settings
+m_dnsbl added
** MODIFIED CONFIGURATION DIRECTIVES **
opertype:commands changed operserv/sgline to opserv/snline
diff --git a/include/config.h b/include/config.h
index 11969707f..4ea2aae23 100644
--- a/include/config.h
+++ b/include/config.h
@@ -572,6 +572,11 @@ class ServerConfig
/* Don't quote the To: address */
bool DontQuoteAddresses;
+ /* Nameserver to use for resolving hostnames */
+ Anope::string NameServer;
+ /* TIme before a DNS query is considered dead */
+ time_t DNSTimeout;
+
/* Prefix of guest nicks when a user gets forced off of a nick */
Anope::string NSGuestNickPrefix;
/* Allow users to set kill immed on */
diff --git a/include/dns.h b/include/dns.h
new file mode 100644
index 000000000..a8ef82d44
--- /dev/null
+++ b/include/dns.h
@@ -0,0 +1,181 @@
+#ifndef DNS_H
+#define DNS_H
+
+/** Valid query types
+ */
+enum QueryType
+{
+ /* Nothing */
+ DNS_QUERY_NONE,
+ /* A simple A lookup */
+ DNS_QUERY_A = 1,
+ /* A CNAME lookup */
+ DNS_QUERY_CNAME = 5,
+ /* Reverse DNS lookup */
+ DNS_QUERY_PTR = 12,
+ /* IPv6 AAAA lookup */
+ DNS_QUERY_AAAA = 28
+};
+
+/** Flags that can be AND'd into DNSPacket::flags to receive certain values
+ */
+enum QueryFlags
+{
+ DNS_QUERYFLAGS_QR = 0x8000,
+ DNS_QUERYFLAGS_OPCODE = 0x7800,
+ DNS_QUERYFLAGS_AA = 0x400,
+ DBS_QUERYFLAGS_TC = 0x200,
+ DNS_QUERYFLAGS_RD = 0x100,
+ DNS_QUERYFLAGS_RA = 0x80,
+ DNS_QUERYFLAGS_Z = 0x70,
+ DNS_QUERYFLAGS_RCODE = 0xF
+};
+
+enum DNSError
+{
+ DNS_ERROR_UNKNOWN,
+ DNS_ERROR_TIMEOUT,
+ DNS_ERROR_NOT_AN_ANSWER,
+ DNS_ERROR_NONSTANDARD_QUERY,
+ DNS_ERROR_FORMAT_ERROR,
+ DNS_ERROR_SERVER_FAILURE,
+ DNS_ERROR_DOMAIN_NOT_FOUND,
+ DNS_ERROR_NOT_IMPLEMENTED,
+ DNS_ERROR_REFUSED,
+ DNS_ERROR_NO_RECORDS,
+ DNS_ERROR_INVALID_TYPE
+};
+
+class DNSRequestTimeout; // Forward declarations
+struct DNSRecord;
+
+/** The request
+ */
+class DNSRequest
+{
+ /* Timeout timer for this request */
+ DNSRequestTimeout *timeout;
+
+ public:
+ /* Address we're looking up */
+ Anope::string address;
+ /* QueryType, A, AAAA, PTR etc */
+ QueryType QT;
+
+ DNSRequest(const Anope::string &addr, QueryType qt, bool cache = false);
+
+ virtual ~DNSRequest();
+
+ virtual void OnLookupComplete(const DNSRecord *r) = 0;
+
+ virtual void OnError(DNSError error, const Anope::string &message);
+};
+
+/** A full packet sent to the nameserver, may contain multiple queries
+ */
+struct DNSPacket
+{
+ /* Our 16-bit id for this header */
+ unsigned short id;
+ /* Flags on the query */
+ unsigned short flags;
+ /* Number of queries */
+ unsigned short qdcount;
+ /* Number of resource records in answer */
+ unsigned short ancount;
+ /* Number of NS resource records in authority records section */
+ unsigned short nscount;
+ /* Number of resource records in the additional records section */
+ unsigned short arcount;
+ /* How many of the bytes of the payload are in use */
+ unsigned short payload_count;
+ /* The queries, at most can be 512 bytes */
+ unsigned char payload[512];
+
+ inline DNSPacket();
+
+ bool AddQuestion(const Anope::string &address, QueryType qt);
+
+ inline void FillPacket(const unsigned char *input, const size_t length);
+
+ inline void FillBuffer(unsigned char *buffer);
+};
+
+struct DNSRecord
+{
+ /* Name of the initial lookup */
+ Anope::string name;
+ /* Result of the lookup */
+ Anope::string result;
+ /* Type of query this was */
+ QueryType type;
+ /* Record class, should always be 1 */
+ unsigned short record_class;
+ /* Time to live */
+ unsigned long ttl;
+ /* Record length */
+ unsigned short rdlength;
+
+ inline DNSRecord();
+ time_t created;
+};
+
+/** The socket used to talk to the nameserver, uses UDP
+ */
+class DNSSocket : public ClientSocket
+{
+ private:
+ sockaddrs server_addr;
+
+ int SendTo(const unsigned char *buf, size_t len) const;
+ int RecvFrom(char *buf, size_t size, sockaddrs &addrs) const;
+ public:
+ DNSSocket(const Anope::string &nTargetHost, int nPort);
+ virtual ~DNSSocket();
+
+ bool ProcessRead();
+
+ bool ProcessWrite();
+};
+
+/** DNS manager, manages the connection and all requests
+ */
+class DNSManager : public Timer
+{
+ std::multimap<Anope::string, DNSRecord *> cache;
+ public:
+ DNSSocket *sock;
+
+ std::deque<DNSPacket *> packets;
+ std::map<short, DNSRequest *> requests;
+
+ static const int DNSPort = 53;
+
+ DNSManager();
+
+ ~DNSManager();
+
+ void AddCache(DNSRecord *rr);
+ bool CheckCache(DNSRequest *request);
+ void Tick(time_t now);
+};
+
+/** A DNS timeout, one is made for every DNS request to detect timeouts
+ */
+class DNSRequestTimeout : public Timer
+{
+ DNSRequest *request;
+ public:
+ bool done;
+
+ DNSRequestTimeout(DNSRequest *r, time_t timeout);
+
+ ~DNSRequestTimeout();
+
+ void Tick(time_t);
+};
+
+extern DNSManager *DNSEngine;
+
+#endif // DNS_H
+
diff --git a/include/extern.h b/include/extern.h
index 48336be5f..2294c3f28 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -276,7 +276,6 @@ E uint16 netmask_to_cidr(uint32 mask);
E bool str_is_wildcard(const Anope::string &str);
E bool str_is_pure_wildcard(const Anope::string &str);
-E uint32 str_is_ip(const Anope::string &str);
E bool str_is_cidr(const Anope::string &str, uint32 &ip, uint32 &mask, Anope::string &host);
/**** modes.cpp ****/
@@ -362,7 +361,7 @@ E User *finduser(const Anope::string &nick);
E Anope::string TS6SID;
-E User *do_nick(const Anope::string &source, const Anope::string &nick, const Anope::string &username, const Anope::string &host, const Anope::string &server, const Anope::string &realname, time_t ts, uint32 ip, const Anope::string &vhost, const Anope::string &uid);
+E User *do_nick(const Anope::string &source, const Anope::string &nick, const Anope::string &username, const Anope::string &host, const Anope::string &server, const Anope::string &realname, time_t ts, const Anope::string &ip, const Anope::string &vhost, const Anope::string &uid);
E void do_umode(const Anope::string &source, int ac, const char **av);
E void do_quit(const Anope::string &source, int ac, const char **av);
@@ -382,9 +381,6 @@ E void UserSetInternalModes(User *user, int ac, const char **av);
E void b64_encode(const Anope::string &src, Anope::string &target);
E void b64_decode(const Anope::string &src, Anope::string &target);
-E int decode_ip(const Anope::string &buf);
-
-E Anope::string host_resolve(const Anope::string &host);
#ifdef _WIN32
E Anope::string GetWindowsVersion();
diff --git a/include/services.h b/include/services.h
index f44425656..63e2492b2 100644
--- a/include/services.h
+++ b/include/services.h
@@ -363,6 +363,9 @@ template<typename T, size_t Size = 32> class Flags
#include "sockets.h"
#include "socketengine.h"
+#include "extensible.h"
+#include "timers.h"
+#include "dns.h"
/*************************************************************************/
@@ -427,7 +430,6 @@ class Server;
struct EList;
struct Session;
-#include "extensible.h"
#include "threadengine.h"
#include "opertype.h"
#include "modes.h"
@@ -457,7 +459,6 @@ struct IRCDVar
int vident; /* Supports vidents */
int svshold; /* Supports svshold */
int tsonmode; /* Timestamp on mode changes */
- int nickip; /* Sends IP on NICK */
int omode; /* On the fly o:lines */
int umode; /* change user modes */
int nickvhost; /* Users vhost sent during NICK */
@@ -1054,8 +1055,6 @@ struct Uplink
Uplink(const Anope::string &_host, int _port, const Anope::string &_password, bool _ipv6) : host(_host), port(_port), password(_password), ipv6(_ipv6) { }
};
-#include "timers.h"
-
/** Timer for colliding nicks to force people off of nicknames
*/
class NickServCollide : public Timer
diff --git a/include/socketengine.h b/include/socketengine.h
index 7279ba3ad..c45249810 100644
--- a/include/socketengine.h
+++ b/include/socketengine.h
@@ -43,12 +43,12 @@ class CoreExport SocketEngineBase
/** Mark a socket as writeable
* @param s The socket
*/
- virtual void MarkWriteable(Socket *s) { }
+ virtual void MarkWritable(Socket *s) { }
/** Unmark a socket as writeable
* @param s The socket
*/
- virtual void ClearWriteable(Socket *s) { }
+ virtual void ClearWritable(Socket *s) { }
/** Read from sockets and do things
*/
diff --git a/include/sockets.h b/include/sockets.h
index 6eeb3bf3d..772a08a65 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -22,6 +22,49 @@
# define CloseSocket close
#endif
+/** A sockaddr union used to combine IPv4 and IPv6 sockaddrs
+ */
+union CoreExport sockaddrs
+{
+ sockaddr sa;
+ sockaddr_in sa4;
+ sockaddr_in6 sa6;
+
+ /** Get the size of the sockaddr we represent
+ * @return The size
+ */
+ size_t size() const;
+
+ /** Get the port represented by this addr
+ * @return The port, or -1 on fail
+ */
+ int port() const;
+
+ /** Get the address represented by this addr
+ * @return The address
+ */
+ Anope::string addr() const;
+
+ /** Construct the object, sets everything to 0
+ */
+ sockaddrs();
+
+ /** Check if this sockaddr has data in it
+ */
+ bool operator()() const;
+
+ /** Compares with sockaddr with another. Compares address type, port, and address
+ * @return true if they are the same
+ */
+ bool operator==(const sockaddrs &other) const;
+ /* The same as above but not */
+ inline bool operator!=(const sockaddrs &other) const { return !(*this == other); }
+
+ void pton(int type, const Anope::string &address, int pport = 0);
+
+ void ntop(int type, const void *src);
+};
+
class SocketException : public CoreException
{
public:
@@ -44,12 +87,13 @@ enum SocketType
enum SocketFlag
{
- SF_DEAD
+ SF_DEAD,
+ SF_WRITABLE
};
-class CoreExport Socket : public Flags<SocketFlag, 1>
+class CoreExport Socket : public Flags<SocketFlag, 2>
{
- private:
+ protected:
/** Really recieve something from the buffer
* @param buf The buf to read to
* @param sz How much to read
@@ -63,7 +107,6 @@ class CoreExport Socket : public Flags<SocketFlag, 1>
*/
virtual int SendInternal(const Anope::string &buf) const;
- protected:
/* Socket FD */
int Sock;
/* Port we're connected to */
@@ -88,8 +131,9 @@ class CoreExport Socket : public Flags<SocketFlag, 1>
/** Default constructor
* @param nsock The socket to use, 0 if we need to create our own
* @param nIPv6 true if using ipv6
+ * @param type The socket type, defaults to SOCK_STREAM
*/
- Socket(int nsock, bool nIPv6);
+ Socket(int nsock, bool nIPv6, int type = SOCK_STREAM);
/** Default destructor
*/
@@ -130,7 +174,7 @@ class CoreExport Socket : public Flags<SocketFlag, 1>
*/
virtual bool ProcessRead();
- /** Called when there is something to be written to this socket
+ /** Called when the socket is ready to be written to
* @return true on success, false to drop this socket
*/
virtual bool ProcessWrite();
@@ -156,20 +200,37 @@ class CoreExport Socket : public Flags<SocketFlag, 1>
class CoreExport Pipe : public Socket
{
private:
+ /** The FD of the write pipe (if this isn't evenfd)
+ * this->Sock is the readfd
+ */
int WritePipe;
+ /** Our overloaded RecvInternal call
+ */
int RecvInternal(char *buf, size_t sz) const;
+ /** Our overloaded SendInternal call
+ */
int SendInternal(const Anope::string &buf) const;
public:
+ /** Constructor
+ */
Pipe();
+ /** Called when data is to be read
+ */
bool ProcessRead();
+ /** Function that calls OnNotify
+ */
bool Read(const Anope::string &);
+ /** Called when this pipe needs to be woken up
+ */
void Notify();
+ /** Should be overloaded to do something useful
+ */
virtual void OnNotify();
};
@@ -190,8 +251,9 @@ class CoreExport ClientSocket : public Socket
* @param nPort The target port to connect to
* @param nBindHost The host to bind to for connecting
* @param nIPv6 true to use IPv6
+ * @param type The socket type, defaults to SOCK_STREAM
*/
- ClientSocket(const Anope::string &nTargetHost, int nPort, const Anope::string &nBindHost, bool nIPv6);
+ ClientSocket(const Anope::string &nTargetHost, int nPort, const Anope::string &nBindHost = "", bool nIPv6 = false, int type = SOCK_STREAM);
/** Default destructor
*/
diff --git a/include/sysconf.h.cmake b/include/sysconf.h.cmake
index 0184c5359..2d278e3dd 100644
--- a/include/sysconf.h.cmake
+++ b/include/sysconf.h.cmake
@@ -8,7 +8,6 @@
#cmakedefine HAVE_STDINT_H 1
#cmakedefine HAVE_STDDEF_H 1
#cmakedefine HAVE_BACKTRACE 1
-#cmakedefine HAVE_GETHOSTBYNAME 1
#cmakedefine HAVE_GETTIMEOFDAY 1
#cmakedefine HAVE_SETGRENT 1
#cmakedefine HAVE_STRCASECMP 1
diff --git a/include/users.h b/include/users.h
index 596f5ee39..b880a197a 100644
--- a/include/users.h
+++ b/include/users.h
@@ -51,10 +51,10 @@ class CoreExport User : public Extensible
Anope::string nick; /* User's current nick */
Anope::string host; /* User's real hostname */
- Anope::string hostip; /* User's IP number */
- Anope::string vhost; /* User's virtual hostname */
- Anope::string chost; /* User's cloaked hostname */
- Anope::string realname; /* Realname */
+ Anope::string vhost; /* User's virtual hostname */
+ Anope::string chost; /* User's cloaked hostname */
+ Anope::string realname; /* Realname */
+ sockaddrs ip; /* User's IP */
Server *server; /* Server user is connected to */
time_t timestamp; /* Timestamp of the nick */
time_t my_signon; /* When did _we_ see the user? */
diff --git a/modules/core/os_defcon.cpp b/modules/core/os_defcon.cpp
index 009d34dda..711046beb 100644
--- a/modules/core/os_defcon.cpp
+++ b/modules/core/os_defcon.cpp
@@ -274,7 +274,7 @@ class OSDefcon : public Module
void OnUserConnect(User *u)
{
Session *session = findsession(u->host);
- Exception *exception = find_hostip_exception(u->host, u->hostip);
+ Exception *exception = find_hostip_exception(u->host, u->ip.addr());
if (CheckDefCon(DEFCON_REDUCE_SESSION) && !exception)
{
diff --git a/modules/extra/m_dnsbl.cpp b/modules/extra/m_dnsbl.cpp
new file mode 100644
index 000000000..cecff84a8
--- /dev/null
+++ b/modules/extra/m_dnsbl.cpp
@@ -0,0 +1,123 @@
+/*
+ * (C) 2003-2010 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ */
+
+#include "module.h"
+
+struct Blacklist
+{
+ Anope::string name;
+ time_t bantime;
+ Anope::string reason;
+
+ Blacklist(const Anope::string &n, time_t b, const Anope::string &r) : name(n), bantime(b), reason(r) { }
+};
+
+class DNSBLResolver : public DNSRequest
+{
+ dynamic_reference<User> user;
+ Blacklist blacklist;
+ public:
+ DNSBLResolver(User *u, const Blacklist &b, const Anope::string &host) : DNSRequest(host, DNS_QUERY_A, true), user(u), blacklist(b) { }
+
+ void OnLookupComplete(const DNSRecord *)
+ {
+ if (!user || !SGLine)
+ return;
+
+ Anope::string reason = this->blacklist.reason;
+ reason = reason.replace_all_ci("%i", user->ip.addr());
+ reason = reason.replace_all_ci("%h", user->host);
+
+ XLine *x = SGLine->Add(NULL, NULL, Anope::string("*@") + user->host, time(NULL) + this->blacklist.bantime, reason);
+ if (x)
+ {
+ static Command command_akill("AKILL", 0);
+ command_akill.service = OperServ;
+ Log(LOG_COMMAND, OperServ, &command_akill) << "for " << user->GetMask() << " (Listed in " << this->blacklist.name << ")";
+ /* If AkillOnAdd is disabled send it anyway, noone wants bots around... */
+ if (!Config->AkillOnAdd)
+ ircdproto->SendAkill(x);
+ }
+ }
+};
+
+class ModuleDNSBL : public Module
+{
+ std::vector<Blacklist> blacklists;
+ bool check_on_connect;
+ bool check_on_netburst;
+
+ public:
+ ModuleDNSBL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator)
+ {
+ OnReload(false);
+
+ Implementation i[] = { I_OnReload, I_OnPreUserConnect };
+ ModuleManager::Attach(i, this, 2);
+ }
+
+ void OnReload(bool)
+ {
+ ConfigReader config;
+
+ this->check_on_connect = config.ReadFlag("m_dnsbl", "check_on_connect", "no", 0);
+ this->check_on_netburst = config.ReadFlag("m_dnsbl", "check_on_netburst", "no", 0);
+
+ this->blacklists.clear();
+ for (int i = 0, num = config.Enumerate("blacklist"); i < num; ++i)
+ {
+ Anope::string bname = config.ReadValue("blacklist", "name", "", i);
+ if (bname.empty())
+ continue;
+ Anope::string sbantime = config.ReadValue("blacklist", "time", "4h", i);
+ time_t bantime = dotime(sbantime);
+ if (bantime < 0)
+ bantime = 9000;
+ Anope::string reason = config.ReadValue("blacklist", "reason", "", i);
+
+ this->blacklists.push_back(Blacklist(bname, bantime, reason));
+ }
+ }
+
+ EventReturn OnPreUserConnect(User *u)
+ {
+ if (!this->check_on_connect && !Me->IsSynced())
+ return EVENT_CONTINUE;
+ if (!this->check_on_netburst && !u->server->IsSynced())
+ return EVENT_CONTINUE;
+ /* At this time we only support IPv4 */
+ if (u->ip.sa.sa_family != AF_INET)
+ return EVENT_CONTINUE;
+
+ unsigned long ip = u->ip.sa4.sin_addr.s_addr;
+ unsigned long reverse_ip = ((ip & 0xFF) << 24) | ((ip & 0xFF00) << 8) | ((ip & 0xFF0000) >> 8) | ((ip & 0xFF000000) >> 24);
+
+ sockaddrs user_ip;
+ user_ip.sa4.sin_family = AF_INET;
+ user_ip.sa4.sin_addr.s_addr = reverse_ip;
+
+ for (unsigned i = 0; i < this->blacklists.size(); ++i)
+ {
+ const Blacklist &b = this->blacklists[i];
+
+ try
+ {
+ Anope::string dnsbl_host = user_ip.addr() + "." + b.name;
+ new DNSBLResolver(u, b, dnsbl_host);
+ }
+ catch (const SocketException &ex)
+ {
+ Log() << "Resolver: " << ex.GetReason();
+ }
+ }
+
+ return EVENT_CONTINUE;
+ }
+};
+
+MODULE_INIT(ModuleDNSBL)
+
diff --git a/modules/protocol/bahamut.cpp b/modules/protocol/bahamut.cpp
index ae65bd364..9938d33c7 100644
--- a/modules/protocol/bahamut.cpp
+++ b/modules/protocol/bahamut.cpp
@@ -34,7 +34,6 @@ IRCDVar myIrcd[] = {
0, /* vidents */
1, /* svshold */
1, /* time stamp on mode */
- 1, /* NICKIP */
0, /* O:LINE */
1, /* UMODE */
0, /* VHOST ON NICK */
@@ -451,7 +450,7 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
if (ac != 2)
{
- user = do_nick(source, av[0], av[4], av[5], av[6], av[9], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, Anope::string(av[8]).is_pos_number_only() ? convertTo<uint32>(av[8]) : 0, "", "");
+ user = do_nick(source, av[0], av[4], av[5], av[6], av[9], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, av[8], "", "");
if (user)
{
UserSetInternalModes(user, 1, &av[3]);
@@ -467,7 +466,7 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
}
}
else
- do_nick(source, av[0], "", "", "", "", Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : 0, 0, "", "");
+ do_nick(source, av[0], "", "", "", "", Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : 0, "", "", "");
return MOD_CONT;
}
diff --git a/modules/protocol/inspircd11.cpp b/modules/protocol/inspircd11.cpp
index ebbedd362..042814465 100644
--- a/modules/protocol/inspircd11.cpp
+++ b/modules/protocol/inspircd11.cpp
@@ -35,7 +35,6 @@ IRCDVar myIrcd[] = {
1, /* vidents */
1, /* svshold */
0, /* time stamp on mode */
- 0, /* NICKIP */
1, /* O:LINE */
1, /* UMODE */
1, /* VHOST ON NICK */
@@ -714,11 +713,9 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
{
time_t ts = Anope::string(av[0]).is_pos_number_only() ? convertTo<time_t>(av[0]) : 0;
- user = do_nick("", av[1], av[4], av[2], source, av[7], ts, 0, av[3], "");
+ user = do_nick("", av[1], av[4], av[2], source, av[7], ts, av[6], av[3], "");
if (user)
{
- user->hostip = av[6];
-
UserSetInternalModes(user, 1, &av[5]);
user->SetCloakedHost(av[3]);
@@ -735,7 +732,7 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
}
}
else
- do_nick(source, av[0], "", "", "", "", 0, 0, "", "");
+ do_nick(source, av[0], "", "", "", "", 0, "", "", "");
return MOD_CONT;
}
diff --git a/modules/protocol/inspircd12.cpp b/modules/protocol/inspircd12.cpp
index 8b6c55907..0fec91e25 100644
--- a/modules/protocol/inspircd12.cpp
+++ b/modules/protocol/inspircd12.cpp
@@ -35,7 +35,6 @@ IRCDVar myIrcd[] = {
1, /* vidents */
1, /* svshold */
0, /* time stamp on mode */
- 0, /* NICKIP */
0, /* O:LINE */
1, /* UMODE */
1, /* VHOST ON NICK */
@@ -725,7 +724,7 @@ int anope_event_sethost(const Anope::string &source, int ac, const char **av)
int anope_event_nick(const Anope::string &source, int ac, const char **av)
{
- do_nick(source, av[0], "", "", "", "", 0, 0, "", "");
+ do_nick(source, av[0], "", "", "", "", 0, "", "", "");
return MOD_CONT;
}
@@ -764,7 +763,7 @@ int anope_event_uid(const Anope::string &source, int ac, const char **av)
}
user = NULL;
- user = do_nick("", av[2], av[5], av[3], s->GetName(), av[ac - 1], ts, 0, av[4], av[0]);
+ user = do_nick("", av[2], av[5], av[3], s->GetName(), av[ac - 1], ts, av[6], av[4], av[0]);
if (user)
{
UserSetInternalModes(user, 1, &av[8]);
diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp
index be7b7c760..4445b82b9 100644
--- a/modules/protocol/inspircd20.cpp
+++ b/modules/protocol/inspircd20.cpp
@@ -35,7 +35,6 @@ IRCDVar myIrcd[] = {
1, /* vidents */
1, /* svshold */
0, /* time stamp on mode */
- 0, /* NICKIP */
0, /* O:LINE */
1, /* UMODE */
1, /* VHOST ON NICK */
@@ -722,7 +721,7 @@ int anope_event_sethost(const Anope::string &source, int ac, const char **av)
int anope_event_nick(const Anope::string &source, int ac, const char **av)
{
- do_nick(source, av[0], "", "", "", "", 0, 0, "", "");
+ do_nick(source, av[0], "", "", "", "", 0, "", "", "");
return MOD_CONT;
}
@@ -761,7 +760,7 @@ int anope_event_uid(const Anope::string &source, int ac, const char **av)
}
user = NULL;
- user = do_nick("", av[2], av[5], av[3], s->GetName(), av[ac - 1], ts, 0, av[4], av[0]);
+ user = do_nick("", av[2], av[5], av[3], s->GetName(), av[ac - 1], ts, av[6], av[4], av[0]);
if (user)
{
UserSetInternalModes(user, 1, &av[8]);
diff --git a/modules/protocol/ratbox.cpp b/modules/protocol/ratbox.cpp
index db5c4d5bd..d43a80b52 100644
--- a/modules/protocol/ratbox.cpp
+++ b/modules/protocol/ratbox.cpp
@@ -34,7 +34,6 @@ IRCDVar myIrcd[] = {
0, /* vidents */
0, /* svshold */
0, /* time stamp on mode */
- 0, /* NICKIP */
0, /* UMODE */
0, /* O:LINE */
0, /* VHOST ON NICK */
@@ -405,7 +404,7 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
{
Server *s = Server::Find(source);
/* Source is always the server */
- user = do_nick("", av[0], av[4], av[5], s->GetName(), av[8], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, 0, "*", av[7]);
+ user = do_nick("", av[0], av[4], av[5], s->GetName(), av[8], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, av[6], "*", av[7]);
if (user)
{
UserSetInternalModes(user, 1, &av[3]);
@@ -421,7 +420,7 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
}
}
else if (ac == 2)
- do_nick(source, av[0], "", "", "", "", Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : 0, 0, "", "");
+ do_nick(source, av[0], "", "", "", "", Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : 0, "", "", "");
return MOD_CONT;
}
diff --git a/modules/protocol/unreal32.cpp b/modules/protocol/unreal32.cpp
index 047f51b15..fb12892e2 100644
--- a/modules/protocol/unreal32.cpp
+++ b/modules/protocol/unreal32.cpp
@@ -34,7 +34,6 @@ IRCDVar myIrcd[] = {
1, /* vidents */
1, /* svshold */
1, /* time stamp on mode */
- 1, /* NICKIP */
1, /* O:LINE */
1, /* UMODE */
1, /* VHOST ON NICK */
@@ -133,7 +132,7 @@ class UnrealIRCdProto : public IRCDProto
time_t timeleft = x->Expires - time(NULL);
if (timeleft > 172800)
timeleft = 172800;
- send_cmd("", "BD + G %s %s %s %ld %ld :%s", x->GetUser().c_str(), x->GetHost().c_str(), x->By.c_str(), static_cast<long>(time(NULL) + timeleft), static_cast<long>(x->Expires), x->Reason.c_str());
+ send_cmd("", "BD + G %s %s %s %ld %ld :%s", x->GetUser().c_str(), x->GetHost().c_str(), x->By.c_str(), static_cast<long>(time(NULL) + timeleft), static_cast<long>(x->Created), x->Reason.c_str());
}
void SendSVSKillInternal(const BotInfo *source, const User *user, const Anope::string &buf)
@@ -175,7 +174,7 @@ class UnrealIRCdProto : public IRCDProto
void SendClientIntroduction(const Anope::string &nick, const Anope::string &user, const Anope::string &host, const Anope::string &real, const Anope::string &modes, const Anope::string &)
{
EnforceQlinedNick(nick, Config->ServerName);
- send_cmd("", "& %s 1 %ld %s %s %s 0 %s %s%s :%s", nick.c_str(), static_cast<long>(time(NULL)), user.c_str(), host.c_str(), Config->ServerName.c_str(), modes.c_str(), host.c_str(), myIrcd->nickip ? " *" : "", real.c_str());
+ send_cmd("", "& %s 1 %ld %s %s %s 0 %s %s * :%s", nick.c_str(), static_cast<long>(time(NULL)), user.c_str(), host.c_str(), Config->ServerName.c_str(), modes.c_str(), host.c_str(), real.c_str());
}
void SendKickInternal(const BotInfo *source, const Channel *chan, const User *user, const Anope::string &buf)
@@ -860,11 +859,17 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
<codemastr> it's sent when a nick collision occurs
- so we have to leave it around for now -TSL
*/
- do_nick(source, av[0], av[3], av[4], av[5], av[6], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, 0, "*", "");
+ do_nick(source, av[0], av[3], av[4], av[5], av[6], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, "", "*", "");
}
else if (ac == 11)
{
- user = do_nick(source, av[0], av[3], av[4], av[5], av[10], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, ntohl(decode_ip(av[9])), av[8], "");
+ Anope::string decoded_ip;
+ b64_decode(av[9], decoded_ip);
+
+ sockaddrs ip;
+ ip.ntop(strlen(av[9]) == 8 ? AF_INET : AF_INET6, decoded_ip.c_str());
+
+ user = do_nick(source, av[0], av[3], av[4], av[5], av[10], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, ip.addr(), av[8], "");
if (user)
{
UserSetInternalModes(user, 1, &av[7]);
@@ -883,7 +888,7 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
else
{
/* NON NICKIP */
- user = do_nick(source, av[0], av[3], av[4], av[5], av[9], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, 0, av[8], "");
+ user = do_nick(source, av[0], av[3], av[4], av[5], av[9], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0, "", av[8], "");
if (user)
{
UserSetInternalModes(user, 1, &av[7]);
@@ -901,7 +906,7 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
}
}
else
- do_nick(source, av[0], "", "", "", "", Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : 0, 0, "", "");
+ do_nick(source, av[0], "", "", "", "", Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : 0, "", "", "");
return MOD_CONT;
}
@@ -1136,7 +1141,7 @@ void moduleAddIRCDMsgs()
Anope::AddMessage("PRIVMSG", anope_event_privmsg);
Anope::AddMessage("!", anope_event_privmsg);
Anope::AddMessage("QUIT", anope_event_quit);
- Anope::AddMessage("),", anope_event_quit);
+ Anope::AddMessage(",", anope_event_quit);
Anope::AddMessage("SERVER", anope_event_server);
Anope::AddMessage("'", anope_event_server);
Anope::AddMessage("SQUIT", anope_event_squit);
diff --git a/modules/socketengines/m_socketengine_epoll.cpp b/modules/socketengines/m_socketengine_epoll.cpp
index 5a2561b25..5edc40502 100644
--- a/modules/socketengines/m_socketengine_epoll.cpp
+++ b/modules/socketengines/m_socketengine_epoll.cpp
@@ -80,8 +80,11 @@ class SocketEngineEPoll : public SocketEngineBase
--SocketCount;
}
- void MarkWriteable(Socket *s)
+ void MarkWritable(Socket *s)
{
+ if (s->HasFlag(SF_WRITABLE))
+ return;
+
epoll_event ev;
memset(&ev, 0, sizeof(ev));
@@ -91,10 +94,15 @@ class SocketEngineEPoll : public SocketEngineBase
if (epoll_ctl(EngineHandle, EPOLL_CTL_MOD, ev.data.fd, &ev) == -1)
Log() << "Unable to mark fd " << ev.data.fd << " as writable in socketengine epoll: " << strerror(errno);
+ else
+ s->SetFlag(SF_WRITABLE);
}
- void ClearWriteable(Socket *s)
+ void ClearWriteble(Socket *s)
{
+ if (!s->HasFlag(SF_WRITABLE))
+ return;
+
epoll_event ev;
memset(&ev, 0, sizeof(ev));
@@ -104,6 +112,8 @@ class SocketEngineEPoll : public SocketEngineBase
if (epoll_ctl(EngineHandle, EPOLL_CTL_MOD, ev.data.fd, &ev) == -1)
Log() << "Unable to mark fd " << ev.data.fd << " as unwritable in socketengine epoll: " << strerror(errno);
+ else
+ s->UnsetFlag(SF_WRITABLE);
}
void Process()
@@ -150,7 +160,7 @@ class SocketEngineEPoll : public SocketEngineBase
class ModuleSocketEngineEPoll : public Module
{
- SocketEngineEPoll *engine;
+ SocketEngineEPoll engine;
public:
ModuleSocketEngineEPoll(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator)
@@ -159,13 +169,11 @@ class ModuleSocketEngineEPoll : public Module
this->SetPermanent(true);
this->SetType(SOCKETENGINE);
- engine = new SocketEngineEPoll();
- SocketEngine = engine;
+ SocketEngine = &engine;
}
~ModuleSocketEngineEPoll()
{
- delete engine;
SocketEngine = NULL;
}
};
diff --git a/modules/socketengines/m_socketengine_select.cpp b/modules/socketengines/m_socketengine_select.cpp
index e708693d2..b966820bd 100644
--- a/modules/socketengines/m_socketengine_select.cpp
+++ b/modules/socketengines/m_socketengine_select.cpp
@@ -41,14 +41,20 @@ class SocketEngineSelect : public SocketEngineBase
Sockets.erase(s->GetSock());
}
- void MarkWriteable(Socket *s)
+ void MarkWritable(Socket *s)
{
+ if (s->HasFlag(SF_WRITABLE))
+ return;
FD_SET(s->GetSock(), &WriteFDs);
+ s->SetFlag(SF_WRITABLE);
}
- void ClearWriteable(Socket *s)
+ void ClearWritable(Socket *s)
{
+ if (!s->HasFlag(SF_WRITABLE))
+ return;
FD_CLR(s->GetSock(), &WriteFDs);
+ s->UnsetFlag(SF_WRITABLE);
}
void Process()
@@ -101,7 +107,7 @@ class SocketEngineSelect : public SocketEngineBase
class ModuleSocketEngineSelect : public Module
{
- SocketEngineSelect *engine;
+ SocketEngineSelect engine;
public:
ModuleSocketEngineSelect(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator)
@@ -110,13 +116,11 @@ class ModuleSocketEngineSelect : public Module
this->SetPermanent(true);
this->SetType(SOCKETENGINE);
- engine = new SocketEngineSelect();
- SocketEngine = engine;
+ SocketEngine = &engine;
}
~ModuleSocketEngineSelect()
{
- delete engine;
SocketEngine = NULL;
}
};
diff --git a/src/actions.cpp b/src/actions.cpp
index bdc5a041d..92ecca132 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -73,8 +73,7 @@ void kill_user(const Anope::string &source, const Anope::string &user, const Ano
*/
void common_unban(ChannelInfo *ci, const Anope::string &nick)
{
- Anope::string host;
- uint32 ip = 0;
+ //uint32 ip = 0;
User *u;
Entry *ban, *next;
@@ -87,27 +86,13 @@ void common_unban(ChannelInfo *ci, const Anope::string &nick)
if (!ci->c->bans || !ci->c->bans->count)
return;
- if (u->hostip.empty())
- {
- host = host_resolve(u->host);
- /* we store the just resolved hostname so we don't
- * need to do this again */
- if (!host.empty())
- u->hostip = host;
- }
- else
- host = u->hostip;
- /* Convert the host to an IP.. */
- if (!host.empty())
- ip = str_is_ip(host);
-
if (ircd->svsmode_unban)
ircdproto->SendBanDel(ci->c, nick);
else
for (ban = ci->c->bans->entries; ban; ban = next)
{
next = ban->next;
- if (entry_match(ban, u->nick, u->GetIdent(), u->host, ip) || entry_match(ban, u->nick, u->GetIdent(), u->GetDisplayedHost(), ip))
+ if (entry_match(ban, u->nick, u->GetIdent(), u->host, /*ip XXX */ 0) || entry_match(ban, u->nick, u->GetIdent(), u->GetDisplayedHost(), /*ip XXX */0))
ci->c->RemoveMode(NULL, CMODE_BAN, ban->mask);
}
}
diff --git a/src/base64.cpp b/src/base64.cpp
index 4f51eb5e8..cddfb273f 100644
--- a/src/base64.cpp
+++ b/src/base64.cpp
@@ -161,17 +161,3 @@ void b64_decode(const Anope::string &src, Anope::string &target)
target.erase(target.length() - 1);
}
-int decode_ip(const Anope::string &buf)
-{
- int len = buf.length();
- Anope::string targ;
-
- b64_decode(buf, targ);
- const struct in_addr ia = *reinterpret_cast<const struct in_addr *>(targ.c_str());
- if (len == 24) /* IPv6 */
- return 0;
- else if (len == 8) /* IPv4 */
- return ia.s_addr;
- else /* Error?? */
- return 0;
-}
diff --git a/src/channels.cpp b/src/channels.cpp
index 389577f71..882dc887a 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -1765,33 +1765,17 @@ Entry *elist_match_mask(EList *list, const Anope::string &mask, uint32 ip)
Entry *elist_match_user(EList *list, User *u)
{
Entry *res;
- Anope::string host;
- uint32 ip = 0;
+ //uint32 ip = 0;
if (!list || !list->entries || !u)
return NULL;
- if (u->hostip.empty())
- {
- host = host_resolve(u->host);
- /* we store the just resolved hostname so we don't
- * need to do this again */
- if (!host.empty())
- u->hostip = host;
- }
- else
- host = u->hostip;
-
- /* Convert the host to an IP.. */
- if (!host.empty())
- ip = str_is_ip(host);
-
/* Match what we ve got against the lists.. */
- res = elist_match(list, u->nick, u->GetIdent(), u->host, ip);
+ res = elist_match(list, u->nick, u->GetIdent(), u->host, /*ip XXX*/0);
if (!res)
- res = elist_match(list, u->nick, u->GetIdent(), u->GetDisplayedHost(), ip);
+ res = elist_match(list, u->nick, u->GetIdent(), u->GetDisplayedHost(), /*ip XXX*/0);
if (!res && !u->GetCloakedHost().empty() && !u->GetCloakedHost().equals_cs(u->GetDisplayedHost()))
- res = elist_match(list, u->nick, u->GetIdent(), u->GetCloakedHost(), ip);
+ res = elist_match(list, u->nick, u->GetIdent(), u->GetCloakedHost(), /*ip XXX*/ 0);
return res;
}
diff --git a/src/config.cpp b/src/config.cpp
index d43f97e6f..d8ac4f863 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -349,6 +349,36 @@ ServerConfig::ServerConfig() : errstr(""), config_data()
}
SetDefaultMLock(this);
+
+ if (IsFile(this->NameServer))
+ {
+ std::ifstream f(this->NameServer.c_str());
+ Anope::string server;
+ bool success = false;
+
+ while (f.is_open() && getline(f, server.str()))
+ {
+ if (server.find("nameserver ") == 0 && getline(f, server.str()))
+ {
+ if (server.substr(11).is_pos_number_only())
+ {
+ this->NameServer = server.substr(11);
+ Log(LOG_DEBUG) << "Nameserver set to " << this->NameServer;
+ success = true;
+ break;
+ }
+ }
+ }
+
+ if (f.is_open())
+ f.close();
+
+ if (!success)
+ {
+ Log() << "Unable to find nameserver, defaulting to 127.0.0.1";
+ this->NameServer = "127.0.0.1";
+ }
+ }
}
bool ServerConfig::CheckOnce(const Anope::string &tag)
@@ -1053,6 +1083,8 @@ void ServerConfig::Read()
{"mail", "restrict", "no", new ValueContainerBool(&this->RestrictMail), DT_BOOLEAN, NoValidation},
{"mail", "delay", "0", new ValueContainerTime(&this->MailDelay), DT_TIME, NoValidation},
{"mail", "dontquoteaddresses", "no", new ValueContainerBool(&this->DontQuoteAddresses), DT_BOOLEAN, NoValidation},
+ {"dns", "nameserver", "127.0.0.1", new ValueContainerString(&this->NameServer), DT_STRING, NoValidation},
+ {"dns", "timeout", "5", new ValueContainerTime(&this->DNSTimeout), DT_TIME, NoValidation},
{"chanserv", "nick", "ChanServ", new ValueContainerString(&this->s_ChanServ), DT_STRING | DT_NORELOAD, ValidateNotEmpty},
{"chanserv", "description", "Channel Registration Service", new ValueContainerString(&this->desc_ChanServ), DT_STRING | DT_NORELOAD, ValidateNotEmpty},
{"chanserv", "modules", "", new ValueContainerString(&ChanCoreModules), DT_STRING, NoValidation},
diff --git a/src/dns.cpp b/src/dns.cpp
new file mode 100644
index 000000000..51cd14938
--- /dev/null
+++ b/src/dns.cpp
@@ -0,0 +1,550 @@
+#include "services.h"
+
+DNSManager *DNSEngine;
+
+static inline unsigned short GetRandomID()
+{
+ return random();
+}
+
+DNSRequest::DNSRequest(const Anope::string &addr, QueryType qt, bool cache) : address(addr), QT(qt)
+{
+ if (!DNSEngine)
+ DNSEngine = new DNSManager();
+ if (DNSEngine->packets.size() == 65535)
+ throw SocketException("DNS queue full");
+
+ Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << addr << ", of type " << qt;
+
+ if (cache && DNSEngine->CheckCache(this))
+ {
+ delete this;
+ return;
+ }
+
+ DNSPacket *p = new DNSPacket();
+
+ while (DNSEngine->requests.count((p->id = GetRandomID())));
+
+ DNSEngine->requests[p->id] = this;
+ DNSEngine->packets.push_back(p);
+
+ p->flags = DNS_QUERYFLAGS_RD;
+ if (!p->AddQuestion(addr, qt))
+ {
+ delete this;
+ return;
+ }
+
+ SocketEngine->MarkWritable(DNSEngine->sock);
+
+ this->timeout = new DNSRequestTimeout(this, Config->DNSTimeout);
+}
+
+DNSRequest::~DNSRequest()
+{
+ if (!this->timeout->done)
+ {
+ delete this->timeout;
+ }
+}
+
+void DNSRequest::OnError(DNSError error, const Anope::string &message)
+{
+}
+
+inline DNSPacket::DNSPacket()
+{
+ this->id = this->flags = this->qdcount = this->ancount = this->nscount = this->arcount = this->payload_count = 0;
+ memset(&this->payload, 0, sizeof(this->payload));
+}
+
+bool DNSPacket::AddQuestion(const Anope::string &name, const QueryType qt)
+{
+ unsigned char temp_buffer[512] = "";
+ unsigned short buffer_pos = 0;
+
+ Anope::string working_name = name;
+
+ switch (qt)
+ {
+ case DNS_QUERY_PTR:
+ {
+ if (working_name.find(':') != Anope::string::npos)
+ {
+ in6_addr ip;
+ if (!inet_pton(AF_INET6, working_name.c_str(), &ip))
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received an invalid IP for PTR lookup (" << working_name << "): " << strerror(errno);
+ return false;
+ }
+
+ static const char *const hex = "0123456789abcdef";
+ char reverse_ip[128];
+ unsigned reverse_ip_count = 0;
+ for (int i = 15; i >= 0; --i)
+ {
+ reverse_ip[reverse_ip_count++] = hex[ip.s6_addr[i] & 0xF];
+ reverse_ip[reverse_ip_count++] = '.';
+ reverse_ip[reverse_ip_count++] = hex[ip.s6_addr[i] >> 4];
+ reverse_ip[reverse_ip_count++] = '.';
+ }
+ reverse_ip[reverse_ip_count++] = 0;
+
+ working_name = reverse_ip;
+ working_name += "ip6.arpa";
+ Log(LOG_DEBUG_2) << "IP changed to in6.arpa format: " << working_name;
+ }
+ else
+ {
+ in_addr ip;
+ if (!inet_pton(AF_INET, working_name.c_str(), &ip))
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received an invalid IP for PTR lookup (" << working_name << "): " << strerror(errno);
+ return false;
+ }
+ unsigned long reverse_ip = ((ip.s_addr & 0xFF) << 24) | ((ip.s_addr & 0xFF00) << 8) | ((ip.s_addr & 0xFF0000) >> 8) | ((ip.s_addr & 0xFF000000) >> 24);
+ char ipbuf[INET_ADDRSTRLEN];
+ if (!inet_ntop(AF_INET, &reverse_ip, ipbuf, sizeof(ipbuf)))
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Reformatted IP " << working_name << " back into an invalid IP: " << strerror(errno);
+ return false;
+ }
+
+ working_name = ipbuf;
+ working_name += ".in-addr.arpa";
+ Log(LOG_DEBUG_2) << "IP changed to in-addr.arpa format: " << working_name;
+ }
+ }
+ case DNS_QUERY_CNAME:
+ case DNS_QUERY_A:
+ case DNS_QUERY_AAAA:
+ {
+ sepstream sep(working_name, '.');
+ Anope::string token;
+ while (sep.GetToken(token))
+ {
+ temp_buffer[buffer_pos++] = token.length();
+ memcpy(&temp_buffer[buffer_pos], token.c_str(), token.length());
+ buffer_pos += token.length();
+ }
+ break;
+ }
+ default:
+ Log(LOG_DEBUG_2) << "Resolver: Received an unknown query type format " << qt;
+ return false;
+ }
+
+ temp_buffer[buffer_pos++] = 0;
+
+ short i = htons(qt);
+ memcpy(&temp_buffer[buffer_pos], &i, 2);
+ buffer_pos += 2;
+
+ i = htons(1);
+ memcpy(&temp_buffer[buffer_pos], &i, 2);
+ buffer_pos += 2;
+
+ Log(LOG_DEBUG_3) << "Resolver: Packet payload to: " << temp_buffer;
+ Log(LOG_DEBUG_3) << "Resolver: Bytes used: " << buffer_pos << ", payload count " << this->payload_count;
+
+ if (buffer_pos > (sizeof(this->payload) - this->payload_count))
+ return false;
+
+ memmove(this->payload + this->payload_count, temp_buffer, buffer_pos);
+ this->payload_count += buffer_pos;
+
+ this->qdcount++;
+
+ return true;
+}
+
+inline void DNSPacket::FillPacket(const unsigned char *input, const size_t length)
+{
+ this->id = (input[0] << 8) | input[1];
+ this->flags = (input[2] << 8) | input[3];
+ this->qdcount = (input[4] << 8) | input[5];
+ this->ancount = (input[6] << 8) | input[7];
+ this->nscount = (input[8] << 8) | input[9];
+ this->arcount = (input[10] << 8) | input[11];
+ memcpy(this->payload, &input[12], length);
+ this->payload_count = length;
+}
+
+inline void DNSPacket::FillBuffer(unsigned char *buffer)
+{
+ buffer[0] = this->id >> 8;
+ buffer[1] = this->id & 0xFF;
+ buffer[2] = this->flags >> 8;
+ buffer[3] = this->flags & 0xFF;
+ buffer[4] = this->qdcount >> 8;
+ buffer[5] = this->qdcount & 0xFF;
+ buffer[6] = this->ancount >> 8;
+ buffer[7] = this->ancount & 0xFF;
+ buffer[8] = this->nscount >> 8;
+ buffer[9] = this->nscount & 0xFF;
+ buffer[10] = this->arcount >> 8;
+ buffer[11] = this->arcount & 0xFF;
+ memcpy(&buffer[12], this->payload, this->payload_count);
+}
+
+inline DNSRecord::DNSRecord()
+{
+ this->type = DNS_QUERY_NONE;
+ this->record_class = this->ttl = this->rdlength = 0;
+ this->created = time(NULL);
+}
+
+DNSSocket::DNSSocket(const Anope::string &nTargetHost, int nPort) : ClientSocket(nTargetHost, nPort, "", false, SOCK_DGRAM)
+{
+ this->server_addr.pton(AF_INET, TargetHost, Port);
+}
+
+DNSSocket::~DNSSocket()
+{
+ Log() << "Resolver: Lost connection to nameserver";
+ DNSEngine->sock = NULL;
+}
+
+int DNSSocket::SendTo(const unsigned char *buf, size_t len) const
+{
+ return sendto(this->GetSock(), buf, len, 0, &this->server_addr.sa, this->server_addr.size());
+}
+
+int DNSSocket::RecvFrom(char *buf, size_t len, sockaddrs &addrs) const
+{
+ socklen_t x = sizeof(addrs);
+ return recvfrom(this->GetSock(), buf, len, 0, &addrs.sa, &x);
+}
+
+bool DNSSocket::ProcessRead()
+{
+ Log(LOG_DEBUG_2) << "Resolver: Reading from UDP socket";
+
+ sockaddrs from_server;
+ unsigned char packet_buffer[524];
+ int length = this->RecvFrom(reinterpret_cast<char *>(&packet_buffer), sizeof(packet_buffer), from_server);
+
+ if (length < 0)
+ return false;
+
+ if (this->server_addr != from_server)
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->server_addr.addr() << "' != '" << from_server.addr() << "'";
+ return true;
+ }
+
+ if (length < 12)
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received a corrupted packet";
+ return true;
+ }
+
+ /* Remove header length */
+ length -= 12;
+
+ DNSPacket recv_packet;
+ recv_packet.FillPacket(packet_buffer, length);
+
+ std::map<short, DNSRequest *>::iterator it = DNSEngine->requests.find(recv_packet.id);
+ if (it == DNSEngine->requests.end())
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received an answer for something we didn't request";
+ return true;
+ }
+ DNSRequest *request = it->second;
+ DNSEngine->requests.erase(it);
+
+ if (!(recv_packet.flags & DNS_QUERYFLAGS_QR))
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received a non-answer";
+ request->OnError(DNS_ERROR_NOT_AN_ANSWER, "Received a non-answer");
+ }
+ else if (recv_packet.flags & DNS_QUERYFLAGS_OPCODE)
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received a nonstandard query";
+ request->OnError(DNS_ERROR_NONSTANDARD_QUERY, "Received a nonstandard query");
+ }
+ else if (recv_packet.flags & DNS_QUERYFLAGS_RCODE)
+ {
+ switch (recv_packet.flags & DNS_QUERYFLAGS_RCODE)
+ {
+ case 1:
+ Log(LOG_DEBUG_2) << "Resolver: Format error";
+ request->OnError(DNS_ERROR_FORMAT_ERROR, "Format error");
+ break;
+ case 2:
+ Log(LOG_DEBUG_2) << "Resolver: Server failure";
+ request->OnError(DNS_ERROR_SERVER_FAILURE, "Server failure");
+ break;
+ case 3:
+ Log(LOG_DEBUG_2) << "Resolver: Domain name not found";
+ request->OnError(DNS_ERROR_DOMAIN_NOT_FOUND, "Domain not found");
+ break;
+ case 4:
+ Log(LOG_DEBUG_2) << "Resolver: Not Implemented - The name server does not support the requested kind of query.";
+ request->OnError(DNS_ERROR_NOT_IMPLEMENTED, "Not Implemented - The name server does not support the requested kind of query.");
+ break;
+ case 5:
+ Log(LOG_DEBUG_2) << "Resolver: Server refused to perform the specificed operation";
+ request->OnError(DNS_ERROR_REFUSED, "Server refused to perform the specified operation");
+ break;
+ default:
+ Log(LOG_DEBUG_2) << "Resolver: Unknown error";
+ request->OnError(DNS_ERROR_UNKNOWN, "Unknown error");
+ }
+ }
+ else if (recv_packet.ancount < 1)
+ {
+ Log(LOG_DEBUG_2) << "Resolver: No resource records returned";
+ request->OnError(DNS_ERROR_NO_RECORDS, "No resource records returned");
+ }
+ else
+ {
+ unsigned packet_pos = 0;
+
+ /* Skip over the questions in this reponse */
+ for (unsigned qdcount = 0; qdcount < recv_packet.qdcount; ++qdcount)
+ {
+ for (unsigned offset = recv_packet.payload[packet_pos]; offset; packet_pos += offset + 1, offset = recv_packet.payload[packet_pos])
+ {
+ if (offset & 0xC0)
+ {
+ packet_pos += 2;
+ offset = 0;
+ }
+ }
+
+ packet_pos += 5;
+ }
+
+ for (unsigned ancount = 0; ancount < recv_packet.ancount; ++ancount)
+ {
+ Anope::string name;
+ unsigned packet_pos_ptr = packet_pos;
+ for (unsigned offset = recv_packet.payload[packet_pos_ptr]; offset; packet_pos_ptr += offset + 1, offset = recv_packet.payload[packet_pos_ptr])
+ {
+ if (offset & 0xC0)
+ {
+ offset = (offset & 0x3F) << 8 | recv_packet.payload[++packet_pos_ptr];
+ packet_pos_ptr = offset - 12;
+ offset = recv_packet.payload[packet_pos_ptr];
+ }
+ for (unsigned i = 1; i <= offset; ++i)
+ name += recv_packet.payload[packet_pos_ptr + i];
+ name += ".";
+ }
+ name.erase(name.begin() + name.length() - 1);
+
+ if (packet_pos_ptr < packet_pos)
+ packet_pos += 2;
+ else
+ packet_pos = packet_pos_ptr + 1;
+
+ DNSRecord *rr = new DNSRecord;
+ rr->name = name;
+
+ Log(LOG_DEBUG_2) << "Resolver: Received answer for " << name;
+
+ rr->type = static_cast<QueryType>(recv_packet.payload[packet_pos] << 8 | (recv_packet.payload[packet_pos + 1] & 0xFF));
+ packet_pos += 2;
+
+ rr->record_class = recv_packet.payload[packet_pos] << 8 | (recv_packet.payload[packet_pos + 1] & 0xFF);
+ packet_pos += 2;
+
+ rr->ttl = (recv_packet.payload[packet_pos] << 24) | (recv_packet.payload[packet_pos + 1] << 16) | (recv_packet.payload[packet_pos + 2] << 8) | recv_packet.payload[packet_pos + 3];
+ packet_pos += 4;
+
+ rr->rdlength = (recv_packet.payload[packet_pos] << 8 | recv_packet.payload[packet_pos + 1]);
+ packet_pos += 2;
+
+ switch (rr->type)
+ {
+ case DNS_QUERY_A:
+ {
+ unsigned long ip = (recv_packet.payload[packet_pos]) | (recv_packet.payload[packet_pos + 1]) << 8 | (recv_packet.payload[packet_pos + 2] << 16) | (recv_packet.payload[packet_pos + 3] << 24);
+ packet_pos += 4;
+
+ char ipbuf[INET_ADDRSTRLEN];
+ if (!inet_ntop(AF_INET, &ip, ipbuf, sizeof(ipbuf)))
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received an invalid IP for DNS_QUERY_A: " << strerror(errno);
+ request->OnError(DNS_ERROR_FORMAT_ERROR, "Received an invalid IP from the nameserver: " + stringify(strerror(errno)));
+ delete rr;
+ rr = NULL;
+ }
+ else
+ rr->result = ipbuf;
+ break;
+ }
+ case DNS_QUERY_AAAA:
+ {
+ unsigned char ip[16];
+ for (int i = 0; i < 16; ++i)
+ ip[i] = recv_packet.payload[packet_pos + i];
+ packet_pos += 16;
+
+ char ipbuf[INET6_ADDRSTRLEN];
+ if (!inet_ntop(AF_INET6, &ip, ipbuf, sizeof(ipbuf)))
+ {
+ Log(LOG_DEBUG_2) << "Resolver: Received an invalid IP for DNS_QUERY_A: " << strerror(errno);
+ request->OnError(DNS_ERROR_FORMAT_ERROR, "Received an invalid IP from the nameserver: " + stringify(strerror(errno)));
+ delete rr;
+ rr = NULL;
+ }
+ else
+ rr->result = ipbuf;
+ break;
+ }
+ case DNS_QUERY_CNAME:
+ case DNS_QUERY_PTR:
+ {
+ name.clear();
+ packet_pos_ptr = packet_pos;
+ for (unsigned offset = recv_packet.payload[packet_pos_ptr]; offset; packet_pos_ptr += offset + 1, offset = recv_packet.payload[packet_pos_ptr])
+ {
+ if (offset & 0xC0)
+ {
+ offset = (offset & 0x3F) << 8 | recv_packet.payload[++packet_pos_ptr];
+ packet_pos_ptr = offset - 12;
+ offset = recv_packet.payload[packet_pos_ptr];
+ }
+ for (unsigned i = 1; i <= offset; ++i)
+ name += recv_packet.payload[packet_pos_ptr + i];
+ name += ".";
+ }
+ name.erase(name.begin() + name.length() - 1);
+
+ if (packet_pos_ptr < packet_pos)
+ packet_pos += 2;
+ else
+ packet_pos = packet_pos_ptr + 1;
+
+ rr->result = name;
+ break;
+ }
+ default:
+ delete rr;
+ request->OnError(DNS_ERROR_INVALID_TYPE, "Invalid query type");
+ rr = NULL;
+ }
+
+ if (rr && request->QT != rr->type)
+ {
+ delete rr;
+ rr = NULL;
+ }
+
+ if (rr)
+ {
+ request->OnLookupComplete(rr);
+ DNSEngine->AddCache(rr);
+ }
+ }
+ }
+
+ delete request;
+ return true;
+}
+
+bool DNSSocket::ProcessWrite()
+{
+ Log(LOG_DEBUG_2) << "Resolver: Writing to UDP socket";
+
+ bool cont = true;
+ for (unsigned i = DNSEngine->packets.size(); i > 0; --i)
+ {
+ DNSPacket *r = DNSEngine->packets[i - 1];
+
+ unsigned char buffer[524];
+ r->FillBuffer(buffer);
+
+ cont = this->SendTo(buffer, r->payload_count + 12) >= 0;
+
+ if (!cont)
+ break;
+
+ delete r;
+ DNSEngine->packets.erase(DNSEngine->packets.begin() + i - 1);
+ }
+ SocketEngine->ClearWritable(this);
+ return cont;
+}
+
+DNSManager::DNSManager() : Timer(3600, time(NULL), true)
+{
+ this->sock = NULL;
+
+ try
+ {
+ this->sock = new DNSSocket(Config->NameServer, DNSManager::DNSPort);
+ }
+ catch (const SocketException &ex)
+ {
+ throw SocketException("Unable to connect to nameserver: " + ex.GetReason());
+ }
+}
+
+DNSManager::~DNSManager()
+{
+ delete this->sock;
+}
+
+void DNSManager::AddCache(DNSRecord *rr)
+{
+ this->cache.insert(std::make_pair(rr->name, rr));
+}
+
+bool DNSManager::CheckCache(DNSRequest *request)
+{
+ std::multimap<Anope::string, DNSRecord *>::iterator it = this->cache.find(request->address);
+ if (it != this->cache.end())
+ {
+ std::multimap<Anope::string, DNSRecord *>::iterator it_end = this->cache.upper_bound(request->address);
+
+ time_t now = time(NULL);
+ for (; it != it_end; ++it)
+ {
+ DNSRecord *rec = it->second;
+ if (rec->created + rec->ttl >= now)
+ {
+ request->OnLookupComplete(rec);
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void DNSManager::Tick(time_t now)
+{
+ for (std::multimap<Anope::string, DNSRecord *>::iterator it = this->cache.begin(), it_end = this->cache.end(); it != it_end; ++it)
+ {
+ DNSRecord *req = it->second;
+
+ if (req->created + req->ttl < now)
+ {
+ delete req;
+ this->cache.erase(it);
+ }
+ }
+}
+
+DNSRequestTimeout::DNSRequestTimeout(DNSRequest *r, time_t timeout) : Timer(timeout), request(r)
+{
+ this->done = false;
+}
+
+DNSRequestTimeout::~DNSRequestTimeout()
+{
+}
+
+void DNSRequestTimeout::Tick(time_t)
+{
+ this->done = true;
+ this->request->OnError(DNS_ERROR_TIMEOUT, "Request timed out");
+ delete this->request;
+}
+
diff --git a/src/init.cpp b/src/init.cpp
index aae8e9eb2..c91cc3b31 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -373,6 +373,15 @@ void Init(int ac, char **av)
if (ModuleManager::LoadModule(Config->SocketEngine, NULL))
throw FatalException("Unable to load socket engine " + Config->SocketEngine);
+ try
+ {
+ DNSEngine = new DNSManager();
+ }
+ catch (const SocketException &ex)
+ {
+ throw FatalException(ex.GetReason());
+ }
+
/* Add Core MSG handles */
moduleAddMsgs();
diff --git a/src/logger.cpp b/src/logger.cpp
index a5637d4d8..673f7f9cb 100644
--- a/src/logger.cpp
+++ b/src/logger.cpp
@@ -290,7 +290,7 @@ bool LogInfo::HasType(LogType type)
case LOG_RAWIO:
return this->RawIO;
case LOG_DEBUG:
- return this->Debug;
+ return debug ? true : this->Debug;
// LOG_DEBUG_[234]
default:
break;
diff --git a/src/main.cpp b/src/main.cpp
index 04baf1dd3..d325cdd06 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -243,10 +243,6 @@ static void services_shutdown()
void sighandler(int signum)
{
- /* We set the quit message to something default, just to be sure it is
- * always set when we need it. It seems some signals slip through to the
- * QUIT code without having a valid quitmsg. -GD
- */
if (quitmsg.empty())
quitmsg = Anope::string("Services terminating via signal ") + strsignal(signum) + " (" + stringify(signum) + ")";
bool fatal = false;
@@ -286,7 +282,6 @@ void sighandler(int signum)
expire_all();
save_databases();
- quitmsg = "shutting down on sigterm";
default:
fatal = true;
break;
diff --git a/src/misc.cpp b/src/misc.cpp
index 66beff127..05240b77e 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -815,32 +815,6 @@ int myNumToken(const Anope::string &str, char dilim)
/*************************************************************************/
-/**
- * Resolve a host to an IP
- * @param host to convert
- * @return ip address
- */
-Anope::string host_resolve(const Anope::string &host)
-{
- struct hostent *hentp = gethostbyname(host.c_str());
- Anope::string ipreturn;
-
- if (hentp)
- {
- uint32 ip;
- memcpy(&ip, hentp->h_addr, sizeof(hentp->h_length));
- struct in_addr addr;
- addr.s_addr = ip;
- char ipbuf[16];
- ntoa(addr, ipbuf, sizeof(ipbuf));
- ipreturn = ipbuf;
- Log(LOG_DEBUG) << "resolved " << host << " to " << ipbuf;
- }
- return ipreturn;
-}
-
-/*************************************************************************/
-
/** Build a string list from a source string
* @param src The source string
* @return a list of strings
@@ -1199,43 +1173,6 @@ bool str_is_pure_wildcard(const Anope::string &str)
/*************************************************************************/
/**
- * Check if the given string is an IP, and return the IP.
- * @param str String to check
- * @return The IP, if one found. 0 if none.
- */
-uint32 str_is_ip(const Anope::string &str)
-{
- int octets[4] = { -1, -1, -1, -1 };
- std::vector<Anope::string> octets_str = BuildStringVector(str, '.');
-
- if (octets_str.size() != 4)
- return false;
-
- for (unsigned i = 0; i < 4; ++i)
- {
- Anope::string octet = octets_str[i];
-
- if (!octet.is_number_only())
- return 0;
-
- octets[i] = convertTo<int>(octet);
- /* Bail out if the octet is invalid or wrongly terminated */
- if (octets[i] < 0 || octets[i] > 255)
- return 0;
- }
-
- /* Fill the IP - the dirty way */
- uint32 ip = octets[3];
- ip += octets[2] * 256;
- ip += octets[1] * 65536;
- ip += octets[0] * 16777216;
-
- return ip;
-}
-
-/*************************************************************************/
-
-/**
* Check if the given string is an IP or CIDR mask, and fill the given
* ip/cidr params if so.
* @param str String to check
diff --git a/src/operserv.cpp b/src/operserv.cpp
index bbc38eb1a..1a6f20eb5 100644
--- a/src/operserv.cpp
+++ b/src/operserv.cpp
@@ -239,7 +239,7 @@ std::pair<XLineManager *, XLine *> XLineManager::CheckAll(User *u)
if (x)
{
ret.first = xlm;
- ret.second = x;;
+ ret.second = x;
break;
}
}
@@ -425,7 +425,7 @@ XLine *XLineManager::Check(User *u)
if (!x->GetUser().empty() && !Anope::Match(u->GetIdent(), x->GetUser()))
continue;
- if (x->GetHost().empty() || (!u->hostip.empty() && Anope::Match(u->hostip, x->GetHost())) || Anope::Match(u->host, x->GetHost()) || (!u->chost.empty() && Anope::Match(u->chost, x->GetHost())) || (!u->vhost.empty() && Anope::Match(u->vhost, x->GetHost())))
+ if (x->GetHost().empty() || (u->ip() && Anope::Match(u->ip.addr(), x->GetHost())) || Anope::Match(u->host, x->GetHost()) || (!u->chost.empty() && Anope::Match(u->chost, x->GetHost())) || (!u->vhost.empty() && Anope::Match(u->vhost, x->GetHost())))
{
OnMatch(u, x);
return x;
@@ -486,14 +486,14 @@ XLine *SGLineManager::Add(BotInfo *bi, User *u, const Anope::string &mask, time_
notice_lang(bi->nick, u, OPER_AKILL_ALREADY_COVERED, mask.c_str(), canAdd.second->Mask.c_str());
}
- return canAdd.second;
+ return NULL;
}
Anope::string realreason = reason;
if (u && Config->AddAkiller)
realreason = "[" + u->nick + "]" + reason;
- XLine *x = new XLine(mask, u ? u->nick : "", expires, realreason);
+ XLine *x = new XLine(mask, u ? u->nick : OperServ->nick, expires, realreason);
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnAddAkill, OnAddAkill(u, x));
@@ -549,10 +549,10 @@ XLine *SNLineManager::Add(BotInfo *bi, User *u, const Anope::string &mask, time_
notice_lang(bi->nick, u, OPER_SNLINE_ALREADY_COVERED, mask.c_str(), canAdd.second->Mask.c_str());
}
- return canAdd.second;
+ return NULL;
}
- XLine *x = new XLine(mask, u ? u->nick : "", expires, reason);
+ XLine *x = new XLine(mask, u ? u->nick : OperServ->nick, expires, reason);
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnAddXLine, OnAddXLine(u, x, X_SNLINE));
@@ -629,10 +629,10 @@ XLine *SQLineManager::Add(BotInfo *bi, User *u, const Anope::string &mask, time_
notice_lang(bi->nick, u, OPER_SQLINE_ALREADY_COVERED, mask.c_str(), canAdd.second->Mask.c_str());
}
- return canAdd.second;
+ return NULL;
}
- XLine *x = new XLine(mask, u ? u->nick : "", expires, reason);
+ XLine *x = new XLine(mask, u ? u->nick : OperServ->nick, expires, reason);
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnAddXLine, OnAddXLine(u, x, X_SQLINE));
@@ -747,10 +747,10 @@ XLine *SZLineManager::Add(BotInfo *bi, User *u, const Anope::string &mask, time_
notice_lang(bi->nick, u, OPER_SZLINE_ALREADY_COVERED, mask.c_str(), canAdd.second->Mask.c_str());
}
- return canAdd.second;
+ return NULL;
}
- XLine *x = new XLine(mask, u ? u->nick : "", expires, reason);
+ XLine *x = new XLine(mask, u ? u->nick : OperServ->nick, expires, reason);
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnAddXLine, OnAddXLine(u, x, X_SZLINE));
diff --git a/src/servers.cpp b/src/servers.cpp
index 4b843411c..a5721083f 100644
--- a/src/servers.cpp
+++ b/src/servers.cpp
@@ -236,18 +236,18 @@ void Server::Sync(bool SyncLinks)
this->Links[i]->Sync(true);
}
- if (this == Me->GetLinks().front())
+ if (this->GetUplink() && this->GetUplink() == Me)
{
FOREACH_MOD(I_OnPreUplinkSync, OnPreUplinkSync(this));
ircdproto->SendEOB();
- Me->UnsetFlag(SERVER_SYNCING);
+ Me->Sync(false);
}
Log(this, "sync") << "is done syncing";
FOREACH_MOD(I_OnServerSync, OnServerSync(this));
- if (this == Me->GetLinks().front())
+ if (this->GetUplink() && this->GetUplink() == Me)
{
FOREACH_MOD(I_OnUplinkSync, OnUplinkSync(this));
restore_unsynced_topics();
@@ -407,9 +407,6 @@ void CapabParse(int ac, const char **av)
if (Capab_Info[j].Token.equals_ci(av[i]))
{
Capab.SetFlag(Capab_Info[j].Flag);
-
- if (Capab_Info[j].Token.equals_ci("NICKIP") && !ircd->nickip)
- ircd->nickip = 1;
break;
}
}
diff --git a/src/sockets.cpp b/src/sockets.cpp
index 7dcdde678..f58aa2498 100644
--- a/src/sockets.cpp
+++ b/src/sockets.cpp
@@ -15,11 +15,147 @@ static void TrimBuf(std::string &buffer)
buffer.erase(buffer.length() - 1);
}
+/** Get the size of the sockaddr we represent
+ * @return The size
+ */
+size_t sockaddrs::size() const
+{
+ switch (sa.sa_family)
+ {
+ case AF_INET:
+ return sizeof(sa4);
+ case AF_INET6:
+ return sizeof(sa6);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/** Get the port represented by this addr
+ * @return The port, or -1 on fail
+ */
+int sockaddrs::port() const
+{
+ switch (sa.sa_family)
+ {
+ case AF_INET:
+ return ntohs(sa4.sin_port);
+ case AF_INET6:
+ return ntohs(sa6.sin6_port);
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+/** Get the address represented by this addr
+ * @return The address
+ */
+Anope::string sockaddrs::addr() const
+{
+ char address[INET6_ADDRSTRLEN + 1] = "";
+
+ switch (sa.sa_family)
+ {
+ case AF_INET:
+ if (!inet_ntop(AF_INET, &sa4.sin_addr, address, sizeof(address)))
+ throw SocketException(strerror(errno));
+ return address;
+ case AF_INET6:
+ if (!inet_ntop(AF_INET6, &sa6.sin6_addr, address, sizeof(address)))
+ throw SocketException(strerror(errno));
+ return address;
+ default:
+ break;
+ }
+
+ return address;
+}
+
+/** Construct the object, sets everything to 0
+ */
+sockaddrs::sockaddrs()
+{
+ memset(this, 0, sizeof(*this));
+}
+
+/** Check if this sockaddr has data in it
+ */
+bool sockaddrs::operator()() const
+{
+ return this->sa.sa_family != 0;
+}
+
+/** Compares with sockaddr with another. Compares address type, port, and address
+ * @return true if they are the same
+ */
+bool sockaddrs::operator==(const sockaddrs &other) const
+{
+ if (sa.sa_family != other.sa.sa_family)
+ return false;
+ switch (sa.sa_family)
+ {
+ case AF_INET:
+ return (sa4.sin_port == other.sa4.sin_port) && (sa4.sin_addr.s_addr == other.sa4.sin_addr.s_addr);
+ case AF_INET6:
+ return (sa6.sin6_port == other.sa6.sin6_port) && !memcmp(sa6.sin6_addr.s6_addr, other.sa6.sin6_addr.s6_addr, 16);
+ default:
+ return !memcmp(this, &other, sizeof(*this));
+ }
+
+ return false;
+}
+
+void sockaddrs::pton(int type, const Anope::string &address, int pport)
+{
+ switch (type)
+ {
+ case AF_INET:
+ if (inet_pton(type, address.c_str(), &sa4.sin_addr) < 1)
+ throw SocketException(Anope::string("Invalid host: ") + strerror(errno));
+ sa4.sin_family = type;
+ sa4.sin_port = htons(pport);
+ return;
+ case AF_INET6:
+ if (inet_pton(type, address.c_str(), &sa6.sin6_addr) < 1)
+ throw SocketException(Anope::string("Invalid host: ") + strerror(errno));
+ sa6.sin6_family = type;
+ sa6.sin6_port = htons(pport);
+ return;
+ default:
+ break;
+ }
+
+ throw CoreException("Invalid socket type");
+}
+
+void sockaddrs::ntop(int type, const void *src)
+{
+ switch (type)
+ {
+ case AF_INET:
+ sa4.sin_addr = *reinterpret_cast<const in_addr *>(src);
+ sa4.sin_family = type;
+ return;
+ case AF_INET6:
+ sa6.sin6_addr = *reinterpret_cast<const in6_addr *>(src);
+ sa6.sin6_family = type;
+ return;
+ default:
+ break;
+ }
+
+ throw CoreException("Invalid socket type");
+}
+
SocketEngineBase::SocketEngineBase()
{
#ifdef _WIN32
if (WSAStartup(MAKEWORD(2, 0), &wsa))
- Log() << "Failed to initialize WinSock library";
+ throw FatalException("Failed to initialize WinSock library");
#endif
}
@@ -40,13 +176,14 @@ Socket::Socket()
/** Constructor
* @param nsock The socket
* @param nIPv6 IPv6?
+ * @param type The socket type, defaults to SOCK_STREAM
*/
-Socket::Socket(int nsock, bool nIPv6)
+Socket::Socket(int nsock, bool nIPv6, int type)
{
Type = SOCKTYPE_CLIENT;
IPv6 = nIPv6;
if (nsock == 0)
- Sock = socket(IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
+ Sock = socket(IPv6 ? AF_INET6 : AF_INET, type, 0);
else
Sock = nsock;
SocketEngine->AddSocket(this);
@@ -56,7 +193,8 @@ Socket::Socket(int nsock, bool nIPv6)
*/
Socket::~Socket()
{
- SocketEngine->DelSocket(this);
+ if (SocketEngine)
+ SocketEngine->DelSocket(this);
CloseSocket(Sock);
}
@@ -183,7 +321,7 @@ bool Socket::ProcessRead()
return true;
}
-/** Called when there is something to be written to this socket
+/** Called when the socket is ready to be written to
* @return true on success, false to drop this socket
*/
bool Socket::ProcessWrite()
@@ -197,7 +335,7 @@ bool Socket::ProcessWrite()
return false;
}
WriteBuffer.clear();
- SocketEngine->ClearWriteable(this);
+ SocketEngine->ClearWritable(this);
return true;
}
@@ -243,7 +381,7 @@ void Socket::Write(const char *message, ...)
void Socket::Write(const Anope::string &message)
{
WriteBuffer.append(message.str() + "\r\n");
- SocketEngine->MarkWriteable(this);
+ SocketEngine->MarkWritable(this);
}
/** Constructor
@@ -251,103 +389,22 @@ void Socket::Write(const Anope::string &message)
* @param nu The user using this socket
* @param nsock The socket
* @param nIPv6 IPv6
+ * @param type The socket type, defaults to SOCK_STREAM
*/
-ClientSocket::ClientSocket(const Anope::string &nTargetHost, int nPort, const Anope::string &nBindHost, bool nIPv6) : Socket(0, nIPv6), TargetHost(nTargetHost), Port(nPort), BindHost(nBindHost)
+ClientSocket::ClientSocket(const Anope::string &nTargetHost, int nPort, const Anope::string &nBindHost, bool nIPv6, int type) : Socket(0, nIPv6, type), TargetHost(nTargetHost), Port(nPort), BindHost(nBindHost)
{
- addrinfo hints;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = 0;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_family = IPv6 ? AF_INET6 : AF_INET;
-
if (!BindHost.empty())
{
- addrinfo *bindar;
- sockaddr_in bindaddr;
- sockaddr_in6 bindaddr6;
-
- if (!getaddrinfo(BindHost.c_str(), NULL, &hints, &bindar))
- {
- if (IPv6)
- memcpy(&bindaddr6, bindar->ai_addr, bindar->ai_addrlen);
- else
- memcpy(&bindaddr, bindar->ai_addr, bindar->ai_addrlen);
-
- freeaddrinfo(bindar);
- }
- else
- {
- if (IPv6)
- {
- bindaddr6.sin6_family = AF_INET6;
-
- if (inet_pton(AF_INET6, BindHost.c_str(), &bindaddr6.sin6_addr) < 1)
- throw SocketException(Anope::string("Invalid bind host: ") + strerror(errno));
- }
- else
- {
- bindaddr.sin_family = AF_INET;
-
- if (inet_pton(AF_INET, BindHost.c_str(), &bindaddr.sin_addr) < 1)
- throw SocketException(Anope::string("Invalid bind host: ") + strerror(errno));
- }
- }
-
- if (IPv6)
- {
- if (bind(Sock, reinterpret_cast<sockaddr *>(&bindaddr6), sizeof(bindaddr6)) == -1)
- throw SocketException(Anope::string("Unable to bind to address: ") + strerror(errno));
- }
- else
- {
- if (bind(Sock, reinterpret_cast<sockaddr *>(&bindaddr), sizeof(bindaddr)) == -1)
- throw SocketException(Anope::string("Unable to bind to address: ") + strerror(errno));
- }
- }
-
- addrinfo *conar;
- sockaddr_in6 addr6;
- sockaddr_in addr;
-
- if (!getaddrinfo(TargetHost.c_str(), NULL, &hints, &conar))
- {
- if (IPv6)
- memcpy(&addr6, conar->ai_addr, conar->ai_addrlen);
- else
- memcpy(&addr, conar->ai_addr, conar->ai_addrlen);
-
- freeaddrinfo(conar);
- }
- else
- {
- if (IPv6)
- {
- if (inet_pton(AF_INET6, TargetHost.c_str(), &addr6.sin6_addr) < 1)
- throw SocketException(Anope::string("Invalid server host: ") + strerror(errno));
- }
- else
- {
- if (inet_pton(AF_INET, TargetHost.c_str(), &addr.sin_addr) < 1)
- throw SocketException(Anope::string("Invalid server host: ") + strerror(errno));
- }
- }
-
- if (IPv6)
- {
- addr6.sin6_family = AF_INET6;
- addr6.sin6_port = htons(nPort);
-
- if (connect(Sock, reinterpret_cast<sockaddr *>(&addr6), sizeof(addr6)) == -1)
- throw SocketException(Anope::string("Error connecting to server: ") + strerror(errno));
+ sockaddrs bindaddr;
+ bindaddr.pton(IPv6 ? AF_INET6 : AF_INET, BindHost, 0);
+ if (bind(Sock, &bindaddr.sa, bindaddr.size()) == -1)
+ throw SocketException(Anope::string("Unable to bind to address: ") + strerror(errno));
}
- else
- {
- addr.sin_family = AF_INET;
- addr.sin_port = htons(nPort);
- if (connect(Sock, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) == -1)
- throw SocketException(Anope::string("Error connecting to server: ") + strerror(errno));
- }
+ sockaddrs conaddr;
+ conaddr.pton(IPv6 ? AF_INET6 : AF_INET, TargetHost, Port);
+ if (connect(Sock, &conaddr.sa, conaddr.size()) == -1)
+ throw SocketException(Anope::string("Error connecting to server: ") + strerror(errno));
this->SetNonBlocking();
}
@@ -377,36 +434,11 @@ ListenSocket::ListenSocket(const Anope::string &bindip, int port) : Socket(0, (b
BindIP = bindip;
Port = port;
- sockaddr_in sock_addr;
- sockaddr_in6 sock_addr6;
-
- if (IPv6)
- {
- sock_addr6.sin6_family = AF_INET6;
- sock_addr6.sin6_port = htons(port);
-
- if (inet_pton(AF_INET6, bindip.c_str(), &sock_addr6.sin6_addr) < 1)
- throw SocketException(Anope::string("Invalid bind host: ") + strerror(errno));
- }
- else
- {
- sock_addr.sin_family = AF_INET;
- sock_addr.sin_port = htons(port);
-
- if (inet_pton(AF_INET, bindip.c_str(), &sock_addr.sin_addr) < 1)
- throw SocketException(Anope::string("Invalid bind host: ") + strerror(errno));
- }
+ sockaddrs sockaddr;
+ sockaddr.pton(IPv6 ? AF_INET6 : AF_INET, BindIP, Port);
- if (IPv6)
- {
- if (bind(Sock, reinterpret_cast<sockaddr *>(&sock_addr6), sizeof(sock_addr6)) == -1)
- throw SocketException(Anope::string("Unable to bind to address: ") + strerror(errno));
- }
- else
- {
- if (bind(Sock, reinterpret_cast<sockaddr *>(&sock_addr), sizeof(sock_addr)) == -1)
- throw SocketException(Anope::string("Unable to bind to address: ") + strerror(errno));
- }
+ if (bind(Sock, &sockaddr.sa, sockaddr.size()) == -1)
+ throw SocketException(Anope::string("Unable to bind to address: ") + strerror(errno));
if (listen(Sock, 5) == -1)
throw SocketException(Anope::string("Unable to listen: ") + strerror(errno));
@@ -426,7 +458,7 @@ bool ListenSocket::ProcessRead()
{
int newsock = accept(Sock, NULL, NULL);
-#ifndef _WIN32
+#ifndef INVALID_SOCKET
# define INVALID_SOCKET 0
#endif
diff --git a/src/users.cpp b/src/users.cpp
index c9c5ce20e..36b32071b 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -186,7 +186,7 @@ User::~User()
{
Log(LOG_DEBUG_2) << "User::~User() called";
- Log(this, "disconnect") << " (" << this->realname << ") " << "disconnected from the network (" << this->server->GetName() << ")";
+ Log(this, "disconnect") << "(" << this->realname << ") " << "disconnected from the network (" << this->server->GetName() << ")";
this->Logout();
@@ -642,16 +642,13 @@ User *finduser(const Anope::string &nick)
/* Handle a server NICK command. */
-User *do_nick(const Anope::string &source, const Anope::string &nick, const Anope::string &username, const Anope::string &host, const Anope::string &server, const Anope::string &realname, time_t ts, uint32 ip, const Anope::string &vhost, const Anope::string &uid)
+User *do_nick(const Anope::string &source, const Anope::string &nick, const Anope::string &username, const Anope::string &host, const Anope::string &server, const Anope::string &realname, time_t ts, const Anope::string &ip, const Anope::string &vhost, const Anope::string &uid)
{
User *user = NULL;
Anope::string vhost2 = vhost;
if (source.empty())
{
- char ipbuf[16];
- struct in_addr addr;
-
if (ircd->nickvhost && !vhost2.empty() && vhost2.equals_cs("*"))
{
vhost2.clear();
@@ -660,12 +657,6 @@ User *do_nick(const Anope::string &source, const Anope::string &nick, const Anop
/* This is a new user; create a User structure for it. */
Log(LOG_DEBUG) << "new user: " << nick;
- if (ircd->nickip)
- {
- addr.s_addr = htonl(ip);
- ntoa(addr, ipbuf, sizeof(ipbuf));
- }
-
Server *serv = Server::Find(server);
/* Allocate User structure and fill it in. */
@@ -677,14 +668,24 @@ User *do_nick(const Anope::string &source, const Anope::string &nick, const Anop
if (!vhost2.empty())
user->SetCloakedHost(vhost2);
user->SetVIdent(username);
- /* We now store the user's ip in the user_ struct,
- * because we will use it in serveral places -- DrStein */
- if (ircd->nickip)
- user->hostip = ipbuf;
- else
- user->hostip = "";
- Log(user, "connect") << (ircd->nickvhost && !vhost2.empty() ? Anope::string("(") + vhost2 + ")" : "") << ") (" << user->realname << ") " << (ircd->nickip ? Anope::string("[") + ipbuf + "] " : "") << "connected to the network (" << serv->GetName() << ")";
+ if (!ip.empty())
+ {
+ try
+ {
+ if (ip.find(':') != Anope::string::npos)
+ user->ip.pton(AF_INET6, ip);
+ else
+ user->ip.pton(AF_INET, ip);
+ }
+ catch (const SocketException &ex)
+ {
+ Log() << "Received an invalid IP for user " << user->nick << " (" << ip << ")";
+ Log() << ex.GetReason();
+ }
+ }
+
+ Log(user, "connect") << (ircd->nickvhost && !vhost2.empty() ? Anope::string("(") + vhost2 + ")" : "") << ") (" << user->realname << ") " << (user->ip() ? Anope::string("[") + user->ip.addr() + "] " : "") << "connected to the network (" << serv->GetName() << ")";
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnPreUserConnect, OnPreUserConnect(user));
@@ -692,7 +693,7 @@ User *do_nick(const Anope::string &source, const Anope::string &nick, const Anop
return finduser(nick);
if (Config->LimitSessions && !serv->IsULined())
- add_session(nick, host, ipbuf);
+ add_session(nick, host, user->ip() ? user->ip.addr() : "");
XLineManager::CheckAll(user);