summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlethality <lee@lethality.me.uk>2014-02-18 22:24:24 +0000
committerlethality <lee@lethality.me.uk>2014-02-18 22:24:24 +0000
commit5933a5e9b1ade9f926145b67e557b87ae6dd6e8f (patch)
tree41c9c8b4c1818531251c292ce184601a8721aed4
parentf1c5c27f3fda90265d5da8205db1bdd4d12c9851 (diff)
parent109d8f431f3d25d56570a6aaa1af957867bbb80e (diff)
Merge remote branch 'upstream/2.0' into 2.0
-rw-r--r--data/example.conf2
-rw-r--r--data/modules.example.conf265
-rw-r--r--data/stats.standalone.example.conf2
-rw-r--r--docs/Changes.conf1
-rw-r--r--docs/IRCD202
-rw-r--r--docs/WIN32.txt7
-rw-r--r--include/modules/encryption.h (renamed from modules/encryption/encryption.h)0
-rw-r--r--include/modules/os_forbid.h48
-rw-r--r--include/modules/os_ignore.h54
-rw-r--r--include/service.h2
-rw-r--r--include/sockets.h2
-rw-r--r--modules/commands/os_forbid.cpp54
-rw-r--r--modules/commands/os_ignore.cpp160
-rw-r--r--modules/commands/os_session.cpp2
-rw-r--r--modules/database/db_old.cpp24
-rw-r--r--modules/encryption/enc_md5.cpp2
-rw-r--r--modules/encryption/enc_old.cpp2
-rw-r--r--modules/encryption/enc_sha1.cpp2
-rw-r--r--modules/encryption/enc_sha256.cpp2
-rw-r--r--modules/extra/enc_bcrypt.cpp2
-rw-r--r--modules/extra/m_ssl_gnutls.cpp509
-rw-r--r--modules/extra/m_ssl_openssl.cpp (renamed from modules/extra/m_ssl.cpp)4
-rw-r--r--modules/m_httpd.cpp3
-rw-r--r--modules/webcpanel/template_fileserver.cpp11
-rw-r--r--src/socket_transport.cpp2
-rw-r--r--src/sockets.cpp2
26 files changed, 880 insertions, 486 deletions
diff --git a/data/example.conf b/data/example.conf
index fbb7e310e..4d4ba6b17 100644
--- a/data/example.conf
+++ b/data/example.conf
@@ -168,7 +168,7 @@ uplink
/*
* Enable if Services should connect using SSL.
- * You must have m_ssl loaded for this to work.
+ * You must have an SSL module loaded for this to work.
*/
ssl = no
diff --git a/data/modules.example.conf b/data/modules.example.conf
index e58ebea88..30927433f 100644
--- a/data/modules.example.conf
+++ b/data/modules.example.conf
@@ -201,7 +201,7 @@ module { name = "help" }
/* Time before connections to this server are timed out. */
timeout = 30
- /* Listen using SSL. Requires m_ssl. */
+ /* Listen using SSL. Requires an SSL module. */
#ssl = yes
/* If you are using a reverse proxy that sends one of the
@@ -357,6 +357,82 @@ module { name = "help" }
port = 3306
}
}
+/*
+ * m_redis
+ *
+ * This module allows other modules to use Redis.
+ */
+#module
+{
+ name = "m_redis"
+
+ /* A redis database */
+ redis
+ {
+ /* The name of this service */
+ name = "redis/main"
+
+ /*
+ * The redis database to use. New connections default to 0.
+ */
+ db = 0
+
+ ip = "127.0.0.1"
+ port = 6379
+ }
+}
+
+/*
+ * m_regex_pcre [EXTRA]
+ *
+ * Provides the regex engine regex/pcre, which uses the Perl Compatible Regular Expressions library.
+ */
+#module { name = "m_regex_pcre" }
+
+/*
+ * m_regex_posix [EXTRA]
+ *
+ * Provides the regex engine regex/posix, which uses the POSIX compliant regular expressions.
+ * This is likely the only regex module you will not need extra libraries for.
+ */
+#module { name = "m_regex_posix" }
+
+/*
+ * m_regex_tre [EXTRA]
+ *
+ * Provides the regex engine regex/tre, which uses the TRE regex library.
+ */
+#module { name = "m_regex_tre" }
+
+/*
+ * m_rewrite
+ *
+ * Allows rewriting commands sent to/from clients.
+ */
+#module { name = "m_rewrite" }
+#command
+{
+ service = "ChanServ"; name = "CLEAR"; command = "rewrite"
+
+ /* Enable m_rewrite. */
+ rewrite = true
+
+ /* Source message to match. A $ can be used to match anything. */
+ rewrite_source = "CLEAR $ USERS"
+
+ /*
+ * Message to rewrite the source message to. A $ followed by a number, eg $0, gets
+ * replaced by the number-th word from the source_message, starting from 0.
+ */
+ rewrite_target = "KICK $1 *"
+
+ /*
+ * The command description. This only shows up in HELP's output.
+ * Comment this option to prevent the command from showing in the
+ * HELP command.
+ */
+ rewrite_description = "Clears all users from a channel"
+}
/*
* m_proxyscan
@@ -469,6 +545,69 @@ module { name = "help" }
#module { name = "m_sasl_dh-blowfish" }
/*
+ * m_ssl_gnutls [EXTRA]
+ *
+ * This module provides SSL services to Anope using GnuTLS, for example to
+ * connect to the uplink server(s) via SSL.
+ *
+ * You may only load either m_ssl_gnutls or m_ssl_openssl, bot not both.
+ */
+#module
+{
+ name = "m_ssl_gnutls"
+
+ /*
+ * An optional certificate and key for m_gnutls to give to the uplink.
+ *
+ * You can generate your own certificate and key pair by using:
+ *
+ * certtool --generate-privkey --bits 2048 --outfile anope.key
+ * certtool --generate-self-signed --load-privkey anope.key --outfile anope.crt
+ *
+ */
+ cert = "data/anope.crt"
+ key = "data/anope.key"
+
+ /*
+ * Diffie-Hellman parameters to use when acting as a server. This is only
+ * required for TLS servers that want to use ephemeral DH cipher suites.
+ *
+ * This is NOT required for Anope to connect to the uplink server(s) via SSL.
+ *
+ * You can generate DH parameters by using:
+ *
+ * certtool --generate-dh-params --bits 2048 --outfile dhparams.pem
+ *
+ */
+# dhparams = "data/dhparams.pem"
+}
+
+/*
+ * m_ssl_openssl [EXTRA]
+ *
+ * This module provides SSL services to Anope using OpenSSL, for example to
+ * connect to the uplink server(s) via SSL.
+ *
+ * You may only load either m_ssl_openssl or m_ssl_gnutls, bot not both.
+ *
+ */
+#module
+{
+ name = "m_ssl_openssl"
+
+ /*
+ * An optional certificate and key for m_openssl to give to the uplink.
+ *
+ * You can generate your own certificate and key pair by using:
+ *
+ * openssl genrsa -out anope.key 2048
+ * openssl req -new -x509 -key anope.key -out anope.crt -days 1095
+ */
+ cert = "data/anope.crt"
+ key = "data/anope.key"
+}
+
+/*
* m_sql_authentication [EXTRA]
*
* This module allows authenticating users against an external SQL database using a custom
@@ -586,101 +725,26 @@ module { name = "help" }
}
/*
- * m_redis
- *
- * This module allows other modules to use Redis.
- */
-#module
-{
- name = "m_redis"
-
- /* A redis database */
- redis
- {
- /* The name of this service */
- name = "redis/main"
-
- /*
- * The redis database to use. New connections default to 0.
- */
- db = 0
-
- ip = "127.0.0.1"
- port = 6379
- }
-}
-
-/*
- * m_regex_pcre [EXTRA]
- *
- * Provides the regex engine regex/pcre, which uses the Perl Compatible Regular Expressions library.
- */
-#module { name = "m_regex_pcre" }
-
-/*
- * m_regex_posix [EXTRA]
- *
- * Provides the regex engine regex/posix, which uses the POSIX compliant regular expressions.
- * This is likely the only regex module you will not need extra libraries for.
- */
-#module { name = "m_regex_posix" }
-
-/*
- * m_regex_tre [EXTRA]
+ * webcpanel
*
- * Provides the regex engine regex/tre, which uses the TRE regex library.
- */
-#module { name = "m_regex_tre" }
-
-/*
- * m_rewrite
+ * This module creates a web configuration panel that allows users and operators to perform any task
+ * as they could over IRC. If you are using the default configuration you should be able to access
+ * this panel by visiting http://127.0.0.1:8080 in your web browser from the machine Anope is running on.
*
- * Allows rewriting commands sent to/from clients.
+ * This module requires m_httpd.
*/
-#module { name = "m_rewrite" }
-#command
+#module
{
- service = "ChanServ"; name = "CLEAR"; command = "rewrite"
-
- /* Enable m_rewrite. */
- rewrite = true
-
- /* Source message to match. A $ can be used to match anything. */
- rewrite_source = "CLEAR $ USERS"
-
- /*
- * Message to rewrite the source message to. A $ followed by a number, eg $0, gets
- * replaced by the number-th word from the source_message, starting from 0.
- */
- rewrite_target = "KICK $1 *"
+ name = "webcpanel"
- /*
- * The command description. This only shows up in HELP's output.
- * Comment this option to prevent the command from showing in the
- * HELP command.
- */
- rewrite_description = "Clears all users from a channel"
-}
+ /* Web server to use. */
+ server = "httpd/main";
-/*
- * m_ssl [EXTRA]
- *
- * This module uses SSL to connect to the uplink server(s).
- */
-#module
-{
- name = "m_ssl"
+ /* Template to use. */
+ template = "default";
- /*
- * An optional certificate and key for m_ssl to give to the uplink.
- *
- * You can generate your own certificate and key pair by using:
- *
- * openssl genrsa -out anope.key 2048
- * openssl req -new -x509 -key anope.key -out anope.crt -days 1095
- */
- cert = "data/anope.crt"
- key = "data/anope.key"
+ /* Page title. */
+ title = "Anope IRC Services";
}
/*
@@ -704,26 +768,3 @@ module { name = "help" }
* Requires m_xmlrpc.
*/
#module { name = "m_xmlrpc_main" }
-
-/*
- * webcpanel
- *
- * This module creates a web configuration panel that allows users and operators to perform any task
- * as they could over IRC. If you are using the default configuration you should be able to access
- * this panel by visiting http://127.0.0.1:8080 in your web browser from the machine Anope is running on.
- *
- * This module requires m_httpd.
- */
-#module
-{
- name = "webcpanel"
-
- /* Web server to use. */
- server = "httpd/main";
-
- /* Template to use. */
- template = "default";
-
- /* Page title. */
- title = "Anope IRC Services";
-}
diff --git a/data/stats.standalone.example.conf b/data/stats.standalone.example.conf
index 7ba985e19..8db7c9999 100644
--- a/data/stats.standalone.example.conf
+++ b/data/stats.standalone.example.conf
@@ -168,7 +168,7 @@ uplink
/*
* Enable if Services should connect using SSL.
- * You must have m_ssl loaded for this to work.
+ * You must have an SSL module loaded for this to work.
*/
ssl = no
diff --git a/docs/Changes.conf b/docs/Changes.conf
index aae151fd9..8b41ad2be 100644
--- a/docs/Changes.conf
+++ b/docs/Changes.conf
@@ -2,6 +2,7 @@ Anope Version 2.0.0
-------------------
options:passlen, enforceruser, enforcerhost, releasetimeout, and guestnickprefix moved to nickserv's module configuration
options:hideregisteredcommands added
+m_ssl renamed to m_ssl_openssl
Anope Version 1.9.9
-------------------
diff --git a/docs/IRCD b/docs/IRCD
deleted file mode 100644
index 7a3effbb3..000000000
--- a/docs/IRCD
+++ /dev/null
@@ -1,202 +0,0 @@
-How To Add IRCd Support
------------------------
-
-1) Files to Edit
-2) The Code
-3) The IRCDVar struct
-4) Modes
-5) Functions / Events
-6) CAPAB/PROTOCTL
-7) IRCDProto Class
-
-1) Files to Edit
-
- When preparing to add supprt to Anope for your IRCd, you need to edit
- the following files
-
- A) Make a copy of the .cpp file of the IRCd that matches the IRCd that
- you are attempting to add support for best.
- B) Add your IRCd into the supported IRCds in example.conf
-
-2) The Code
-
- Here is where the code of the .cpp file comes in. Be prepared to spend at
- least an hour, if not longer, going over the code and getting it right;
- Especially if you are setting up an ircd that is completely different
- than the one you used as a base. This section covers the majority of the
- code that is in use.
-
- The first bit of code you will face is the IRCDVar structure, This is one
- of two structs which holds your IRCd information; This allows you to quickly
- setup your specific ircd.
-
- IRCDVar myIrcd[] = { };
-
- This struct contains your basic IRCd functions. Your base source file has
- the list of all available variables; note that you should not swap any
- around, or you will break stuff. Here is a brief description of the usage
- of each.
-
- 1) Name: This member tells Anope about the IRCD's name. It may contain
- text about it's name and version. This is used to identify the
- build on startup.
-
- 2) Pseudo Client Mode: This is the user mode set by Anope on all BotServ
- bots. Normally you want this to be a some form of
- service or bot flag; you can use + for no mode at
- all.
-
- 3) Max Channelmode Symbols: This is the total number of possible channel
- modes that can appear before a nick. Do
- remember to count each possible mode, so +ov
- is 2.
-
- 4) SVSNICK: Can the ircd use SVSNICK to change some ones nick? Otherwise,
- KILL is used. Use 1 for yes, 0 for no.
-
- 5) VHOST: Can a user's host be changed on the fly? Enabling this allow
- HostServ online. Use 1 for yes, 0 for no.
-
- 6) SNLINE: Does the IRCd support realname (geocs) bans? Use 1 for yes,
- 0 for no.
-
- 7) SQLINE: Does the IRCd support nick bans? Use 1 for yes, 0 for no.
-
- 8) SZLINE: Does the IRCd support SZLINES? Use 1 for yes, 0 for no.
-
- 10) Join to Message: Services must join a channel to send any message to
- that channel (cannot override +n). Use 1 for yes,
- 0 for no.
-
- 11) SQline Channels: The IRCd's supports banning channel names via
- SQLINES. Use 1 for yes, 0 for no.
-
- 12) Quit On Kill: When we (SVS)KILL a user, does the IRCd send back a
- QUIT message for that user? Use 1 for yes, 0 for no.
-
- 13) SVSMODE UNBAN: We can use SVSMODE to unban hosts from a channel. Use
- 1 for yes, 0 for no.
-
- 14) Reverse: We can do a reverse check when unbanning. For use with
- DreamForge based IRCd's. Use 1 for yes, 0 for no.
-
- 15) vIdent: Support for including a user's ident in their vHost. Use
- 1 for yes, 0 for no.
-
- 16) SVSHOLD: Support for temporarily 'holding' a nick, instead of using
- a nick enforcer client. Use 1 for yes, 0 for no.
-
- 17) TS on MODE: We need to send a timestamp when modes are being changed.
- Use 1 for yes, 0 for no.
-
- 18) Umode: We can use OperServ to change a user's mode. Use 1 for yes,
- 0 for no.
-
- 19) OMODE: We can use OperServ to give some user a temporary O:LINE.
- Use 1 for yes, 0 for no.
-
- 20) No Knock Requires +i: Does the No Knock channel mode require invite
- only channels? Use 1 for yes, 0 for no.
-
- 21) SVSMODE UCMODE: Can we clear user channel modes with SVSMODE? Use
- 1 for yes, 0 for no.
-
- 22) SGline Enforce: Does the IRCd enforce SNLINES for us or do we need to
- do so? Use 1 for yes, 0 for no.
-
- 23) TS6: Does the IRCd support TS6? Use 1 for yes, 0 for no.
-
- 24) Global TLD Prefix: Prefix used to send global messages, should probably
- be "$"
-
- 25) Max Modes: The max number of mode changes we can send in one line
-
-3) Modes
-
- Anope is told about modes in the protocol module.
- For the most part, the syntax for adding channel and user modes are:
-
- ModeManager::AddUserMode(new UserMode(UMODE_NETADMIN, "UMODE_NETADMIN", 'N'));
- Where 'N' is the char for the mode, and UMODE_NETADMIN shows what the
- mode does. Or:
-
- ModeManager::AddChannelMode(new ChannelMode(CMODE_BLOCKCOLOR, "CMODE_BLOCKCOLOR", 'c'));
- Where 'c' is the char for the mode and CMODE_BLOCKCOLOR shows what
- the mode does
-
- A full list of valid mode names for the second param can be found
- in services.h in the enum for ChannelModeName and UserModeName
- If necessary, you can add additional modes to this list.
-
- Adding simple modes with parameters is similar, instead adding a
- 'new ChannelMode', use 'new ChannelModeParam', set the third optional
- arg of ChannelModeParam to false if the param should NOT be sent when unsetting
- it. Eg:
-
- ModeManager::AddChannelMode(new ChannelModeParam(CMODE_JOINFLOOD, "CMODE_JOINFLOOD", 'j', true));
-
- Anope will internally track the params, and they can be retrieved through
- Channel::GetParam();
-
- If you want to make param validity checking for a mode, you must create a new
- class which inherits from ChannelModeParam and overload the IsValid function.
- Modes CMODE_OPERONLY, CMODE_ADMINONLY, and CMODE_REGISTERED already exist
- internally as classes, to overload the CanSet function to disable non opers
- from mlocking (or in CMODE_REGISTERED's case, anyone) from setting them.
- This should be added like:
-
- ModeManager::AddChannelMode(new ChannelModeOper('O'));
-
-4) Functions and Events
-
- A brief word about functions and events. All events are captured by creating a Message struct
- with the name of the message and the callback function:
-
- Message my_message("MESSAGE", do_my_messsage);
-
- Each message should have a message handler if its important enough to be
- processed by services. All event functions should be formed like this:
-
- bool do_my_message(const Anope::string &source, const std::vector<Anope::string> &params)
- {
- return true;
- }
-
- They will receive the source; this can be empty at times depending on the
- event. Next, params holds the arguments for the event. Events are likely to
- pass to various upper level event handlers; see the previous ircd source for
- how they handle these events.
-
-5) CAPAB/PROTOCTL
-
- Most IRCDs send a CAPAB or PROTOCTL line so that they can work out what
- the other end of the connection is capable of doing. The protocol module should
- handle all of these without the cores knowledge with the exception of the following:
-
- --------------------------------------------------------------------------
- Define | Description
- ----------------|---------------------------------------------------------
- CAPAB_NOQUIT | NOQUIT protocol support
- CAPAB_TSMODE | Chanmodes are timestamped
- CAPAB_UNCONNECT | UNCONNECT protocol support
- CAPAB_QS | Quitstorm - same as NOQUIT
-
- You can override the default OnCapab method in IRCdMessage if required.
-
-6) IRCDProto Class
-
- The IRCDProto class is set up like:
-
- class MyIRCdProto : public IRCDProto { } ircdproto;
-
- And told to Anope through the
-
- pmodule_ircd_proto(&ircd_proto);
-
- function.
-
- This is used for sending out specific messages from Anope to your IRCd.
- A list of all of the valid function names to overload and their args
- are in services.h. If the protocol module you are editing is similar enough
- to the IRCd you are adding support for, many of these probably won't need to
- be changed.
diff --git a/docs/WIN32.txt b/docs/WIN32.txt
index 7922523f4..018b898d2 100644
--- a/docs/WIN32.txt
+++ b/docs/WIN32.txt
@@ -71,9 +71,10 @@ Anope for Windows
our IRC Support channel for assistance.
Some Anope modules require third party libraries, such as m_mysql and
- m_ssl. If these libraries are installed in nonstandard locations, cmake
- will probably not find them and should be told where they are by passing
- additional search paths to the last question in Config, such as:
+ the SSL modules. If these libraries are installed in nonstandard
+ locations, cmake will probably not find them and should be told where
+ they are by passing additional search paths to the last question in
+ Config, such as:
-DEXTRA_INCLUDE:STRING=c:/openssl/include;c:/mysql/include
-DEXTRA_LIBS:STRING=c:/openssl/lib;c:/mysql/lib
diff --git a/modules/encryption/encryption.h b/include/modules/encryption.h
index 95c5703aa..95c5703aa 100644
--- a/modules/encryption/encryption.h
+++ b/include/modules/encryption.h
diff --git a/include/modules/os_forbid.h b/include/modules/os_forbid.h
index 3f1fe9a7f..fe96ba5c6 100644
--- a/include/modules/os_forbid.h
+++ b/include/modules/os_forbid.h
@@ -10,7 +10,7 @@ enum ForbidType
FT_SIZE
};
-struct ForbidData : Serializable
+struct ForbidData
{
Anope::string mask;
Anope::string creator;
@@ -19,9 +19,9 @@ struct ForbidData : Serializable
time_t expires;
ForbidType type;
- ForbidData() : Serializable("ForbidData") { }
- void Serialize(Serialize::Data &data) const anope_override;
- static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
+ virtual ~ForbidData() { }
+ protected:
+ ForbidData() : created(0), expires(0) { }
};
class ForbidService : public Service
@@ -33,6 +33,8 @@ class ForbidService : public Service
virtual void RemoveForbid(ForbidData *d) = 0;
+ virtual ForbidData* CreateForbid() = 0;
+
virtual ForbidData *FindForbid(const Anope::string &mask, ForbidType type) = 0;
virtual std::vector<ForbidData *> GetForbids() = 0;
@@ -40,43 +42,5 @@ class ForbidService : public Service
static ServiceReference<ForbidService> forbid_service("ForbidService", "forbid");
-void ForbidData::Serialize(Serialize::Data &data) const
-{
- data["mask"] << this->mask;
- data["creator"] << this->creator;
- data["reason"] << this->reason;
- data["created"] << this->created;
- data["expires"] << this->expires;
- data["type"] << this->type;
-}
-
-Serializable* ForbidData::Unserialize(Serializable *obj, Serialize::Data &data)
-{
- if (!forbid_service)
- return NULL;
-
- ForbidData *fb;
- if (obj)
- fb = anope_dynamic_static_cast<ForbidData *>(obj);
- else
- fb = new ForbidData;
-
- data["mask"] >> fb->mask;
- data["creator"] >> fb->creator;
- data["reason"] >> fb->reason;
- data["created"] >> fb->created;
- data["expires"] >> fb->expires;
- unsigned int t;
- data["type"] >> t;
- fb->type = static_cast<ForbidType>(t);
-
- if (t > FT_SIZE - 1)
- return NULL;
-
- if (!obj)
- forbid_service->AddForbid(fb);
- return fb;
-}
-
#endif
diff --git a/include/modules/os_ignore.h b/include/modules/os_ignore.h
index 0f2c2f0d8..2511d47b2 100644
--- a/include/modules/os_ignore.h
+++ b/include/modules/os_ignore.h
@@ -10,70 +10,36 @@
*/
-struct IgnoreData : Serializable
+struct IgnoreData
{
Anope::string mask;
Anope::string creator;
Anope::string reason;
time_t time; /* When do we stop ignoring them? */
- IgnoreData() : Serializable("IgnoreData") { }
- void Serialize(Serialize::Data &data) const anope_override;
- static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
+ virtual ~IgnoreData() { }
+ protected:
+ IgnoreData() : time(0) { }
};
class IgnoreService : public Service
{
protected:
- std::list<IgnoreData> ignores;
-
IgnoreService(Module *c) : Service(c, "IgnoreService", "ignore") { }
public:
- virtual IgnoreData* AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime) = 0;
+ virtual void AddIgnore(IgnoreData *) = 0;
+
+ virtual void DelIgnore(IgnoreData *) = 0;
- virtual bool DelIgnore(const Anope::string &mask) = 0;
+ virtual void ClearIgnores() = 0;
- inline void ClearIgnores() { this->ignores.clear(); }
+ virtual IgnoreData *Create() = 0;
virtual IgnoreData *Find(const Anope::string &mask) = 0;
- inline std::list<IgnoreData> &GetIgnores() { return this->ignores; }
+ virtual std::vector<IgnoreData *> &GetIgnores() = 0;
};
static ServiceReference<IgnoreService> ignore_service("IgnoreService", "ignore");
-void IgnoreData::Serialize(Serialize::Data &data) const
-{
- data["mask"] << this->mask;
- data["creator"] << this->creator;
- data["reason"] << this->reason;
- data["time"] << this->time;
-}
-
-Serializable* IgnoreData::Unserialize(Serializable *obj, Serialize::Data &data)
-{
- if (!ignore_service)
- return NULL;
-
- if (obj)
- {
- IgnoreData *ign = anope_dynamic_static_cast<IgnoreData *>(obj);
- data["mask"] >> ign->mask;
- data["creator"] >> ign->creator;
- data["reason"] >> ign->reason;
- data["time"] >> ign->time;
- return ign;
- }
-
- Anope::string smask, screator, sreason;
- time_t t;
-
- data["mask"] >> smask;
- data["creator"] >> screator;
- data["reason"] >> sreason;
- data["time"] >> t;
-
- return ignore_service->AddIgnore(smask, screator, sreason, t);
-}
-
diff --git a/include/service.h b/include/service.h
index db0b2af4b..8142363d6 100644
--- a/include/service.h
+++ b/include/service.h
@@ -20,7 +20,7 @@
/** Anything that inherits from this class can be referred to
* using ServiceReference. Any interfaces provided by modules,
* such as commands, use this. This is also used for modules
- * that publish a service (m_ssl, etc).
+ * that publish a service (m_ssl_openssl, etc).
*/
class CoreExport Service : public virtual Base
{
diff --git a/include/sockets.h b/include/sockets.h
index 744f1a23e..0dfa5d9d0 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -347,7 +347,7 @@ class CoreExport BinarySocket : public virtual Socket
/** Write data to the socket
* @param buffer The data to write
- * @param l The length of the data
+ * @param l The length of the data; if 0 then this function returns without doing anything
*/
virtual void Write(const char *buffer, size_t l);
void Write(const char *message, ...);
diff --git a/modules/commands/os_forbid.cpp b/modules/commands/os_forbid.cpp
index c1fe1af8b..11215ab05 100644
--- a/modules/commands/os_forbid.cpp
+++ b/modules/commands/os_forbid.cpp
@@ -14,6 +14,51 @@
static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
+struct ForbidDataImpl : ForbidData, Serializable
+{
+ ForbidDataImpl() : Serializable("ForbidData") { }
+ void Serialize(Serialize::Data &data) const anope_override;
+ static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
+};
+
+void ForbidDataImpl::Serialize(Serialize::Data &data) const
+{
+ data["mask"] << this->mask;
+ data["creator"] << this->creator;
+ data["reason"] << this->reason;
+ data["created"] << this->created;
+ data["expires"] << this->expires;
+ data["type"] << this->type;
+}
+
+Serializable* ForbidDataImpl::Unserialize(Serializable *obj, Serialize::Data &data)
+{
+ if (!forbid_service)
+ return NULL;
+
+ ForbidDataImpl *fb;
+ if (obj)
+ fb = anope_dynamic_static_cast<ForbidDataImpl *>(obj);
+ else
+ fb = new ForbidDataImpl();
+
+ data["mask"] >> fb->mask;
+ data["creator"] >> fb->creator;
+ data["reason"] >> fb->reason;
+ data["created"] >> fb->created;
+ data["expires"] >> fb->expires;
+ unsigned int t;
+ data["type"] >> t;
+ fb->type = static_cast<ForbidType>(t);
+
+ if (t > FT_SIZE - 1)
+ return NULL;
+
+ if (!obj)
+ forbid_service->AddForbid(fb);
+ return fb;
+}
+
class MyForbidService : public ForbidService
{
Serialize::Checker<std::vector<ForbidData *>[FT_SIZE - 1]> forbid_data;
@@ -43,6 +88,11 @@ class MyForbidService : public ForbidService
delete d;
}
+ ForbidData *CreateForbid() anope_override
+ {
+ return new ForbidDataImpl();
+ }
+
ForbidData *FindForbid(const Anope::string &mask, ForbidType ftype) anope_override
{
for (unsigned i = this->forbids(ftype).size(); i > 0; --i)
@@ -157,7 +207,7 @@ class CommandOSForbid : public Command
bool created = false;
if (d == NULL)
{
- d = new ForbidData();
+ d = new ForbidDataImpl();
created = true;
}
@@ -379,7 +429,7 @@ class OSForbid : public Module
public:
OSForbid(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- forbidService(this), forbiddata_type("ForbidData", ForbidData::Unserialize), commandosforbid(this)
+ forbidService(this), forbiddata_type("ForbidData", ForbidDataImpl::Unserialize), commandosforbid(this)
{
}
diff --git a/modules/commands/os_ignore.cpp b/modules/commands/os_ignore.cpp
index b4d4b09a3..e00b4dd31 100644
--- a/modules/commands/os_ignore.cpp
+++ b/modules/commands/os_ignore.cpp
@@ -12,61 +12,94 @@
#include "module.h"
#include "modules/os_ignore.h"
+struct IgnoreDataImpl : IgnoreData, Serializable
+{
+ IgnoreDataImpl() : Serializable("IgnoreData") { }
+ ~IgnoreDataImpl();
+ void Serialize(Serialize::Data &data) const anope_override;
+ static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
+};
+
+IgnoreDataImpl::~IgnoreDataImpl()
+{
+ if (ignore_service)
+ ignore_service->DelIgnore(this);
+}
+
+void IgnoreDataImpl::Serialize(Serialize::Data &data) const
+{
+ data["mask"] << this->mask;
+ data["creator"] << this->creator;
+ data["reason"] << this->reason;
+ data["time"] << this->time;
+}
+
+Serializable* IgnoreDataImpl::Unserialize(Serializable *obj, Serialize::Data &data)
+{
+ if (!ignore_service)
+ return NULL;
+
+ IgnoreDataImpl *ign;
+ if (obj)
+ ign = anope_dynamic_static_cast<IgnoreDataImpl *>(obj);
+ else
+ {
+ ign = new IgnoreDataImpl();
+ ignore_service->AddIgnore(ign);
+ }
+
+ data["mask"] >> ign->mask;
+ data["creator"] >> ign->creator;
+ data["reason"] >> ign->reason;
+ data["time"] >> ign->time;
+
+ return ign;
+}
+
+
class OSIgnoreService : public IgnoreService
{
+ Serialize::Checker<std::vector<IgnoreData *> > ignores;
+
public:
- OSIgnoreService(Module *o) : IgnoreService(o) { }
+ OSIgnoreService(Module *o) : IgnoreService(o), ignores("IgnoreData") { }
- IgnoreData* AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime) anope_override
+ void AddIgnore(IgnoreData *ign) anope_override
{
- /* Check if we already got an identical entry. */
- IgnoreData *ign = this->Find(mask);
- if (ign != NULL)
- {
- if (!delta)
- ign->time = 0;
- else
- ign->time = Anope::CurTime + delta;
- return ign;
- }
- /* Create new entry.. */
- else
- {
- IgnoreData newign;
- newign.mask = mask;
- newign.creator = creator;
- newign.reason = reason;
- newign.time = delta ? Anope::CurTime + delta : 0;
- this->ignores.push_back(newign);
- return &this->ignores.back();
- }
+ ignores->push_back(ign);
}
- bool DelIgnore(const Anope::string &mask) anope_override
+ void DelIgnore(IgnoreData *ign) anope_override
{
- for (std::list<IgnoreData>::iterator it = this->ignores.begin(), it_end = this->ignores.end(); it != it_end; ++it)
+ std::vector<IgnoreData *>::iterator it = std::find(ignores->begin(), ignores->end(), ign);
+ if (it != ignores->end())
+ ignores->erase(it);
+ }
+
+ void ClearIgnores() anope_override
+ {
+ for (unsigned i = ignores->size(); i > 0; --i)
{
- IgnoreData &idn = *it;
- if (idn.mask.equals_ci(mask))
- {
- this->ignores.erase(it);
- return true;
- }
+ IgnoreData *ign = ignores->at(i - 1);
+ delete ign;
}
+ }
- return false;
+ IgnoreData *Create() anope_override
+ {
+ return new IgnoreDataImpl();
}
IgnoreData *Find(const Anope::string &mask) anope_override
{
User *u = User::Find(mask, true);
- std::list<IgnoreData>::iterator ign = this->ignores.begin(), ign_end = this->ignores.end();
+ std::vector<IgnoreData *>::iterator ign = this->ignores->begin(), ign_end = this->ignores->end();
if (u)
{
for (; ign != ign_end; ++ign)
{
- Entry ignore_mask("", ign->mask);
+ Entry ignore_mask("", (*ign)->mask);
if (ignore_mask.Matches(u, true))
break;
}
@@ -94,26 +127,31 @@ class OSIgnoreService : public IgnoreService
tmp = mask + "!*@*";
for (; ign != ign_end; ++ign)
- if (Anope::Match(tmp, ign->mask, false, true))
+ if (Anope::Match(tmp, (*ign)->mask, false, true))
break;
}
/* Check whether the entry has timed out */
if (ign != ign_end)
{
- IgnoreData &id = *ign;
+ IgnoreData *id = *ign;
- if (id.time && !Anope::NoExpire && id.time <= Anope::CurTime)
+ if (id->time && !Anope::NoExpire && id->time <= Anope::CurTime)
{
- Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id.mask;
- this->ignores.erase(ign);
+ Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->mask;
+ delete id;
}
else
- return &id;
+ return id;
}
return NULL;
}
+
+ std::vector<IgnoreData *> &GetIgnores() anope_override
+ {
+ return *ignores;
+ }
};
class CommandOSIgnore : public Command
@@ -183,7 +221,13 @@ class CommandOSIgnore : public Command
if (Anope::ReadOnly)
source.Reply(READ_ONLY_MODE);
- ignore_service->AddIgnore(mask, source.GetNick(), reason, t);
+ IgnoreData *ign = new IgnoreDataImpl();
+ ign->mask = mask;
+ ign->creator = source.GetNick();
+ ign->reason = reason;
+ ign->time = t ? Anope::CurTime + t : 0;
+
+ ignore_service->AddIgnore(ign);
if (!t)
{
source.Reply(_("\002%s\002 will now permanently be ignored."), mask.c_str());
@@ -202,18 +246,15 @@ class CommandOSIgnore : public Command
if (!ignore_service)
return;
- std::list<IgnoreData> &ignores = ignore_service->GetIgnores();
-
- for (std::list<IgnoreData>::iterator it = ignores.begin(), next_it; it != ignores.end(); it = next_it)
+ std::vector<IgnoreData *> &ignores = ignore_service->GetIgnores();
+ for (unsigned i = ignores.size(); i > 0; --i)
{
- IgnoreData &id = *it;
- next_it = it;
- ++next_it;
+ IgnoreData *id = ignores[i - 1];
- if (id.time && !Anope::NoExpire && id.time <= Anope::CurTime)
+ if (id->time && !Anope::NoExpire && id->time <= Anope::CurTime)
{
- Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id.mask;
- ignores.erase(it);
+ Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->mask;
+ delete id;
}
}
@@ -223,15 +264,16 @@ class CommandOSIgnore : public Command
{
ListFormatter list(source.GetAccount());
list.AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Reason")).AddColumn(_("Expires"));
- for (std::list<IgnoreData>::const_iterator ign = ignores.begin(), ign_end = ignores.end(); ign != ign_end; ++ign)
+
+ for (unsigned i = ignores.size(); i > 0; --i)
{
- const IgnoreData &ignore = *ign;
+ const IgnoreData *ignore = ignores[i - 1];
ListFormatter::ListEntry entry;
- entry["Mask"] = ignore.mask;
- entry["Creator"] = ignore.creator;
- entry["Reason"] = ignore.reason;
- entry["Expires"] = Anope::Expires(ignore.time, source.GetAccount());
+ entry["Mask"] = ignore->mask;
+ entry["Creator"] = ignore->creator;
+ entry["Reason"] = ignore->reason;
+ entry["Expires"] = Anope::Expires(ignore->time, source.GetAccount());
list.AddEntry(entry);
}
@@ -264,13 +306,15 @@ class CommandOSIgnore : public Command
return;
}
- if (ignore_service->DelIgnore(mask))
+ IgnoreData *ign = ignore_service->Find(mask);
+ if (ign)
{
if (Anope::ReadOnly)
source.Reply(READ_ONLY_MODE);
Log(LOG_ADMIN, source, this) << "to remove an ignore on " << mask;
source.Reply(_("\002%s\002 will no longer be ignored."), mask.c_str());
+ delete ign;
}
else
source.Reply(_("\002%s\002 not found on ignore list."), mask.c_str());
@@ -355,7 +399,7 @@ class OSIgnore : public Module
public:
OSIgnore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- ignoredata_type("IgnoreData", IgnoreData::Unserialize), osignoreservice(this), commandosignore(this)
+ ignoredata_type("IgnoreData", IgnoreDataImpl::Unserialize), osignoreservice(this), commandosignore(this)
{
}
diff --git a/modules/commands/os_session.cpp b/modules/commands/os_session.cpp
index 8f5abdc1d..d3e82b04a 100644
--- a/modules/commands/os_session.cpp
+++ b/modules/commands/os_session.cpp
@@ -668,7 +668,7 @@ class OSSession : public Module
if (u->Quitting() || !session_limit || exempt || !u->server || u->server->IsULined())
return;
- cidr u_ip(u->ip);
+ cidr u_ip(u->ip, u->ip.find(':') != Anope::string::npos ? ipv6_cidr : ipv4_cidr);
if (!u_ip.valid())
return;
diff --git a/modules/database/db_old.cpp b/modules/database/db_old.cpp
index 8c322d02e..8fe57cfdd 100644
--- a/modules/database/db_old.cpp
+++ b/modules/database/db_old.cpp
@@ -620,9 +620,18 @@ static void LoadNicks()
if (tmpu16 & OLD_NS_VERBOTEN)
{
if (!forbid)
+ {
+ delete nc;
+ continue;
+ }
+
+ if (nc->display.find_first_of("?*") != Anope::string::npos)
+ {
+ delete nc;
continue;
+ }
- ForbidData *d = new ForbidData();
+ ForbidData *d = forbid->CreateForbid();
d->mask = nc->display;
d->creator = last_usermask;
d->reason = last_realname;
@@ -783,7 +792,7 @@ static void LoadChannels()
if (tmpu32 & OLD_CI_SECURE)
ci->Extend<bool>("CS_SECURE");
if (tmpu32 & OLD_CI_NO_EXPIRE)
- ci->Extend<bool>("CI_NO_EXPIRE");
+ ci->Extend<bool>("CS_NO_EXPIRE");
if (tmpu32 & OLD_CI_MEMO_HARDMAX)
ci->Extend<bool>("MEMO_HARDMAX");
if (tmpu32 & OLD_CI_SECUREFOUNDER)
@@ -1029,9 +1038,18 @@ static void LoadChannels()
if (forbid_chan)
{
if (!forbid)
+ {
+ delete ci;
+ continue;
+ }
+
+ if (ci->name.find_first_of("?*") != Anope::string::npos)
+ {
+ delete ci;
continue;
+ }
- ForbidData *d = new ForbidData();
+ ForbidData *d = forbid->CreateForbid();
d->mask = ci->name;
d->creator = forbidby;
d->reason = forbidreason;
diff --git a/modules/encryption/enc_md5.cpp b/modules/encryption/enc_md5.cpp
index ae51e0394..b56f03324 100644
--- a/modules/encryption/enc_md5.cpp
+++ b/modules/encryption/enc_md5.cpp
@@ -12,7 +12,7 @@
*/
#include "module.h"
-#include "encryption.h"
+#include "modules/encryption.h"
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
diff --git a/modules/encryption/enc_old.cpp b/modules/encryption/enc_old.cpp
index e56224e22..c8c1093da 100644
--- a/modules/encryption/enc_old.cpp
+++ b/modules/encryption/enc_old.cpp
@@ -10,7 +10,7 @@
*/
#include "module.h"
-#include "encryption.h"
+#include "modules/encryption.h"
static ServiceReference<Encryption::Provider> md5("Encryption::Provider", "md5");
diff --git a/modules/encryption/enc_sha1.cpp b/modules/encryption/enc_sha1.cpp
index 4ef3e51fe..38f32b2cb 100644
--- a/modules/encryption/enc_sha1.cpp
+++ b/modules/encryption/enc_sha1.cpp
@@ -15,7 +15,7 @@ A million repetitions of "a"
/* #define LITTLE_ENDIAN * This should be #define'd if true. */
#include "module.h"
-#include "encryption.h"
+#include "modules/encryption.h"
union CHAR64LONG16
{
diff --git a/modules/encryption/enc_sha256.cpp b/modules/encryption/enc_sha256.cpp
index 7533c2891..cccbceea1 100644
--- a/modules/encryption/enc_sha256.cpp
+++ b/modules/encryption/enc_sha256.cpp
@@ -48,7 +48,7 @@
*/
#include "module.h"
-#include "encryption.h"
+#include "modules/encryption.h"
static const unsigned SHA256_DIGEST_SIZE = 256 / 8;
static const unsigned SHA256_BLOCK_SIZE = 512 / 8;
diff --git a/modules/extra/enc_bcrypt.cpp b/modules/extra/enc_bcrypt.cpp
index 67f2e8bef..cd5e05c35 100644
--- a/modules/extra/enc_bcrypt.cpp
+++ b/modules/extra/enc_bcrypt.cpp
@@ -1,7 +1,7 @@
/* RequiredLibraries: xcrypt */
#include "module.h"
-#include "encryption.h"
+#include "modules/encryption.h"
#include <xcrypt.h>
class EBCRYPT : public Module
diff --git a/modules/extra/m_ssl_gnutls.cpp b/modules/extra/m_ssl_gnutls.cpp
new file mode 100644
index 000000000..002015f5f
--- /dev/null
+++ b/modules/extra/m_ssl_gnutls.cpp
@@ -0,0 +1,509 @@
+/*
+ * (C) 2014 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ */
+
+/* RequiredLibraries: gnutls */
+
+#include "module.h"
+#include "modules/ssl.h"
+
+#include <errno.h>
+#include <gnutls/gnutls.h>
+
+class GnuTLSModule;
+static GnuTLSModule *me;
+
+class MySSLService : public SSLService
+{
+ public:
+ MySSLService(Module *o, const Anope::string &n);
+
+ /** Initialize a socket to use SSL
+ * @param s The socket
+ */
+ void Init(Socket *s) anope_override;
+};
+
+class SSLSocketIO : public SocketIO
+{
+ public:
+ gnutls_session_t sess;
+
+ /** Constructor
+ */
+ SSLSocketIO() : sess(NULL) { }
+
+ /** Really receive something from the buffer
+ * @param s The socket
+ * @param buf The buf to read to
+ * @param sz How much to read
+ * @return Number of bytes received
+ */
+ int Recv(Socket *s, char *buf, size_t sz) anope_override;
+
+ /** Write something to the socket
+ * @param s The socket
+ * @param buf The data to write
+ * @param size The length of the data
+ */
+ int Send(Socket *s, const char *buf, size_t sz) anope_override;
+
+ /** Accept a connection from a socket
+ * @param s The socket
+ * @return The new socket
+ */
+ ClientSocket *Accept(ListenSocket *s) anope_override;
+
+ /** Finished accepting a connection from a socket
+ * @param s The socket
+ * @return SF_ACCEPTED if accepted, SF_ACCEPTING if still in process, SF_DEAD on error
+ */
+ SocketFlag FinishAccept(ClientSocket *cs) anope_override;
+
+ /** Connect the socket
+ * @param s THe socket
+ * @param target IP to connect to
+ * @param port to connect to
+ */
+ void Connect(ConnectionSocket *s, const Anope::string &target, int port) anope_override;
+
+ /** Called to potentially finish a pending connection
+ * @param s The socket
+ * @return SF_CONNECTED on success, SF_CONNECTING if still pending, and SF_DEAD on error.
+ */
+ SocketFlag FinishConnect(ConnectionSocket *s) anope_override;
+
+ /** Called when the socket is destructing
+ */
+ void Destroy() anope_override;
+};
+
+namespace GnuTLS
+{
+ class Init
+ {
+ public:
+ Init() { gnutls_global_init(); }
+ ~Init() { gnutls_global_deinit(); }
+ };
+
+ /** Used to create a gnutls_datum_t* from an Anope::string
+ */
+ class Datum
+ {
+ gnutls_datum_t datum;
+
+ public:
+ Datum(const Anope::string &dat)
+ {
+ datum.data = reinterpret_cast<unsigned char *>(const_cast<char *>(dat.data()));
+ datum.size = static_cast<unsigned int>(dat.length());
+ }
+
+ const gnutls_datum_t *get() const { return &datum; }
+ };
+
+ class DHParams
+ {
+ gnutls_dh_params_t dh_params;
+
+ public:
+ DHParams() : dh_params(NULL) { }
+
+ void Import(const Anope::string &dhstr)
+ {
+ if (dh_params != NULL)
+ {
+ gnutls_dh_params_deinit(dh_params);
+ dh_params = NULL;
+ }
+
+ int ret = gnutls_dh_params_init(&dh_params);
+ if (ret < 0)
+ throw ConfigException("Unable to initialize DH parameters");
+
+ ret = gnutls_dh_params_import_pkcs3(dh_params, Datum(dhstr).get(), GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ {
+ gnutls_dh_params_deinit(dh_params);
+ dh_params = NULL;
+ throw ConfigException("Unable to import DH parameters");
+ }
+ }
+
+ ~DHParams()
+ {
+ if (dh_params)
+ gnutls_dh_params_deinit(dh_params);
+ }
+
+ gnutls_dh_params_t get() const { return dh_params; }
+ };
+
+ class X509CertCredentials
+ {
+ gnutls_certificate_credentials_t cred;
+ DHParams dh;
+
+ public:
+ X509CertCredentials()
+ {
+ if (gnutls_certificate_allocate_credentials(&cred) < 0)
+ throw ConfigException("Cannot allocate certificate credentials");
+ }
+
+ ~X509CertCredentials()
+ {
+ gnutls_certificate_free_credentials(cred);
+ }
+
+ void SetupSession(gnutls_session_t sess)
+ {
+ gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, cred);
+ gnutls_set_default_priority(sess);
+ }
+
+ void SetCertAndKey(const Anope::string &certfile, const Anope::string &keyfile)
+ {
+ int ret = gnutls_certificate_set_x509_key_file(cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ throw ConfigException("Unable to load certificate/private key: " + Anope::string(gnutls_strerror(ret)));
+ }
+
+ void SetDH(const Anope::string &dhfile)
+ {
+ std::ifstream ifs(dhfile.c_str());
+ const Anope::string dhdata((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
+
+ dh.Import(dhdata);
+ gnutls_certificate_set_dh_params(cred, dh.get());
+ }
+
+ bool HasDH() const
+ {
+ return (dh.get() != NULL);
+ }
+ };
+}
+
+class GnuTLSModule : public Module
+{
+ GnuTLS::Init libinit;
+
+ public:
+ GnuTLS::X509CertCredentials cred;
+ MySSLService service;
+
+ GnuTLSModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), service(this, "ssl")
+ {
+ me = this;
+ this->SetPermanent(true);
+ }
+
+ ~GnuTLSModule()
+ {
+ for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
+ {
+ Socket *s = it->second;
+ ++it;
+
+ if (dynamic_cast<SSLSocketIO *>(s->io))
+ delete s;
+ }
+ }
+
+ static void CheckFile(const Anope::string &filename)
+ {
+ if (!Anope::IsFile(filename.c_str()))
+ {
+ Log() << "File does not exist: " << filename;
+ throw ConfigException("Error loading certificate/private key");
+ }
+ }
+
+ void OnReload(Configuration::Conf *conf) anope_override
+ {
+ Configuration::Block *config = conf->GetModule(this);
+
+ const Anope::string certfile = config->Get<const Anope::string>("cert", "data/anope.crt");
+ const Anope::string keyfile = config->Get<const Anope::string>("key", "data/anope.key");
+ const Anope::string dhfile = config->Get<const Anope::string>("dh", "data/dhparams.pem");
+
+ CheckFile(certfile);
+ CheckFile(keyfile);
+
+ // DH params is not mandatory
+ if (Anope::IsFile(dhfile.c_str()))
+ {
+ cred.SetDH(dhfile);
+ Log(LOG_DEBUG) << "m_ssl_gnutls: Successfully loaded DH parameters from " << dhfile;
+ }
+
+ cred.SetCertAndKey(certfile, keyfile);
+ Log(LOG_DEBUG) << "m_ssl_gnutls: Successfully loaded certificate " << certfile << " and private key " << keyfile;
+ }
+
+ void OnPreServerConnect() anope_override
+ {
+ Configuration::Block *config = Config->GetBlock("uplink", Anope::CurrentUplink);
+
+ if (config->Get<bool>("ssl"))
+ {
+ this->service.Init(UplinkSock);
+ }
+ }
+};
+
+MySSLService::MySSLService(Module *o, const Anope::string &n) : SSLService(o, n)
+{
+}
+
+void MySSLService::Init(Socket *s)
+{
+ if (s->io != &NormalSocketIO)
+ throw CoreException("Socket initializing SSL twice");
+
+ s->io = new SSLSocketIO();
+}
+
+int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
+{
+ int ret = gnutls_record_recv(this->sess, buf, sz);
+
+ if (ret > 0)
+ TotalRead += ret;
+ else if (ret < 0)
+ {
+ switch (ret)
+ {
+ case GNUTLS_E_AGAIN:
+ case GNUTLS_E_INTERRUPTED:
+ SocketEngine::SetLastError(EAGAIN);
+ break;
+ default:
+ if (s == UplinkSock)
+ {
+ // Log and fake an errno because this is a fatal error on the uplink socket
+ Log() << "SSL error: " << gnutls_strerror(ret);
+ }
+ SocketEngine::SetLastError(ECONNRESET);
+ }
+ }
+
+ return ret;
+}
+
+int SSLSocketIO::Send(Socket *s, const char *buf, size_t sz)
+{
+ int ret = gnutls_record_send(this->sess, buf, sz);
+
+ if (ret > 0)
+ TotalWritten += ret;
+ else
+ {
+ switch (ret)
+ {
+ case 0:
+ case GNUTLS_E_AGAIN:
+ case GNUTLS_E_INTERRUPTED:
+ SocketEngine::SetLastError(EAGAIN);
+ break;
+ default:
+ if (s == UplinkSock)
+ {
+ // Log and fake an errno because this is a fatal error on the uplink socket
+ Log() << "SSL error: " << gnutls_strerror(ret);
+ }
+ SocketEngine::SetLastError(ECONNRESET);
+ }
+ }
+
+ return ret;
+}
+
+ClientSocket *SSLSocketIO::Accept(ListenSocket *s)
+{
+ if (s->io == &NormalSocketIO)
+ throw SocketException("Attempting to accept on uninitialized socket with SSL");
+
+ sockaddrs conaddr;
+
+ socklen_t size = sizeof(conaddr);
+ int newsock = accept(s->GetFD(), &conaddr.sa, &size);
+
+#ifndef INVALID_SOCKET
+ const int INVALID_SOCKET = -1;
+#endif
+
+ if (newsock < 0 || newsock == INVALID_SOCKET)
+ throw SocketException("Unable to accept connection: " + Anope::LastError());
+
+ ClientSocket *newsocket = s->OnAccept(newsock, conaddr);
+ me->service.Init(newsocket);
+ SSLSocketIO *io = anope_dynamic_static_cast<SSLSocketIO *>(newsocket->io);
+
+ if (gnutls_init(&io->sess, GNUTLS_SERVER) != GNUTLS_E_SUCCESS)
+ throw SocketException("Unable to initialize SSL socket");
+
+ me->cred.SetupSession(io->sess);
+ gnutls_transport_set_int(io->sess, newsock);
+
+ newsocket->flags[SF_ACCEPTING] = true;
+ this->FinishAccept(newsocket);
+
+ return newsocket;
+}
+
+SocketFlag SSLSocketIO::FinishAccept(ClientSocket *cs)
+{
+ if (cs->io == &NormalSocketIO)
+ throw SocketException("Attempting to finish connect uninitialized socket with SSL");
+ else if (cs->flags[SF_ACCEPTED])
+ return SF_ACCEPTED;
+ else if (!cs->flags[SF_ACCEPTING])
+ throw SocketException("SSLSocketIO::FinishAccept called for a socket not accepted nor accepting?");
+
+ SSLSocketIO *io = anope_dynamic_static_cast<SSLSocketIO *>(cs->io);
+
+ int ret = gnutls_handshake(io->sess);
+ if (ret < 0)
+ {
+ if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
+ {
+ // gnutls_handshake() wants to read or write again;
+ // if gnutls_record_get_direction() returns 0 it wants to read, otherwise it wants to write.
+ if (gnutls_record_get_direction(io->sess) == 0)
+ {
+ SocketEngine::Change(cs, false, SF_WRITABLE);
+ SocketEngine::Change(cs, true, SF_READABLE);
+ }
+ else
+ {
+ SocketEngine::Change(cs, true, SF_WRITABLE);
+ SocketEngine::Change(cs, false, SF_READABLE);
+ }
+ return SF_ACCEPTING;
+ }
+ else
+ {
+ cs->OnError(Anope::string(gnutls_strerror(ret)));
+ cs->flags[SF_DEAD] = true;
+ cs->flags[SF_ACCEPTING] = false;
+ return SF_DEAD;
+ }
+ }
+ else
+ {
+ cs->flags[SF_ACCEPTED] = true;
+ cs->flags[SF_ACCEPTING] = false;
+ SocketEngine::Change(cs, false, SF_WRITABLE);
+ SocketEngine::Change(cs, true, SF_READABLE);
+ cs->OnAccept();
+ return SF_ACCEPTED;
+ }
+}
+
+void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int port)
+{
+ if (s->io == &NormalSocketIO)
+ throw SocketException("Attempting to connect uninitialized socket with SSL");
+
+ s->flags[SF_CONNECTING] = s->flags[SF_CONNECTED] = false;
+
+ s->conaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, target, port);
+ int c = connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size());
+ if (c == -1)
+ {
+ if (Anope::LastErrorCode() != EINPROGRESS)
+ {
+ s->OnError(Anope::LastError());
+ s->flags[SF_DEAD] = true;
+ return;
+ }
+ else
+ {
+ SocketEngine::Change(s, true, SF_WRITABLE);
+ s->flags[SF_CONNECTING] = true;
+ return;
+ }
+ }
+ else
+ {
+ s->flags[SF_CONNECTING] = true;
+ this->FinishConnect(s);
+ }
+}
+
+SocketFlag SSLSocketIO::FinishConnect(ConnectionSocket *s)
+{
+ if (s->io == &NormalSocketIO)
+ throw SocketException("Attempting to finish connect uninitialized socket with SSL");
+ else if (s->flags[SF_CONNECTED])
+ return SF_CONNECTED;
+ else if (!s->flags[SF_CONNECTING])
+ throw SocketException("SSLSocketIO::FinishConnect called for a socket not connected nor connecting?");
+
+ SSLSocketIO *io = anope_dynamic_static_cast<SSLSocketIO *>(s->io);
+
+ if (io->sess == NULL)
+ {
+ if (gnutls_init(&io->sess, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS)
+ throw SocketException("Unable to initialize SSL socket");
+ me->cred.SetupSession(io->sess);
+ gnutls_transport_set_int(io->sess, s->GetFD());
+ }
+
+ int ret = gnutls_handshake(io->sess);
+ if (ret < 0)
+ {
+ if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
+ {
+ // gnutls_handshake() wants to read or write again;
+ // if gnutls_record_get_direction() returns 0 it wants to read, otherwise it wants to write.
+ if (gnutls_record_get_direction(io->sess) == 0)
+ {
+ SocketEngine::Change(s, false, SF_WRITABLE);
+ SocketEngine::Change(s, true, SF_READABLE);
+ }
+ else
+ {
+ SocketEngine::Change(s, true, SF_WRITABLE);
+ SocketEngine::Change(s, false, SF_READABLE);
+ }
+
+ return SF_CONNECTING;
+ }
+ else
+ {
+ s->OnError(Anope::string(gnutls_strerror(ret)));
+ s->flags[SF_CONNECTING] = false;
+ s->flags[SF_DEAD] = true;
+ return SF_DEAD;
+ }
+ }
+ else
+ {
+ s->flags[SF_CONNECTING] = false;
+ s->flags[SF_CONNECTED] = true;
+ SocketEngine::Change(s, false, SF_WRITABLE);
+ SocketEngine::Change(s, true, SF_READABLE);
+ s->OnConnect();
+ return SF_CONNECTED;
+ }
+}
+
+void SSLSocketIO::Destroy()
+{
+ if (this->sess)
+ {
+ gnutls_bye(this->sess, GNUTLS_SHUT_WR);
+ gnutls_deinit(this->sess);
+ }
+
+ delete this;
+}
+
+MODULE_INIT(GnuTLSModule)
diff --git a/modules/extra/m_ssl.cpp b/modules/extra/m_ssl_openssl.cpp
index 44971908c..a274dc78d 100644
--- a/modules/extra/m_ssl.cpp
+++ b/modules/extra/m_ssl_openssl.cpp
@@ -137,7 +137,7 @@ class SSLModule : public Module
if (!SSL_CTX_use_certificate_file(client_ctx, this->certfile.c_str(), SSL_FILETYPE_PEM) || !SSL_CTX_use_certificate_file(server_ctx, this->certfile.c_str(), SSL_FILETYPE_PEM))
throw ConfigException("Error loading certificate");
else
- Log(LOG_DEBUG) << "m_ssl: Successfully loaded certificate " << this->certfile;
+ Log(LOG_DEBUG) << "m_ssl_openssl: Successfully loaded certificate " << this->certfile;
}
else
Log() << "Unable to open certificate " << this->certfile;
@@ -147,7 +147,7 @@ class SSLModule : public Module
if (!SSL_CTX_use_PrivateKey_file(client_ctx, this->keyfile.c_str(), SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(server_ctx, this->keyfile.c_str(), SSL_FILETYPE_PEM))
throw ConfigException("Error loading private key");
else
- Log(LOG_DEBUG) << "m_ssl: Successfully loaded private key " << this->keyfile;
+ Log(LOG_DEBUG) << "m_ssl_openssl: Successfully loaded private key " << this->keyfile;
}
else
{
diff --git a/modules/m_httpd.cpp b/modules/m_httpd.cpp
index e08452d81..f3d0677a9 100644
--- a/modules/m_httpd.cpp
+++ b/modules/m_httpd.cpp
@@ -454,9 +454,6 @@ class HTTPD : public Module
void OnModuleLoad(User *u, Module *m) anope_override
{
- if (m->name != "m_ssl")
- return;
-
for (std::map<Anope::string, MyHTTPProvider *>::iterator it = this->providers.begin(), it_end = this->providers.end(); it != it_end; ++it)
{
MyHTTPProvider *p = it->second;
diff --git a/modules/webcpanel/template_fileserver.cpp b/modules/webcpanel/template_fileserver.cpp
index d4e5ec7e4..dc950b330 100644
--- a/modules/webcpanel/template_fileserver.cpp
+++ b/modules/webcpanel/template_fileserver.cpp
@@ -220,8 +220,11 @@ void TemplateFileServer::Serve(HTTPProvider *server, const Anope::string &page_n
Log() << "Invalid INCLUDE in web template " << this->file_name;
else
{
- reply.Write(finished); // Write out what we have currently so we insert this files contents here
- finished.clear();
+ if (!finished.empty())
+ {
+ reply.Write(finished); // Write out what we have currently so we insert this files contents here
+ finished.clear();
+ }
TemplateFileServer tfs(tokens[1]);
tfs.Serve(server, page_name, client, message, reply, r);
@@ -255,7 +258,7 @@ void TemplateFileServer::Serve(HTTPProvider *server, const Anope::string &page_n
}
}
- reply.Write(finished);
- return;
+ if (!finished.empty())
+ reply.Write(finished);
}
diff --git a/src/socket_transport.cpp b/src/socket_transport.cpp
index 6293ea385..1476d0662 100644
--- a/src/socket_transport.cpp
+++ b/src/socket_transport.cpp
@@ -167,6 +167,8 @@ bool BinarySocket::ProcessWrite()
void BinarySocket::Write(const char *buffer, size_t l)
{
+ if (l == 0)
+ return;
this->write_buffer.push_back(new DataBlock(buffer, l));
SocketEngine::Change(this, true, SF_WRITABLE);
}
diff --git a/src/sockets.cpp b/src/sockets.cpp
index 948f3e238..f50092744 100644
--- a/src/sockets.cpp
+++ b/src/sockets.cpp
@@ -517,7 +517,7 @@ ListenSocket::ListenSocket(const Anope::string &bindip, int port, bool i)
{
this->SetBlocking(false);
- const char op = 1;
+ int op = 1;
setsockopt(this->GetFD(), SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op));
this->bindaddr.pton(i ? AF_INET6 : AF_INET, bindip, port);