mirror of
https://github.com/anope/anope.git
synced 2026-07-04 21:13:12 +02:00
Add os_dns, a way to control your DNS zone via services
This commit is contained in:
@@ -281,6 +281,13 @@ networkinfo
|
||||
*/
|
||||
options
|
||||
{
|
||||
/*
|
||||
* On Linux/UNIX systems Anope can setuid and setgid to this user and group
|
||||
* after starting up. This is useful if Anope has to bind to privileged ports
|
||||
*/
|
||||
#user = "anope"
|
||||
#group = "anope"
|
||||
|
||||
/*
|
||||
* The case mapping used by services. This must be set to a valid locale name
|
||||
* installed on your machine. Services use this case map to compare, with
|
||||
@@ -1047,6 +1054,15 @@ dns
|
||||
* How long to wait in seconds before a DNS query has timed out
|
||||
*/
|
||||
timeout = 5
|
||||
|
||||
/*
|
||||
* The port services use to listen for DNS queries.
|
||||
* Note that ports less than 1024 are privileged on UNIX/Linux systems, and
|
||||
* require Anope to be started as root. If you do this, it is recommended you
|
||||
* set options:user and options:group so Anope can change users after binding
|
||||
* to this port.
|
||||
*/
|
||||
port = 53
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -355,15 +355,61 @@ defcon
|
||||
}
|
||||
|
||||
/*
|
||||
* os_list
|
||||
* os_dns
|
||||
*
|
||||
* Provides the commands operserv/chanlist and operserv/userlist.
|
||||
* Provides the command operserv/dns.
|
||||
*
|
||||
* Used to list and search the channels and users currently on the network.
|
||||
* This module allows controlling a DNS zone. This is useful for
|
||||
* controlling what servers users are placed on for load balancing,
|
||||
* and to automatically remove split servers.
|
||||
*
|
||||
* To use this module you must set a nameserver record for services
|
||||
* so that DNS queries go to services.
|
||||
*
|
||||
* We recommend you use something similar to BIND's query forwarding
|
||||
* ability to hide service's IP, provide query caching, and provide
|
||||
* better fault tolerance. To do this, configure BIND similar to:
|
||||
*
|
||||
* options {
|
||||
* dnssec-enable no;
|
||||
* dnssec-validation no;
|
||||
* };
|
||||
* zone "irc.example.com" IN {
|
||||
* type forward;
|
||||
* forward first;
|
||||
* forwarders { 10.0.0.1 port 5353; }; # Where this is the IP and dns:port of services
|
||||
* };
|
||||
*
|
||||
* And then set a NS record for irc.example.com. to BIND.
|
||||
*/
|
||||
module { name = "os_list" }
|
||||
command { service = "OperServ"; name = "CHANLIST"; command = "operserv/chanlist"; }
|
||||
command { service = "OperServ"; name = "USERLIST"; command = "operserv/userlist"; }
|
||||
#module { name = "os_dns" }
|
||||
#command { service = "OperServ"; name = "DNS"; command = "operserv/dns"; permission = "operserv/dns"; }
|
||||
os_dns
|
||||
{
|
||||
/* TTL for records. This should be very low if your records change often. */
|
||||
ttl = 1m
|
||||
|
||||
/* If a server drops this many users the server is automatically removed from the DNS zone.
|
||||
* This directive is optional.
|
||||
*/
|
||||
user_drop_mark = 50
|
||||
|
||||
/* The time used for user_drop_mark */
|
||||
user_drop_time = 1m
|
||||
|
||||
/* When a server is removed from the zone for dropping users, it is readded after this time.
|
||||
* This directive is optional.
|
||||
*/
|
||||
user_drop_readd_time = 5m
|
||||
|
||||
/* If set, if a server splits it is automatically removed from the zone */
|
||||
remove_split_servers = yes
|
||||
|
||||
/* If set, when a server connects to the network it will be automatically added to
|
||||
* the zone if it is a known server.
|
||||
*/
|
||||
readd_connected_servers = no
|
||||
}
|
||||
|
||||
/*
|
||||
* os_config
|
||||
@@ -425,6 +471,17 @@ command { service = "OperServ"; name = "KICK"; command = "operserv/kick"; permis
|
||||
module { name = "os_kill" }
|
||||
command { service = "OperServ"; name = "KILL"; command = "operserv/kill"; permission = "operserv/kill"; }
|
||||
|
||||
/*
|
||||
* os_list
|
||||
*
|
||||
* Provides the commands operserv/chanlist and operserv/userlist.
|
||||
*
|
||||
* Used to list and search the channels and users currently on the network.
|
||||
*/
|
||||
module { name = "os_list" }
|
||||
command { service = "OperServ"; name = "CHANLIST"; command = "operserv/chanlist"; }
|
||||
command { service = "OperServ"; name = "USERLIST"; command = "operserv/userlist"; }
|
||||
|
||||
/*
|
||||
* os_login
|
||||
*
|
||||
|
||||
+7
-1
@@ -394,6 +394,10 @@ class CoreExport ServerConfig
|
||||
/* Max length of channel names */
|
||||
unsigned ChanLen;
|
||||
|
||||
/* User and group to run as */
|
||||
Anope::string User;
|
||||
Anope::string Group;
|
||||
|
||||
/* Casemapping to use */
|
||||
Anope::string CaseMap;
|
||||
|
||||
@@ -494,8 +498,10 @@ class CoreExport ServerConfig
|
||||
|
||||
/* Nameserver to use for resolving hostnames */
|
||||
Anope::string NameServer;
|
||||
/* TIme before a DNS query is considered dead */
|
||||
/* Time before a DNS query is considered dead */
|
||||
time_t DNSTimeout;
|
||||
/* The port DNS queries come in on */
|
||||
int DNSPort;
|
||||
|
||||
/* Prefix of guest nicks when a user gets forced off of a nick */
|
||||
Anope::string NSGuestNickPrefix;
|
||||
|
||||
+21
-12
@@ -95,7 +95,6 @@ struct CoreExport DNSQuery
|
||||
|
||||
DNSQuery();
|
||||
DNSQuery(const Question &q);
|
||||
DNSQuery(const DNSPacket &p);
|
||||
};
|
||||
|
||||
/** The request
|
||||
@@ -124,7 +123,7 @@ class CoreExport DNSRequest : public Timer, public Question
|
||||
void Tick(time_t) anope_override;
|
||||
};
|
||||
|
||||
/** A full packet sent or recieved to/from the nameserver, may contain multiple queries
|
||||
/** A full packet sent or recieved to/from the nameserver
|
||||
*/
|
||||
class DNSPacket : public DNSQuery
|
||||
{
|
||||
@@ -139,12 +138,14 @@ class DNSPacket : public DNSQuery
|
||||
public:
|
||||
static const int HEADER_LENGTH = 12;
|
||||
|
||||
/* Our 16-bit id for this header */
|
||||
/* Source or destination of the packet */
|
||||
sockaddrs addr;
|
||||
/* ID for this packet */
|
||||
unsigned short id;
|
||||
/* Flags on the query */
|
||||
/* Flags on the packet */
|
||||
unsigned short flags;
|
||||
|
||||
DNSPacket();
|
||||
DNSPacket(const sockaddrs &a);
|
||||
void Fill(const unsigned char *input, const unsigned short len);
|
||||
unsigned short Pack(unsigned char *output, unsigned short output_size);
|
||||
};
|
||||
@@ -155,20 +156,19 @@ class CoreExport DNSManager : public Timer, public Socket
|
||||
{
|
||||
typedef std::multimap<Anope::string, ResourceRecord, ci::less> cache_map;
|
||||
cache_map cache;
|
||||
sockaddrs addrs;
|
||||
public:
|
||||
std::deque<DNSPacket *> packets;
|
||||
std::map<unsigned short, DNSRequest *> requests;
|
||||
|
||||
static const int DNSPort = 53;
|
||||
std::deque<DNSPacket *> packets;
|
||||
public:
|
||||
sockaddrs addrs;
|
||||
std::map<unsigned short, DNSRequest *> requests;
|
||||
|
||||
DNSManager(const Anope::string &nameserver, int port);
|
||||
|
||||
~DNSManager();
|
||||
|
||||
bool ProcessRead();
|
||||
bool ProcessRead() anope_override;
|
||||
|
||||
bool ProcessWrite();
|
||||
bool ProcessWrite() anope_override;
|
||||
|
||||
/** Add a record to the dns cache
|
||||
* @param r The record
|
||||
@@ -189,6 +189,15 @@ class CoreExport DNSManager : public Timer, public Socket
|
||||
*/
|
||||
void Cleanup(Module *mod);
|
||||
|
||||
/** Get the list of packets pending to be sent
|
||||
*/
|
||||
std::deque<DNSPacket *>& GetPackets();
|
||||
|
||||
/** Queues a packet for sending
|
||||
* @param p The packet
|
||||
*/
|
||||
void SendPacket(DNSPacket *p);
|
||||
|
||||
/** Does a BLOCKING DNS query and returns the first IP.
|
||||
* Only use this if you know what you are doing. Unless you specifically
|
||||
* need a blocking query use the DNSRequest system
|
||||
|
||||
+6
-1
@@ -917,6 +917,11 @@ class CoreExport Module : public Extensible
|
||||
*/
|
||||
virtual void OnLog(Log *l) { }
|
||||
|
||||
/** Called when a DNS request (question) is recieved.
|
||||
* @param req The dns request
|
||||
*/
|
||||
virtual void OnDnsRequest(DNSPacket &req) { }
|
||||
|
||||
/** Called when a channels modes are being checked to see if they are allowed,
|
||||
* mostly to ensure mlock/+r are set.
|
||||
* @param c The channel
|
||||
@@ -995,7 +1000,7 @@ enum Implementation
|
||||
I_OnServerQuit, I_OnTopicUpdated,
|
||||
I_OnEncrypt, I_OnDecrypt,
|
||||
I_OnChannelModeSet, I_OnChannelModeUnset, I_OnUserModeSet, I_OnUserModeUnset, I_OnChannelModeAdd, I_OnUserModeAdd,
|
||||
I_OnMLock, I_OnUnMLock, I_OnServerSync, I_OnUplinkSync, I_OnBotPrivmsg, I_OnPrivmsg, I_OnLog,
|
||||
I_OnMLock, I_OnUnMLock, I_OnServerSync, I_OnUplinkSync, I_OnBotPrivmsg, I_OnPrivmsg, I_OnLog, I_OnDnsRequest,
|
||||
|
||||
I_OnSerializeCheck, I_OnSerializableConstruct, I_OnSerializableDestruct, I_OnSerializableUpdate,
|
||||
I_END
|
||||
|
||||
@@ -63,6 +63,9 @@ class CoreExport Server : public Flags<ServerFlag>
|
||||
~Server();
|
||||
|
||||
public:
|
||||
/* Number of users on the server */
|
||||
unsigned Users;
|
||||
|
||||
/** Delete this server with a reason
|
||||
* @param reason The reason
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* (C) 2003-2012 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
|
||||
class DNSServer;
|
||||
static std::vector<DNSServer *> dns_servers;
|
||||
|
||||
static std::map<Anope::string, std::list<time_t> > server_quit_times;
|
||||
|
||||
class DNSServer : public Serializable
|
||||
{
|
||||
Anope::string server_name;
|
||||
std::vector<Anope::string> ips;
|
||||
unsigned limit;
|
||||
|
||||
DNSServer() : Serializable("DNSServer"), limit(0), pooled(false), repool(0) { dns_servers.push_back(this); }
|
||||
public:
|
||||
bool pooled;
|
||||
time_t repool;
|
||||
|
||||
DNSServer(const Anope::string &sn) : Serializable("DNSServer"), server_name(sn), limit(0), pooled(false), repool(0)
|
||||
{
|
||||
dns_servers.push_back(this);
|
||||
}
|
||||
|
||||
~DNSServer()
|
||||
{
|
||||
std::vector<DNSServer *>::iterator it = std::find(dns_servers.begin(), dns_servers.end(), this);
|
||||
if (it != dns_servers.end())
|
||||
dns_servers.erase(it);
|
||||
}
|
||||
|
||||
const Anope::string &GetName() const { return server_name; }
|
||||
std::vector<Anope::string> &GetIPs() { return ips; }
|
||||
unsigned GetLimit() const { return limit; }
|
||||
void SetLimit(unsigned l) { limit = l; }
|
||||
|
||||
Serialize::Data serialize() const anope_override
|
||||
{
|
||||
Serialize::Data data;
|
||||
|
||||
data["server_name"] << server_name;
|
||||
for (unsigned i = 0; i < ips.size(); ++i)
|
||||
data["ip" + stringify(i)] << ips[i];
|
||||
data["limit"] << limit;
|
||||
data["pooled"] << pooled;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static Serializable* unserialize(Serializable *obj, Serialize::Data &data)
|
||||
{
|
||||
DNSServer *req;
|
||||
|
||||
if (obj)
|
||||
req = anope_dynamic_static_cast<DNSServer *>(obj);
|
||||
else
|
||||
req = new DNSServer();
|
||||
|
||||
data["server_name"] >> req->server_name;
|
||||
for (unsigned i = 0; data.count("ip" + stringify(i)); ++i)
|
||||
{
|
||||
Anope::string ip_str;
|
||||
data["ip" + stringify(i)] >> ip_str;
|
||||
req->ips.push_back(ip_str);
|
||||
}
|
||||
data["limit"] >> req->limit;
|
||||
data["pooled"] >> req->pooled;
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static DNSServer *Find(const Anope::string &s)
|
||||
{
|
||||
for (unsigned i = 0; i < dns_servers.size(); ++i)
|
||||
if (dns_servers[i]->GetName() == s)
|
||||
return dns_servers[i];
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
class CommandOSDNS : public Command
|
||||
{
|
||||
void DisplayPoolState(CommandSource &source)
|
||||
{
|
||||
if (dns_servers.empty())
|
||||
{
|
||||
source.Reply(_("There are no configured servers."));
|
||||
return;
|
||||
}
|
||||
|
||||
ListFormatter lf;
|
||||
lf.addColumn("Server").addColumn("IP").addColumn("Limit").addColumn("State");
|
||||
for (unsigned i = 0; i < dns_servers.size(); ++i)
|
||||
{
|
||||
DNSServer *s = dns_servers[i];
|
||||
Server *srv = Server::Find(s->GetName());
|
||||
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Server"] = s->GetName();
|
||||
entry["Limit"] = s->GetLimit() ? stringify(s->GetLimit()) : "None";
|
||||
|
||||
Anope::string ip_str;
|
||||
for (unsigned j = 0; j < s->GetIPs().size(); ++j)
|
||||
ip_str += s->GetIPs()[j] + " ";
|
||||
ip_str.trim();
|
||||
if (ip_str.empty())
|
||||
ip_str = "None";
|
||||
entry["IP"] = ip_str;
|
||||
|
||||
if (!srv)
|
||||
entry["State"] = "Split";
|
||||
else if (s->pooled)
|
||||
entry["State"] = "Pooled";
|
||||
else
|
||||
entry["State"] = "Unpooled";
|
||||
|
||||
lf.addEntry(entry);
|
||||
}
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
lf.Process(replies);
|
||||
|
||||
for (unsigned i = 0; i < replies.size(); ++i)
|
||||
source.Reply(replies[i]);
|
||||
}
|
||||
|
||||
void OnAdd(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(params[1]);
|
||||
|
||||
if (s)
|
||||
{
|
||||
source.Reply(_("Server %s already exists."), params[1].c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Server::Find(params[1]))
|
||||
{
|
||||
source.Reply(_("Server %s is not linked to the network."), params[1].c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
s = new DNSServer(params[1]);
|
||||
source.Reply(_("Added server %s."), s->GetName().c_str());
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "to add server " << s->GetName();
|
||||
}
|
||||
|
||||
void OnDel(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(params[1]);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
source.Reply(_("Server %s does not exist."), params[1].c_str());
|
||||
return;
|
||||
}
|
||||
else if (Server::Find(s->GetName()))
|
||||
{
|
||||
source.Reply(_("Server %s must be quit before it can be deleted."), s->GetName().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "to delete server " << s->GetName();
|
||||
source.Reply(_("Removed server %s."), s->GetName().c_str());
|
||||
delete s;
|
||||
}
|
||||
|
||||
void AddIP(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(params[1]);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
source.Reply(_("Server %s does not exist."), params[1].c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < s->GetIPs().size(); ++i)
|
||||
if (params[2].equals_ci(s->GetIPs()[i]))
|
||||
{
|
||||
source.Reply(_("IP %s already exists for %s."), s->GetIPs()[i].c_str(), s->GetName().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
sockaddrs addr;
|
||||
try
|
||||
{
|
||||
addr.pton(AF_INET, params[2]);
|
||||
}
|
||||
catch (const SocketException &)
|
||||
{
|
||||
try
|
||||
{
|
||||
addr.pton(AF_INET6, params[2]);
|
||||
}
|
||||
catch (const SocketException &)
|
||||
{
|
||||
source.Reply(_("%s is not a valid IP address."), params[2].c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
s->GetIPs().push_back(params[2]);
|
||||
source.Reply(_("Added IP %s to %s."), params[2].c_str(), s->GetName().c_str());
|
||||
Log(LOG_ADMIN, source, this) << "to add IP " << params[2] << " to " << s->GetName();
|
||||
}
|
||||
|
||||
void DelIP(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(params[1]);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
source.Reply(_("Server %s does not exist."), params[1].c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < s->GetIPs().size(); ++i)
|
||||
if (params[2].equals_ci(s->GetIPs()[i]))
|
||||
{
|
||||
s->GetIPs().erase(s->GetIPs().begin() + i);
|
||||
source.Reply(_("Removed IP %s from %s."), params[2].c_str(), s->GetName().c_str());
|
||||
Log(LOG_ADMIN, source, this) << "to remove IP " << params[2] << " from " << s->GetName();
|
||||
|
||||
if (s->GetIPs().empty())
|
||||
{
|
||||
s->repool = 0;
|
||||
s->pooled = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
source.Reply(_("IP %s does not exist for %s."), params[2].c_str(), s->GetName().c_str());
|
||||
}
|
||||
|
||||
void OnSet(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(params[1]);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
source.Reply(_("Server %s does not exist."), params[1].c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (params[2].equals_ci("LIMIT"))
|
||||
{
|
||||
try
|
||||
{
|
||||
unsigned l = convertTo<unsigned>(params[3]);
|
||||
s->SetLimit(l);
|
||||
if (l)
|
||||
source.Reply(_("User limit for %s set to %d."), s->GetName().c_str(), l);
|
||||
else
|
||||
source.Reply(_("User limit for %s removed."), s->GetName().c_str());
|
||||
}
|
||||
catch (const ConvertException &ex)
|
||||
{
|
||||
source.Reply(_("Invalid value for LIMIT. Must be numerical."));
|
||||
}
|
||||
}
|
||||
else
|
||||
source.Reply(_("Unknown SET option"));
|
||||
}
|
||||
|
||||
void OnPool(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(params[1]);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
source.Reply(_("Server %s does not exist."), params[1].c_str());
|
||||
return;
|
||||
}
|
||||
else if (!Server::Find(s->GetName()))
|
||||
{
|
||||
source.Reply(_("Server %s is not currently linked."), s->GetName().c_str());
|
||||
return;
|
||||
}
|
||||
else if (s->pooled)
|
||||
{
|
||||
source.Reply(_("Server %s is already pooled."), s->GetName().c_str());
|
||||
return;
|
||||
}
|
||||
else if (s->GetIPs().empty())
|
||||
{
|
||||
source.Reply(_("Server %s has no configured IPs."), s->GetName().c_str());
|
||||
}
|
||||
|
||||
s->pooled = true;
|
||||
|
||||
source.Reply(_("Pooled %s."), s->GetName().c_str());
|
||||
Log(LOG_ADMIN, source, this) << "to pool " << s->GetName();
|
||||
}
|
||||
|
||||
|
||||
void OnDepool(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(params[1]);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
source.Reply(_("Server %s does not exist."), params[1].c_str());
|
||||
return;
|
||||
}
|
||||
else if (!s->pooled)
|
||||
{
|
||||
source.Reply(_("Server %s is not pooled."), s->GetName().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
s->pooled = false;
|
||||
|
||||
source.Reply(_("Depooled %s."), s->GetName().c_str());
|
||||
Log(LOG_ADMIN, source, this) << "to depool " << s->GetName();
|
||||
}
|
||||
|
||||
public:
|
||||
CommandOSDNS(Module *creator) : Command(creator, "operserv/dns", 0, 3)
|
||||
{
|
||||
this->SetDesc(_("Manage the DNS zone for this network"));
|
||||
this->SetSyntax(_("ADD \037server.name\037"));
|
||||
this->SetSyntax(_("DEL \037server.name\037"));
|
||||
this->SetSyntax(_("ADDIP \037server.name\037 \037ip\037"));
|
||||
this->SetSyntax(_("DELIP \037server.name\037 \037ip\037"));
|
||||
this->SetSyntax(_("SET \037server.name\037 \37option\37 \037value\037"));
|
||||
this->SetSyntax(_("POOL \037server.name\037"));
|
||||
this->SetSyntax(_("DEPOOL \037server.name\037"));
|
||||
}
|
||||
|
||||
void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
|
||||
{
|
||||
if (params.empty())
|
||||
this->DisplayPoolState(source);
|
||||
else if (params[0].equals_ci("ADD") && params.size() > 1)
|
||||
this->OnAdd(source, params);
|
||||
else if (params[0].equals_ci("DEL") && params.size() > 1)
|
||||
this->OnDel(source, params);
|
||||
else if (params[0].equals_ci("ADDIP") && params.size() > 2)
|
||||
this->AddIP(source, params);
|
||||
else if (params[0].equals_ci("DELIP") && params.size() > 2)
|
||||
this->DelIP(source, params);
|
||||
else if (params[0].equals_ci("SET") && params.size() > 3)
|
||||
this->OnSet(source, params);
|
||||
else if (params[0].equals_ci("POOL") && params.size() > 1)
|
||||
this->OnPool(source, params);
|
||||
else if (params[0].equals_ci("DEPOOL") && params.size() > 1)
|
||||
this->OnDepool(source, params);
|
||||
else
|
||||
this->OnSyntaxError(source, "");
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
|
||||
{
|
||||
this->SendSyntax(source);
|
||||
source.Reply(" ");
|
||||
source.Reply(_("This command allows managing a DNS zone\n"
|
||||
"used for controlling what servers users\n"
|
||||
"are directed to when connecting. Omitting\n"
|
||||
"all parameters prints out the status of\n"
|
||||
"the DNS zone.\n"));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleDNS : public Module
|
||||
{
|
||||
SerializeType dns_type;
|
||||
CommandOSDNS commandosdns;
|
||||
|
||||
time_t ttl;
|
||||
int user_drop_mark;
|
||||
time_t user_drop_time;
|
||||
time_t user_drop_readd_time;
|
||||
bool remove_split_servers;
|
||||
bool readd_connected_servers;
|
||||
|
||||
public:
|
||||
ModuleDNS(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED),
|
||||
dns_type("DNSServer", DNSServer::unserialize), commandosdns(this)
|
||||
{
|
||||
this->SetAuthor("Anope");
|
||||
|
||||
Implementation i[] = { I_OnReload, I_OnNewServer, I_OnServerQuit, I_OnUserConnect, I_OnUserLogoff, I_OnDnsRequest };
|
||||
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
|
||||
|
||||
this->OnReload();
|
||||
}
|
||||
|
||||
void OnReload() anope_override
|
||||
{
|
||||
ConfigReader config;
|
||||
|
||||
this->ttl = dotime(config.ReadValue("os_dns", "ttl", 0));
|
||||
this->user_drop_mark = config.ReadInteger("os_dns", "user_drop_mark", 0, false);
|
||||
this->user_drop_time = dotime(config.ReadValue("os_dns", "user_drop_time", 0, false));
|
||||
this->user_drop_readd_time = dotime(config.ReadValue("os_dns", "user_drop_readd_time", 0, false));
|
||||
this->remove_split_servers = config.ReadFlag("os_dns", "remove_split_servers", 0);
|
||||
this->readd_connected_servers = config.ReadFlag("os_dns", "readd_connected_servers", 0);
|
||||
}
|
||||
|
||||
void OnNewServer(Server *s) anope_override
|
||||
{
|
||||
if (this->readd_connected_servers)
|
||||
{
|
||||
DNSServer *dns = DNSServer::Find(s->GetName());
|
||||
if (dns && !dns->pooled && !dns->GetIPs().empty() && dns->GetLimit() < s->Users)
|
||||
{
|
||||
dns->pooled = true;
|
||||
Log() << "Pooling server " << s->GetName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OnServerQuit(Server *s) anope_override
|
||||
{
|
||||
DNSServer *dns = DNSServer::Find(s->GetName());
|
||||
if (dns && dns->pooled)
|
||||
{
|
||||
dns->pooled = false;
|
||||
Log() << "Depooling delinked server " << s->GetName();
|
||||
}
|
||||
}
|
||||
|
||||
void OnUserConnect(dynamic_reference<User> &u, bool &exempt) anope_override
|
||||
{
|
||||
if (u && u->server)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(u->server->GetName());
|
||||
/* Check for user limit reached */
|
||||
if (s && s->GetLimit() && s->pooled && u->server->Users >= s->GetLimit())
|
||||
{
|
||||
Log() << "Depooling full server " << s->GetName() << ": " << u->server->Users << " users";
|
||||
s->pooled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnUserLogoff(User *u) anope_override
|
||||
{
|
||||
if (u && u->server)
|
||||
{
|
||||
DNSServer *s = DNSServer::Find(u->server->GetName());
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
/* Check for dropping under userlimit */
|
||||
if (s->GetLimit() && !s->pooled && s->GetLimit() > u->server->Users)
|
||||
{
|
||||
Log() << "Pooling server " << s->GetName();
|
||||
s->pooled = true;
|
||||
}
|
||||
|
||||
if (this->user_drop_mark > 0)
|
||||
{
|
||||
std::list<time_t>& times = server_quit_times[u->server->GetName()];
|
||||
times.push_back(Anope::CurTime);
|
||||
if (times.size() > static_cast<unsigned>(this->user_drop_mark))
|
||||
times.pop_front();
|
||||
|
||||
if (s->pooled && times.size() == static_cast<unsigned>(this->user_drop_mark))
|
||||
{
|
||||
time_t diff = Anope::CurTime - *times.begin();
|
||||
|
||||
/* Check for very fast user drops */
|
||||
if (diff <= this->user_drop_time)
|
||||
{
|
||||
Log() << "Depooling server " << s->GetName() << ": dropped " << this->user_drop_mark << " users in " << diff << " seconds";
|
||||
s->repool = Anope::CurTime + this->user_drop_readd_time;
|
||||
s->pooled = false;
|
||||
}
|
||||
/* Check for needing to re-pool a server that dropped users */
|
||||
else if (s->repool && s->repool <= Anope::CurTime && !s->pooled)
|
||||
{
|
||||
s->pooled = true;
|
||||
s->repool = 0;
|
||||
Log() << "Pooling server " << s->GetName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDnsRequest(DNSPacket &req) anope_override
|
||||
{
|
||||
if (req.questions.empty())
|
||||
return;
|
||||
/* Currently we reply to any QR */
|
||||
const Question& q = req.questions[0];
|
||||
|
||||
DNSPacket *packet = new DNSPacket(req);
|
||||
packet->flags |= DNS_QUERYFLAGS_QR; /* This is a reponse */
|
||||
|
||||
for (unsigned i = 0; i < dns_servers.size(); ++i)
|
||||
{
|
||||
DNSServer *s = dns_servers[i];
|
||||
if (!s->pooled)
|
||||
continue;
|
||||
|
||||
for (unsigned j = 0; j < s->GetIPs().size(); ++j)
|
||||
{
|
||||
ResourceRecord rr(q.name, s->GetIPs()[j].find(':') != Anope::string::npos ? DNS_QUERY_AAAA : DNS_QUERY_A);
|
||||
rr.ttl = this->ttl;
|
||||
rr.rdata = s->GetIPs()[j];
|
||||
packet->answers.push_back(rr);
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->answers.empty())
|
||||
{
|
||||
static time_t last_warn = 0;
|
||||
if (last_warn + 60 < Anope::CurTime)
|
||||
{
|
||||
last_warn = Anope::CurTime;
|
||||
Log() << "os_dns: Warning! There are no pooled servers!";
|
||||
}
|
||||
|
||||
/* Something messed up, just return them all and hope one is available */
|
||||
for (unsigned i = 0; i < dns_servers.size(); ++i)
|
||||
{
|
||||
DNSServer *s = dns_servers[i];
|
||||
|
||||
for (unsigned j = 0; j < s->GetIPs().size(); ++j)
|
||||
{
|
||||
ResourceRecord rr(q.name, s->GetIPs()[j].find(':') != Anope::string::npos ? DNS_QUERY_AAAA : DNS_QUERY_A);
|
||||
rr.ttl = this->ttl;
|
||||
rr.rdata = s->GetIPs()[j];
|
||||
packet->answers.push_back(rr);
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->answers.empty())
|
||||
{
|
||||
Log() << "os_dns: Error! There are no servers with any IPs. At all.";
|
||||
/* Send back an empty answer anyway */
|
||||
}
|
||||
}
|
||||
|
||||
DNSEngine->SendPacket(packet);
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(ModuleDNS)
|
||||
@@ -17,6 +17,14 @@
|
||||
#include "opertype.h"
|
||||
#include "channels.h"
|
||||
#include "hashcomp.h"
|
||||
#include "dns.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
@@ -200,6 +208,9 @@ ServerConfig::ServerConfig() : config_data(), NSDefFlags(NickCoreFlagStrings), C
|
||||
this->NameServer = "127.0.0.1";
|
||||
}
|
||||
}
|
||||
if (DNSEngine)
|
||||
DNSEngine->SetFlag(SF_DEAD);
|
||||
DNSEngine = new DNSManager(this->NameServer, this->DNSPort);
|
||||
|
||||
if (this->CaseMap == "ascii")
|
||||
Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype<char>());
|
||||
@@ -219,6 +230,31 @@ ServerConfig::ServerConfig() : config_data(), NSDefFlags(NickCoreFlagStrings), C
|
||||
|
||||
if (this->SessionIPv4CIDR > 32 || this->SessionIPv6CIDR > 128)
|
||||
throw ConfigException("Session CIDR value out of range");
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!this->User.empty())
|
||||
{
|
||||
errno = 0;
|
||||
struct passwd *u = getpwnam(this->User.c_str());
|
||||
if (u == NULL)
|
||||
Log() << "Unable to setuid to " << this->User << ": " << Anope::LastError();
|
||||
else if (setuid(u->pw_uid) == -1)
|
||||
Log() << "Unable to setuid to " << this->User << ": " << Anope::LastError();
|
||||
else
|
||||
Log() << "Successfully set user to " << this->User;
|
||||
}
|
||||
if (!this->Group.empty())
|
||||
{
|
||||
errno = 0;
|
||||
struct group *g = getgrnam(this->Group.c_str());
|
||||
if (g == NULL)
|
||||
Log() << "Unable to setgid to " << this->Group << ": " << Anope::LastError();
|
||||
else if (setuid(g->gr_gid) == -1)
|
||||
Log() << "Unable to setgid to " << this->Group << ": " << Anope::LastError();
|
||||
else
|
||||
Log() << "Successfully set group to " << this->Group;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ServerConfig::CheckOnce(const Anope::string &tag)
|
||||
@@ -1191,6 +1227,8 @@ ConfigItems::ConfigItems(ServerConfig *conf)
|
||||
{"networkinfo", "userlen", "10", new ValueContainerUInt(&conf->UserLen), DT_UINTEGER | DT_NORELOAD, NoValidation},
|
||||
{"networkinfo", "hostlen", "64", new ValueContainerUInt(&conf->HostLen), DT_UINTEGER | DT_NORELOAD, NoValidation},
|
||||
{"networkinfo", "chanlen", "32", new ValueContainerUInt(&conf->ChanLen), DT_UINTEGER | DT_NORELOAD, NoValidation},
|
||||
{"options", "user", "", new ValueContainerString(&conf->User), DT_STRING, NoValidation},
|
||||
{"options", "group", "", new ValueContainerString(&conf->Group), DT_STRING, NoValidation},
|
||||
{"options", "casemap", "ascii", new ValueContainerString(&conf->CaseMap), DT_STRING, NoValidation},
|
||||
{"options", "passlen", "32", new ValueContainerUInt(&conf->PassLen), DT_UINTEGER | DT_NORELOAD, NoValidation},
|
||||
{"options", "seed", "0", new ValueContainerLUInt(&conf->Seed), DT_LUINTEGER, NoValidation},
|
||||
@@ -1264,6 +1302,7 @@ ConfigItems::ConfigItems(ServerConfig *conf)
|
||||
{"mail", "memo_message", "", new ValueContainerString(&conf->MailMemoMessage), DT_STRING | DT_ALLOW_NEWLINE, ValidateMail},
|
||||
{"dns", "nameserver", "127.0.0.1", new ValueContainerString(&conf->NameServer), DT_STRING, NoValidation},
|
||||
{"dns", "timeout", "5", new ValueContainerTime(&conf->DNSTimeout), DT_TIME, NoValidation},
|
||||
{"dns", "port", "53", new ValueContainerInt(&conf->DNSPort), DT_INTEGER, NoValidation},
|
||||
{"chanserv", "name", "", new ValueContainerString(&conf->ChanServ), DT_STRING, NoValidation},
|
||||
{"chanserv", "defaults", "keeptopic secure securefounder signkick", new ValueContainerString(&CSDefaults), DT_STRING, ValidateChanServ},
|
||||
{"chanserv", "maxregistered", "0", new ValueContainerUInt(&conf->CSMaxReg), DT_UINTEGER, ValidateChanServ},
|
||||
|
||||
+52
-42
@@ -56,20 +56,11 @@ DNSQuery::DNSQuery(const Question &q)
|
||||
this->error = DNS_ERROR_NONE;
|
||||
}
|
||||
|
||||
DNSQuery::DNSQuery(const DNSPacket &p)
|
||||
{
|
||||
this->questions = p.questions;
|
||||
this->answers = p.answers;
|
||||
this->authorities = p.authorities;
|
||||
this->additional = p.additional;
|
||||
this->error = DNS_ERROR_NONE;
|
||||
}
|
||||
|
||||
DNSRequest::DNSRequest(const Anope::string &addr, QueryType qt, bool cache, Module *c) : Timer(Config->DNSTimeout), Question(addr, qt), use_cache(cache), id(0), creator(c)
|
||||
{
|
||||
if (!DNSEngine)
|
||||
DNSEngine = new DNSManager(Config->NameServer, DNSManager::DNSPort);
|
||||
if (DNSEngine->packets.size() == 65535)
|
||||
throw SocketException("No DNSEngine");
|
||||
if (DNSEngine->GetPackets().size() == 65535)
|
||||
throw SocketException("DNS queue full");
|
||||
|
||||
do
|
||||
@@ -101,14 +92,12 @@ void DNSRequest::Process()
|
||||
return;
|
||||
}
|
||||
|
||||
DNSPacket *p = new DNSPacket();
|
||||
DNSPacket *p = new DNSPacket(DNSEngine->addrs);
|
||||
p->flags = DNS_QUERYFLAGS_RD;
|
||||
|
||||
p->id = this->id;
|
||||
p->questions.push_back(*this);
|
||||
DNSEngine->packets.push_back(p);
|
||||
|
||||
SocketEngine::MarkWritable(DNSEngine);
|
||||
DNSEngine->SendPacket(p);
|
||||
}
|
||||
|
||||
void DNSRequest::OnError(const DNSQuery *r)
|
||||
@@ -239,12 +228,12 @@ ResourceRecord DNSPacket::UnpackResourceRecord(const unsigned char *input, unsig
|
||||
if (pos + 4 > input_size)
|
||||
throw SocketException("Unable to unpack resource record");
|
||||
|
||||
in_addr addr;
|
||||
addr.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16) | (input[pos + 3] << 24);
|
||||
in_addr a;
|
||||
a.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16) | (input[pos + 3] << 24);
|
||||
pos += 4;
|
||||
|
||||
sockaddrs addrs;
|
||||
addrs.ntop(AF_INET, &addr);
|
||||
addrs.ntop(AF_INET, &a);
|
||||
|
||||
record.rdata = addrs.addr();
|
||||
break;
|
||||
@@ -254,13 +243,13 @@ ResourceRecord DNSPacket::UnpackResourceRecord(const unsigned char *input, unsig
|
||||
if (pos + 16 > input_size)
|
||||
throw SocketException("Unable to unpack resource record");
|
||||
|
||||
in6_addr addr;
|
||||
in6_addr a;
|
||||
for (int j = 0; j < 16; ++j)
|
||||
addr.s6_addr[j] = input[pos + j];
|
||||
a.s6_addr[j] = input[pos + j];
|
||||
pos += 16;
|
||||
|
||||
sockaddrs addrs;
|
||||
addrs.ntop(AF_INET6, &addr);
|
||||
addrs.ntop(AF_INET6, &a);
|
||||
|
||||
record.rdata = addrs.addr();
|
||||
break;
|
||||
@@ -280,9 +269,8 @@ ResourceRecord DNSPacket::UnpackResourceRecord(const unsigned char *input, unsig
|
||||
return record;
|
||||
}
|
||||
|
||||
DNSPacket::DNSPacket() : DNSQuery()
|
||||
DNSPacket::DNSPacket(const sockaddrs &a) : DNSQuery(), addr(a), id(0), flags(0)
|
||||
{
|
||||
this->id = this->flags = 0;
|
||||
}
|
||||
|
||||
void DNSPacket::Fill(const unsigned char *input, const unsigned short len)
|
||||
@@ -426,13 +414,13 @@ unsigned short DNSPacket::Pack(unsigned char *output, unsigned short output_size
|
||||
if (pos + 6 > output_size)
|
||||
throw SocketException("Unable to pack packet");
|
||||
|
||||
sockaddrs addr(rr.rdata);
|
||||
sockaddrs a(rr.rdata);
|
||||
|
||||
s = htons(4);
|
||||
memcpy(&output[pos], &s, 2);
|
||||
pos += 2;
|
||||
|
||||
memcpy(&output[pos], &addr.sa4.sin_addr, 4);
|
||||
memcpy(&output[pos], &a.sa4.sin_addr, 4);
|
||||
pos += 4;
|
||||
break;
|
||||
}
|
||||
@@ -441,13 +429,13 @@ unsigned short DNSPacket::Pack(unsigned char *output, unsigned short output_size
|
||||
if (pos + 18 > output_size)
|
||||
throw SocketException("Unable to pack packet");
|
||||
|
||||
sockaddrs addr(rr.rdata);
|
||||
sockaddrs a(rr.rdata);
|
||||
|
||||
s = htons(16);
|
||||
memcpy(&output[pos], &s, 2);
|
||||
pos += 2;
|
||||
|
||||
memcpy(&output[pos], &addr.sa6.sin6_addr, 16);
|
||||
memcpy(&output[pos], &a.sa6.sin6_addr, 16);
|
||||
pos += 16;
|
||||
break;
|
||||
}
|
||||
@@ -477,6 +465,15 @@ unsigned short DNSPacket::Pack(unsigned char *output, unsigned short output_size
|
||||
DNSManager::DNSManager(const Anope::string &nameserver, int port) : Timer(300, Anope::CurTime, true), Socket(-1, nameserver.find(':') != Anope::string::npos, SOCK_DGRAM)
|
||||
{
|
||||
this->addrs.pton(this->IPv6 ? AF_INET6 : AF_INET, nameserver, port);
|
||||
try
|
||||
{
|
||||
this->Bind("0.0.0.0", port);
|
||||
}
|
||||
catch (const SocketException &ex)
|
||||
{
|
||||
/* This error can be from normal operation as most people don't use services to handle DNS queries, so put it in debug log */
|
||||
Log(LOG_DEBUG) << "Unable to bind DNSManager to port " << port << ": " << ex.GetReason();
|
||||
}
|
||||
}
|
||||
|
||||
DNSManager::~DNSManager()
|
||||
@@ -514,13 +511,7 @@ bool DNSManager::ProcessRead()
|
||||
if (length < DNSPacket::HEADER_LENGTH)
|
||||
return true;
|
||||
|
||||
if (this->addrs != from_server)
|
||||
{
|
||||
Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->addrs.addr() << "' != '" << from_server.addr() << "'";
|
||||
return true;
|
||||
}
|
||||
|
||||
DNSPacket recv_packet;
|
||||
DNSPacket recv_packet(from_server);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -532,6 +523,18 @@ bool DNSManager::ProcessRead()
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(recv_packet.flags & DNS_QUERYFLAGS_QR))
|
||||
{
|
||||
FOREACH_MOD(I_OnDnsRequest, OnDnsRequest(recv_packet));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->addrs != from_server)
|
||||
{
|
||||
Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->addrs.addr() << "' != '" << from_server.addr() << "'";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::map<unsigned short, DNSRequest *>::iterator it = DNSEngine->requests.find(recv_packet.id);
|
||||
if (it == DNSEngine->requests.end())
|
||||
{
|
||||
@@ -540,13 +543,7 @@ bool DNSManager::ProcessRead()
|
||||
}
|
||||
DNSRequest *request = it->second;
|
||||
|
||||
if (!(recv_packet.flags & DNS_QUERYFLAGS_QR))
|
||||
{
|
||||
Log(LOG_DEBUG_2) << "Resolver: Received a non-answer";
|
||||
recv_packet.error = DNS_ERROR_NOT_AN_ANSWER;
|
||||
request->OnError(&recv_packet);
|
||||
}
|
||||
else if (recv_packet.flags & DNS_QUERYFLAGS_OPCODE)
|
||||
if (recv_packet.flags & DNS_QUERYFLAGS_OPCODE)
|
||||
{
|
||||
Log(LOG_DEBUG_2) << "Resolver: Received a nonstandard query";
|
||||
recv_packet.error = DNS_ERROR_NONSTANDARD_QUERY;
|
||||
@@ -614,7 +611,7 @@ bool DNSManager::ProcessWrite()
|
||||
unsigned char buffer[524];
|
||||
unsigned short len = r->Pack(buffer, sizeof(buffer));
|
||||
|
||||
sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &this->addrs.sa, this->addrs.size());
|
||||
sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &r->addr.sa, r->addr.size());
|
||||
}
|
||||
catch (const SocketException &) { }
|
||||
|
||||
@@ -698,6 +695,19 @@ void DNSManager::Cleanup(Module *mod)
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<DNSPacket *>& DNSManager::GetPackets()
|
||||
{
|
||||
return this->packets;
|
||||
}
|
||||
|
||||
void DNSManager::SendPacket(DNSPacket *p)
|
||||
{
|
||||
Log(LOG_DEBUG_2) << "Resolver: Queueing packet " << p->id;
|
||||
this->packets.push_back(p);
|
||||
|
||||
SocketEngine::MarkWritable(this);
|
||||
}
|
||||
|
||||
DNSQuery DNSManager::BlockingQuery(const Anope::string &mask, QueryType qt)
|
||||
{
|
||||
Question question(mask, qt);
|
||||
|
||||
+15
-3
@@ -422,6 +422,9 @@ void Init(int ac, char **av)
|
||||
Log(LOG_TERMINAL) << "Using configuration file " << conf_dir << "/" << services_conf.GetName();
|
||||
#endif
|
||||
|
||||
/* Initialize the socket engine */
|
||||
SocketEngine::Init();
|
||||
|
||||
/* Read configuration file; exit if there are problems. */
|
||||
try
|
||||
{
|
||||
@@ -441,6 +444,15 @@ void Init(int ac, char **av)
|
||||
if (!SupportedWindowsVersion())
|
||||
throw FatalException(GetWindowsVersion() + " is not a supported version of Windows");
|
||||
#else
|
||||
/* If we're root, issue a warning now */
|
||||
if (!getuid() && !getgid())
|
||||
{
|
||||
std::cerr << "WARNING: You are currently running Anope as the root superuser. Anope does not" << std::endl;
|
||||
std::cerr << " require root privileges to run, and it is discouraged that you run Anope" << std::endl;
|
||||
std::cerr << " as the root superuser." << std::endl;
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
if (!nofork && AtTerm())
|
||||
{
|
||||
/* Install these before fork() - it is possible for the child to
|
||||
@@ -478,16 +490,16 @@ void Init(int ac, char **av)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the socket engine */
|
||||
SocketEngine::Init();
|
||||
|
||||
/* Write our PID to the PID file. */
|
||||
write_pidfile();
|
||||
|
||||
/* Create me */
|
||||
Me = new Server(NULL, Config->ServerName, 0, Config->ServerDesc, Config->Numeric);
|
||||
for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
|
||||
{
|
||||
it->second->server = Me;
|
||||
++Me->Users;
|
||||
}
|
||||
|
||||
/* Announce ourselves to the logfile. */
|
||||
Log() << "Anope " << Anope::Version() << " starting up" << (debug || readonly ? " (options:" : "") << (debug ? " debug" : "") << (readonly ? " readonly" : "") << (debug || readonly ? ")" : "");
|
||||
|
||||
@@ -362,17 +362,6 @@ Anope::string GetFullProgDir(const Anope::string &argv0)
|
||||
|
||||
int main(int ac, char **av, char **envp)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
/* If we're root, issue a warning now */
|
||||
if (!getuid() && !getgid())
|
||||
{
|
||||
std::cerr << "WARNING: You are currently running Anope as the root superuser. Anope does not" << std::endl;
|
||||
std::cerr << " require root privileges to run, and it is discouraged that you run Anope" << std::endl;
|
||||
std::cerr << " as the root superuser." << std::endl;
|
||||
sleep(3);
|
||||
}
|
||||
#endif
|
||||
|
||||
binary_dir = GetFullProgDir(av[0]);
|
||||
if (binary_dir[binary_dir.length() - 1] == '.')
|
||||
binary_dir = binary_dir.substr(0, binary_dir.length() - 2);
|
||||
|
||||
+4
-1
@@ -66,7 +66,10 @@ User::User(const Anope::string &snick, const Anope::string &sident, const Anope:
|
||||
this->nc = NULL;
|
||||
|
||||
if (sserver) // Our bots are introduced on startup with no server
|
||||
{
|
||||
++sserver->Users;
|
||||
Log(this, "connect") << (!svhost.empty() ? Anope::string("(") + svhost + ") " : "") << "(" << srealname << ") " << sip << " connected to the network (" << sserver->GetName() << ")";
|
||||
}
|
||||
|
||||
++usercnt;
|
||||
if (usercnt > maxusercnt)
|
||||
@@ -241,7 +244,7 @@ User::~User()
|
||||
Log(LOG_DEBUG_2) << "User::~User() called";
|
||||
|
||||
Log(this, "disconnect") << "(" << this->realname << ") " << "disconnected from the network (" << this->server->GetName() << ")";
|
||||
|
||||
--this->server->Users;
|
||||
|
||||
FOREACH_MOD(I_OnUserLogoff, OnUserLogoff(this));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user