* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
- * InspIRCd: (C) 2002-2009 InspIRCd Development Team
+ * InspIRCd: (C) 2002-2010 InspIRCd Development Team
* See: http://wiki.inspircd.org/Credits
*
* This program is free but copyrighted software; see
* ---------------------------------------------------
*/
-/* $Core */
-/* $CopyInstall: conf/inspircd.quotes.example $(CONPATH) */
-/* $CopyInstall: conf/inspircd.rules.example $(CONPATH) */
-/* $CopyInstall: conf/inspircd.motd.example $(CONPATH) */
-/* $CopyInstall: conf/inspircd.helpop-full.example $(CONPATH) */
-/* $CopyInstall: conf/inspircd.helpop.example $(CONPATH) */
-/* $CopyInstall: conf/inspircd.censor.example $(CONPATH) */
-/* $CopyInstall: conf/inspircd.filter.example $(CONPATH) */
-/* $CopyInstall: conf/inspircd.conf.example $(CONPATH) */
-/* $CopyInstall: conf/modules.conf.example $(CONPATH) */
-/* $CopyInstall: conf/opers.conf.example $(CONPATH) */
-/* $CopyInstall: conf/links.conf.example $(CONPATH) */
-/* $CopyInstall: .gdbargs $(BASE) */
-
#include "inspircd.h"
#include <fstream>
#include "xline.h"
#include "exitcodes.h"
#include "commands/cmd_whowas.h"
-#include "modes/cmode_h.h"
-
-struct fpos
-{
- std::string filename;
- int line;
- int col;
- fpos(const std::string& name, int l = 1, int c = 1) : filename(name), line(l), col(c) {}
- std::string str()
- {
- return filename + ":" + ConvToStr(line) + ":" + ConvToStr(col);
- }
-};
-
-enum ParseFlags
-{
- FLAG_NO_EXEC = 1,
- FLAG_NO_INC = 2
-};
-
-struct ParseStack
-{
- std::vector<std::string> reading;
- ConfigDataHash& output;
- std::stringstream& errstr;
-
- ParseStack(ServerConfig* conf)
- : output(conf->config_data), errstr(conf->errstr)
- { }
- bool ParseFile(const std::string& name, int flags);
- bool ParseExec(const std::string& name, int flags);
- void DoInclude(ConfigTag* includeTag, int flags);
-};
-
-struct Parser
-{
- ParseStack& stack;
- const int flags;
- FILE* const file;
- fpos current;
- fpos last_tag;
- reference<ConfigTag> tag;
- int ungot;
-
- Parser(ParseStack& me, int myflags, FILE* conf, const std::string& name)
- : stack(me), flags(myflags), file(conf), current(name), last_tag(name), ungot(-1)
- { }
-
- int next(bool eof_ok = false)
- {
- if (ungot != -1)
- {
- int ch = ungot;
- ungot = -1;
- return ch;
- }
- int ch = fgetc(file);
- if (ch == EOF && !eof_ok)
- {
- throw CoreException("Unexpected end-of-file");
- }
- else if (ch == '\n')
- {
- current.line++;
- current.col = 0;
- }
- else
- {
- current.col++;
- }
- return ch;
- }
-
- void unget(int ch)
- {
- if (ungot != -1)
- throw CoreException("INTERNAL ERROR: cannot unget twice");
- ungot = ch;
- }
-
- void comment()
- {
- while (1)
- {
- int ch = next();
- if (ch == '\n')
- return;
- }
- }
-
- void nextword(std::string& rv)
- {
- int ch = next();
- while (isspace(ch))
- ch = next();
- while (isalnum(ch) || ch == '_')
- {
- rv.push_back(ch);
- ch = next();
- }
- unget(ch);
- }
-
- bool kv()
- {
- std::string key;
- nextword(key);
- int ch = next();
- if (ch == '>' && key.empty())
- {
- return false;
- }
- else if (ch == '#' && key.empty())
- {
- comment();
- return true;
- }
- else if (ch != '=')
- {
- throw CoreException("Invalid character " + std::string(1, ch) + " in key (" + key + ")");
- }
-
- std::string value;
- ch = next();
- if (ch != '"')
- {
- throw CoreException("Invalid character in value of <" + tag->tag + ":" + key + ">");
- }
- while (1)
- {
- ch = next();
- if (ch == '\\')
- {
- ch = next();
- if (ch == 'n')
- ch = '\n';
- else if (ch == 'r')
- ch = '\r';
- }
- else if (ch == '"')
- break;
- value.push_back(ch);
- }
- tag->items.push_back(KeyVal(key, value));
- return true;
- }
-
- void dotag()
- {
- last_tag = current;
- std::string name;
- nextword(name);
-
- int spc = next();
- if (!isspace(spc))
- throw CoreException("Invalid character in tag name");
-
- if (name.empty())
- throw CoreException("Empty tag name");
-
- tag = new ConfigTag(name, current.filename, current.line);
-
- while (kv());
-
- if (tag->tag == "include")
- {
- stack.DoInclude(tag, flags);
- }
- else
- {
- stack.output.insert(std::make_pair(tag->tag, tag));
- }
- // this is not a leak; reference<> takes care of the delete
- tag = NULL;
- }
-
- bool outer_parse()
- {
- try
- {
- while (1)
- {
- int ch = next(true);
- switch (ch)
- {
- case EOF:
- // this is the one place where an EOF is not an error
- return true;
- case '#':
- comment();
- break;
- case '<':
- dotag();
- break;
- case ' ':
- case '\r':
- case '\t':
- case '\n':
- break;
- case 0xFE:
- case 0xFF:
- stack.errstr << "Do not save your files as UTF-16; use ASCII!\n";
- default:
- throw CoreException("Syntax error - start of tag expected");
- }
- }
- }
- catch (CoreException& err)
- {
- stack.errstr << err.GetReason() << " at " << current.str();
- if (tag)
- stack.errstr << " (inside tag " << tag->tag << " at line " << tag->src_line << ")\n";
- else
- stack.errstr << " (last tag was on line " << last_tag.line << ")\n";
- }
- return false;
- }
-};
-
-void ParseStack::DoInclude(ConfigTag* tag, int flags)
-{
- if (flags & FLAG_NO_INC)
- throw CoreException("Invalid <include> tag in file included with noinclude=\"yes\"");
- std::string name;
- if (tag->readString("file", name))
- {
- if (tag->getBool("noinclude", false))
- flags |= FLAG_NO_INC;
- if (tag->getBool("noexec", false))
- flags |= FLAG_NO_EXEC;
- if (!ParseFile(name, flags))
- throw CoreException("Included");
- }
- else if (tag->readString("executable", name))
- {
- if (flags & FLAG_NO_EXEC)
- throw CoreException("Invalid <include:executable> tag in file included with noexec=\"yes\"");
- if (tag->getBool("noinclude", false))
- flags |= FLAG_NO_INC;
- if (tag->getBool("noexec", true))
- flags |= FLAG_NO_EXEC;
- if (!ParseExec(name, flags))
- throw CoreException("Included");
- }
-}
-
-bool ParseStack::ParseFile(const std::string& name, int flags)
-{
- ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading file %s", name.c_str());
- for (unsigned int t = 0; t < reading.size(); t++)
- {
- if (std::string(name) == reading[t])
- {
- throw CoreException("File " + name + " is included recursively (looped inclusion)");
- }
- }
-
- /* It's not already included, add it to the list of files we've loaded */
-
- FILE* file = fopen(name.c_str(), "r");
- if (!file)
- throw CoreException("Could not read \"" + name + "\" for include");
-
- reading.push_back(name);
- Parser p(*this, flags, file, name);
- bool ok = p.outer_parse();
- reading.pop_back();
- return ok;
-}
-
-bool ParseStack::ParseExec(const std::string& name, int flags)
-{
- ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading executable %s", name.c_str());
- for (unsigned int t = 0; t < reading.size(); t++)
- {
- if (std::string(name) == reading[t])
- {
- throw CoreException("Executable " + name + " is included recursively (looped inclusion)");
- }
- }
-
- /* It's not already included, add it to the list of files we've loaded */
-
- FILE* file = popen(name.c_str(), "r");
- if (!file)
- throw CoreException("Could not open executable \"" + name + "\" for include");
-
- reading.push_back(name);
- Parser p(*this, flags, file, name);
- bool ok = p.outer_parse();
- reading.pop_back();
- return ok;
-}
-
-/////////////////////////////////////////////////////////////////////////////
+#include "configparser.h"
ServerConfig::ServerConfig()
{
WhoWasGroupSize = WhoWasMaxGroups = WhoWasMaxKeep = 0;
- log_file = NULL;
- NoUserDns = forcedebug = OperSpyWhois = nofork = HideBans = HideSplits = UndernetMsgPrefix = false;
- CycleHosts = writelog = AllowHalfop = InvBypassModes = true;
- dns_timeout = DieDelay = 5;
+ NoUserDns = OperSpyWhois = HideBans = HideSplits = UndernetMsgPrefix = false;
+ WildcardIPv6 = CycleHosts = InvBypassModes = true;
+ dns_timeout = 5;
MaxTargets = 20;
NetBufferSize = 10240;
SoftLimit = ServerInstance->SE->GetMaxFds();
MaxConn = SOMAXCONN;
- MaxWhoResults = 0;
- debugging = 0;
MaxChans = 20;
OperMaxChans = 30;
c_ipv4_range = 32;
void ServerConfig::Update005()
{
std::stringstream out(data005);
+ std::vector<std::string> data;
std::string token;
+ while (out >> token)
+ data.push_back(token);
+ sort(data.begin(), data.end());
+
std::string line5;
- int token_counter = 0;
isupport.clear();
- while (out >> token)
+ for(unsigned int i=0; i < data.size(); i++)
{
+ token = data[i];
line5 = line5 + token + " ";
- token_counter++;
- if (token_counter >= 13)
+ if (i % 13 == 12)
{
- char buf[MAXBUF];
- snprintf(buf, MAXBUF, "%s:are supported by this server", line5.c_str());
- isupport.push_back(buf);
+ line5.append(":are supported by this server");
+ isupport.push_back(line5);
line5.clear();
- token_counter = 0;
}
}
if (!line5.empty())
{
- char buf[MAXBUF];
- snprintf(buf, MAXBUF, "%s:are supported by this server", line5.c_str());
- isupport.push_back(buf);
+ line5.append(":are supported by this server");
+ isupport.push_back(line5);
}
}
user->WriteNumeric(RPL_ISUPPORT, "%s %s", user->nick.c_str(), line->c_str());
}
-static void ReqRead(ServerConfig* src, const std::string& tag, const std::string& key, std::string& dest)
-{
- ConfigTag* t = src->ConfValue(tag);
- if (!t || !t->readString(key, dest))
- throw CoreException("You must specify a value for <" + tag + ":" + key + ">");
-}
-
template<typename T, typename V>
static void range(T& value, V min, V max, V def, const char* msg)
{
}
-/* NOTE: Before anyone asks why we're not using inet_pton for this, it is because inet_pton and friends do not return so much detail,
- * even in strerror(errno). They just return 'yes' or 'no' to an address without such detail as to whats WRONG with the address.
- * Because ircd users arent as technical as they used to be (;)) we are going to give more of a useful error message.
- */
static void ValidIP(const std::string& ip, const std::string& key)
{
- const char* p = ip.c_str();
- int num_dots = 0;
- int num_seps = 0;
- int not_numbers = false;
- int not_hex = false;
-
- if (*p)
- {
- if (*p == '.')
- throw CoreException("The value of "+key+" is not an IP address");
-
- for (const char* ptr = p; *ptr; ++ptr)
- {
- if (*ptr != ':' && *ptr != '.')
- {
- if (*ptr < '0' || *ptr > '9')
- not_numbers = true;
- if ((*ptr < '0' || *ptr > '9') && (toupper(*ptr) < 'A' || toupper(*ptr) > 'F'))
- not_hex = true;
- }
- switch (*ptr)
- {
- case ' ':
- throw CoreException("The value of "+key+" is not an IP address");
- case '.':
- num_dots++;
- break;
- case ':':
- num_seps++;
- break;
- }
- }
-
- if (num_dots > 3)
- throw CoreException("The value of "+key+" is an IPv4 address with too many fields!");
-
- if (num_seps > 8)
- throw CoreException("The value of "+key+" is an IPv6 address with too many fields!");
-
- if (num_seps == 0 && num_dots < 3)
- throw CoreException("The value of "+key+" looks to be a malformed IPv4 address");
-
- if (num_seps == 0 && num_dots == 3 && not_numbers)
- throw CoreException("The value of "+key+" contains non-numeric characters in an IPv4 address");
-
- if (num_seps != 0 && not_hex)
- throw CoreException("The value of "+key+" contains non-hexdecimal characters in an IPv6 address");
-
- if (num_seps != 0 && num_dots != 3 && num_dots != 0)
- throw CoreException("The value of "+key+" is a malformed IPv6 4in6 address");
- }
+ irc::sockets::sockaddrs dummy;
+ if (!irc::sockets::aptosa(ip, 0, dummy))
+ throw CoreException("The value of "+key+" is not an IP address");
}
static void ValidHost(const std::string& p, const std::string& msg)
throw CoreException("The value of "+msg+" is not a valid hostname");
}
-// Specialized validators
-
bool ServerConfig::ApplyDisabledCommands(const std::string& data)
{
std::stringstream dcmds(data);
static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::string& key, XLineFactory* make)
{
- for(int i=0;; ++i)
+ ConfigTagList tags = conf->ConfTags(tag);
+ for(ConfigIter i = tags.first; i != tags.second; ++i)
{
- ConfigTag* ctag = conf->ConfValue(tag, i);
- if (!ctag)
- break;
+ ConfigTag* ctag = i->second;
std::string mask;
if (!ctag->readString(key, mask))
throw CoreException("<"+tag+":"+key+"> missing at " + ctag->getTagLocation());
}
}
+typedef std::map<std::string, ConfigTag*> LocalIndex;
void ServerConfig::CrossCheckOperClassType()
{
- for (int i = 0;; ++i)
+ LocalIndex operclass;
+ ConfigTagList tags = ConfTags("class");
+ for(ConfigIter i = tags.first; i != tags.second; ++i)
{
- ConfigTag* tag = ConfValue("class", i);
- if (!tag)
- break;
+ ConfigTag* tag = i->second;
std::string name = tag->getString("name");
if (name.empty())
throw CoreException("<class:name> missing from tag at " + tag->getTagLocation());
operclass[name] = tag;
}
- for (int i = 0;; ++i)
+ tags = ConfTags("type");
+ for(ConfigIter i = tags.first; i != tags.second; ++i)
{
- ConfigTag* tag = ConfValue("type", i);
- if (!tag)
- break;
-
+ ConfigTag* tag = i->second;
std::string name = tag->getString("name");
if (name.empty())
throw CoreException("<type:name> is missing from tag at " + tag->getTagLocation());
- opertypes[name] = tag;
+
+ if (!ServerInstance->IsNick(name.c_str(), Limits.NickMax))
+ throw CoreException("<type:name> is invalid (value '" + name + "')");
+
+ OperInfo* ifo = new OperInfo;
+ oper_blocks[" " + name] = ifo;
+ ifo->name = name;
+ ifo->type_block = tag;
std::string classname;
irc::spacesepstream str(tag->getString("classes"));
while (str.GetToken(classname))
{
- if (operclass.find(classname) == operclass.end())
+ LocalIndex::iterator cls = operclass.find(classname);
+ if (cls == operclass.end())
throw CoreException("Oper type " + name + " has missing class " + classname);
+ ifo->class_blocks.push_back(cls->second);
}
}
+
+ tags = ConfTags("oper");
+ for(ConfigIter i = tags.first; i != tags.second; ++i)
+ {
+ ConfigTag* tag = i->second;
+
+ std::string name = tag->getString("name");
+ if (name.empty())
+ throw CoreException("<oper:name> missing from tag at " + tag->getTagLocation());
+
+ std::string type = tag->getString("type");
+ OperIndex::iterator tblk = oper_blocks.find(" " + type);
+ if (tblk == oper_blocks.end())
+ throw CoreException("Oper block " + name + " has missing type " + type);
+ if (oper_blocks.find(name) != oper_blocks.end())
+ throw CoreException("Duplicate oper block with name " + name);
+
+ OperInfo* ifo = new OperInfo;
+ ifo->name = type;
+ ifo->oper_block = tag;
+ ifo->type_block = tblk->second->type_block;
+ ifo->class_blocks.assign(tblk->second->class_blocks.begin(), tblk->second->class_blocks.end());
+ oper_blocks[name] = ifo;
+ }
}
void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current)
for(ClassVector::iterator i = current->Classes.begin(); i != current->Classes.end(); ++i)
{
ConnectClass* c = *i;
- std::string typeMask = (c->type == CC_ALLOW) ? "a" : "d";
- typeMask += c->host;
- oldBlocksByMask[typeMask] = c;
+ if (c->name.substr(0, 8) != "unnamed-")
+ {
+ oldBlocksByMask["n" + c->name] = c;
+ }
+ else if (c->type == CC_ALLOW || c->type == CC_DENY)
+ {
+ std::string typeMask = (c->type == CC_ALLOW) ? "a" : "d";
+ typeMask += c->host;
+ oldBlocksByMask[typeMask] = c;
+ }
}
}
- ClassMap newBlocksByMask;
+ int blk_count = config_data.count("connect");
+ if (blk_count == 0)
+ {
+ // No connect blocks found; make a trivial default block
+ std::vector<KeyVal>* items;
+ ConfigTag* tag = ConfigTag::create("connect", "<auto>", 0, items);
+ items->push_back(std::make_pair("allow", "*"));
+ config_data.insert(std::make_pair("connect", tag));
+ blk_count = 1;
+ }
+
+ Classes.resize(blk_count);
std::map<std::string, int> names;
bool try_again = true;
for(int tries=0; try_again; tries++)
{
try_again = false;
- for(unsigned int i=0;; i++)
+ ConfigTagList tags = ConfTags("connect");
+ int i=0;
+ for(ConfigIter it = tags.first; it != tags.second; ++it, ++i)
{
- ConfigTag* tag = ConfValue("connect", i);
- if (!tag)
- break;
- if (Classes.size() <= i)
- Classes.resize(i+1);
+ ConfigTag* tag = it->second;
if (Classes[i])
continue;
{
try_again = true;
// couldn't find parent this time. If it's the last time, we'll never find it.
- if (tries == 50)
- throw CoreException("Could not find parent connect class \"" + parentName + "\" for connect block " + ConvToStr(i));
+ if (tries >= blk_count)
+ throw CoreException("Could not find parent connect class \"" + parentName + "\" for connect block at " + tag->getTagLocation());
continue;
}
parent = Classes[parentIter->second];
}
std::string name = tag->getString("name");
- if (!name.empty())
- {
- if (names.find(name) != names.end())
- throw CoreException("Two connect classes with name \"" + name + "\" defined!");
- names[name] = i;
- }
-
std::string mask, typeMask;
char type;
type = CC_DENY;
typeMask = 'd' + mask;
}
+ else if (!name.empty())
+ {
+ type = CC_NAMED;
+ mask = name;
+ typeMask = 'n' + mask;
+ }
+ else
+ {
+ throw CoreException("Connect class must have allow, deny, or name specified at " + tag->getTagLocation());
+ }
+
+ if (name.empty())
+ {
+ name = "unnamed-" + ConvToStr(i);
+ }
else
{
- throw CoreException("Connect class must have an allow or deny mask at " + tag->getTagLocation());
+ typeMask = 'n' + name;
}
- ClassMap::iterator dupMask = newBlocksByMask.find(typeMask);
- if (dupMask != newBlocksByMask.end())
- throw CoreException("Two connect classes cannot have the same mask (" + mask + ")");
+
+ if (names.find(name) != names.end())
+ throw CoreException("Two connect classes with name \"" + name + "\" defined!");
+ names[name] = i;
ConnectClass* me = parent ?
new ConnectClass(tag, type, mask, *parent) :
new ConnectClass(tag, type, mask);
- if (!name.empty())
- me->name = name;
+ me->name = name;
- tag->readString("password", me->pass);
- tag->readString("hash", me->hash);
me->registration_timeout = tag->getInt("timeout", me->registration_timeout);
me->pingtime = tag->getInt("pingfreq", me->pingtime);
std::string sendq;
me->softsendqmax = tag->getInt("softsendq", me->softsendqmax);
me->hardsendqmax = tag->getInt("hardsendq", me->hardsendqmax);
me->recvqmax = tag->getInt("recvq", me->recvqmax);
+ me->penaltythreshold = tag->getInt("threshold", me->penaltythreshold);
+ me->commandrate = tag->getInt("commandrate", me->commandrate);
+ me->fakelag = tag->getBool("fakelag", me->fakelag);
me->maxlocal = tag->getInt("localmax", me->maxlocal);
me->maxglobal = tag->getInt("globalmax", me->maxglobal);
- me->port = tag->getInt("port", me->port);
me->maxchans = tag->getInt("maxchans", me->maxchans);
me->limit = tag->getInt("limit", me->limit);
delete me;
me = old;
}
- newBlocksByMask[typeMask] = me;
Classes[i] = me;
}
}
{"options", "netbuffersize", "has been moved to <performance:netbuffersize> as of 1.2a3"},
{"options", "maxwho", "has been moved to <performance:maxwho> as of 1.2a3"},
{"options", "loglevel", "1.2 does not use the loglevel value. Please define <log> tags instead."},
- {"die", "value", "has always been deprecated"},
+ {"die", "value", "you need to reread your config"},
};
void ServerConfig::Fill()
{
- ReqRead(this, "server", "name", ServerName);
- ReqRead(this, "power", "diepass", diepass);
- ReqRead(this, "power", "restartpass", restartpass);
-
ConfigTag* options = ConfValue("options");
ConfigTag* security = ConfValue("security");
+ diepass = ConfValue("power")->getString("diepass");
+ restartpass = ConfValue("power")->getString("restartpass");
powerhash = ConfValue("power")->getString("hash");
- DieDelay = ConfValue("power")->getInt("pause");
PrefixQuit = options->getString("prefixquit");
SuffixQuit = options->getString("suffixquit");
FixedQuit = options->getString("fixedquit");
SoftLimit = ConfValue("performance")->getInt("softlimit", ServerInstance->SE->GetMaxFds());
MaxConn = ConfValue("performance")->getInt("somaxconn", SOMAXCONN);
MoronBanner = options->getString("moronbanner", "You're banned!");
+ ServerName = ConfValue("server")->getString("name");
ServerDesc = ConfValue("server")->getString("description", "Configure Me");
Network = ConfValue("server")->getString("network", "Network");
sid = ConfValue("server")->getString("id", "");
AdminName = ConfValue("admin")->getString("name", "");
AdminEmail = ConfValue("admin")->getString("email", "null@example.com");
AdminNick = ConfValue("admin")->getString("nick", "admin");
- ModPath = options->getString("moduledir", MOD_PATH);
+ ModPath = ConfValue("path")->getString("moduledir", MOD_PATH);
NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240);
- MaxWhoResults = ConfValue("performance")->getInt("maxwho", 1024);
dns_timeout = ConfValue("dns")->getInt("timeout", 5);
DisabledCommands = ConfValue("disabled")->getString("commands", "");
DisabledDontExist = ConfValue("disabled")->getBool("fakenonexistant");
- SetUser = security->getString("runasuser");
- SetGroup = security->getString("runasgroup");
UserStats = security->getString("userstats");
- CustomVersion = security->getString("customversion");
+ CustomVersion = security->getString("customversion", Network + " IRCd");
HideSplits = security->getBool("hidesplits");
HideBans = security->getBool("hidebans");
HideWhoisServer = security->getString("hidewhois");
WhoWasGroupSize = ConfValue("whowas")->getInt("groupsize");
WhoWasMaxGroups = ConfValue("whowas")->getInt("maxgroups");
WhoWasMaxKeep = ServerInstance->Duration(ConfValue("whowas")->getString("maxkeep"));
- DieValue = ConfValue("die")->getString("value");
- MaxChans = ConfValue("channels")->getInt("users");
- OperMaxChans = ConfValue("channels")->getInt("opers");
- c_ipv4_range = ConfValue("cidr")->getInt("ipv4clone");
- c_ipv6_range = ConfValue("cidr")->getInt("ipv6clone");
+ MaxChans = ConfValue("channels")->getInt("users", 20);
+ OperMaxChans = ConfValue("channels")->getInt("opers", 60);
+ c_ipv4_range = ConfValue("cidr")->getInt("ipv4clone", 32);
+ c_ipv6_range = ConfValue("cidr")->getInt("ipv6clone", 128);
Limits.NickMax = ConfValue("limits")->getInt("maxnick", 32);
Limits.ChanMax = ConfValue("limits")->getInt("maxchan", 64);
Limits.MaxModes = ConfValue("limits")->getInt("maxmodes", 20);
range(MaxConn, 0, SOMAXCONN, SOMAXCONN, "<performance:somaxconn>");
range(MaxTargets, 1, 31, 20, "<security:maxtargets>");
range(NetBufferSize, 1024, 65534, 10240, "<performance:netbuffersize>");
- range(MaxWhoResults, 1, 65535, 1024, "<performace:maxwho>");
range(WhoWasGroupSize, 0, 10000, 10, "<whowas:groupsize>");
range(WhoWasMaxGroups, 0, 1000000, 10240, "<whowas:maxgroups>");
range(WhoWasMaxKeep, 3600, INT_MAX, 3600, "<whowas:maxkeep>");
if (!sid.empty() && !ServerInstance->IsSID(sid))
throw CoreException(sid + " is not a valid server ID. A server ID must be 3 characters long, with the first character a digit and the next two characters a digit or letter.");
- for (int i = 0;; ++i)
+ std::string defbind = options->getString("defaultbind");
+ if (assign(defbind) == "ipv4")
{
- ConfigTag* tag = ConfValue("uline", i);
- if (!tag)
- break;
+ WildcardIPv6 = false;
+ }
+ else if (assign(defbind) == "ipv6")
+ {
+ WildcardIPv6 = true;
+ }
+ else
+ {
+ WildcardIPv6 = true;
+ int socktest = socket(AF_INET6, SOCK_STREAM, 0);
+ if (socktest < 0)
+ WildcardIPv6 = false;
+ else
+ close(socktest);
+ }
+ ConfigTagList tags = ConfTags("uline");
+ for(ConfigIter i = tags.first; i != tags.second; ++i)
+ {
+ ConfigTag* tag = i->second;
std::string server;
if (!tag->readString("server", server))
throw CoreException("<uline> tag missing server at " + tag->getTagLocation());
ulines[assign(server)] = tag->getBool("silent");
}
- for(int i=0;; ++i)
+ tags = ConfTags("banlist");
+ for(ConfigIter i = tags.first; i != tags.second; ++i)
{
- ConfigTag* tag = ConfValue("banlist", i);
- if (!tag)
- break;
+ ConfigTag* tag = i->second;
std::string chan;
if (!tag->readString("chan", chan))
throw CoreException("<banlist> tag missing chan at " + tag->getTagLocation());
Limits.Finalise();
}
-/* These tags MUST occur and must ONLY occur once in the config file */
-static const char* const Once[] = { "server", "admin", "files", "power", "options" };
-
// WARNING: it is not safe to use most of the codebase in this function, as it
// will run in the config reader thread
void ServerConfig::Read()
}
if (valid)
{
- ReadFile(MOTD, ConfValue("files")->getString("motd"));
- ReadFile(RULES, ConfValue("files")->getString("rules"));
DNSServer = ConfValue("dns")->getString("server");
FindDNS(DNSServer);
}
/* The stuff in here may throw CoreException, be sure we're in a position to catch it. */
try
{
- /* Check we dont have more than one of singular tags, or any of them missing
- */
- for (int Index = 0; Index * sizeof(*Once) < sizeof(Once); Index++)
- {
- std::string tag = Once[Index];
- if (!ConfValue(tag))
- throw CoreException("You have not defined a <"+tag+"> tag, this is required.");
- if (ConfValue(tag, 1))
- {
- errstr << "You have more than one <" << tag << "> tag.\n"
- << "First occurrence at " << ConfValue(tag, 0)->getTagLocation()
- << "; second occurrence at " << ConfValue(tag, 1)->getTagLocation() << std::endl;
- }
- }
-
for (int Index = 0; Index * sizeof(Deprecated) < sizeof(ChangedConfig); Index++)
{
std::string dummy;
// write once here, to try it out and make sure its ok
ServerInstance->WritePID(this->PID);
+ // Check errors before dealing with failed binds, since continuing on failed bind is wanted in some circumstances.
+ valid = errstr.str().empty();
+
/*
* These values can only be set on boot. Keep their old values. Do it before we send messages so we actually have a servername.
*/
{
this->ServerName = old->ServerName;
this->sid = old->sid;
- this->argv = old->argv;
- this->argc = old->argc;
+ this->cmdline = old->cmdline;
// Same for ports... they're bound later on first run.
FailedPortList pl;
User* user = useruid.empty() ? NULL : ServerInstance->FindNick(useruid);
- valid = errstr.str().empty();
if (!valid)
ServerInstance->Logs->Log("CONFIG",DEFAULT, "There were errors in your configuration file:");
ServerInstance->Exit(EXIT_STATUS_CONFIG);
}
- if (ConfValue("options")->getBool("allowhalfop"))
- ServerInstance->Modes->AddMode(new ModeChannelHalfOp);
-
return;
}
void ServerConfig::ApplyModules(User* user)
{
- bool AllowHalfOp = ConfValue("options")->getBool("allowhalfop");
- ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL);
- if (AllowHalfOp && !mh) {
- ServerInstance->Logs->Log("CONFIG", DEFAULT, "Enabling halfop mode.");
- mh = new ModeChannelHalfOp;
- ServerInstance->Modes->AddMode(mh);
- } else if (!AllowHalfOp && mh) {
- ServerInstance->Logs->Log("CONFIG", DEFAULT, "Disabling halfop mode.");
- ServerInstance->Modes->DelMode(mh);
- delete mh;
- }
-
Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so");
if (whowas)
WhowasRequest(NULL, whowas, WhowasRequest::WHOWAS_PRUNE).Send();
std::vector<std::string> added_modules;
std::set<std::string> removed_modules(v.begin(), v.end());
- for(int i=0; ; i++)
+ ConfigTagList tags = ConfTags("module");
+ for(ConfigIter i = tags.first; i != tags.second; ++i)
{
- ConfigTag* tag = ConfValue("module", i);
- if (!tag)
- break;
+ ConfigTag* tag = i->second;
std::string name;
if (tag->readString("name", name))
{
}
}
+ if (ConfValue("options")->getBool("allowhalfop") && removed_modules.erase("m_halfop.so") == 0)
+ added_modules.push_back("m_halfop.so");
+
for (std::set<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
{
// Don't remove cmd_*.so, just remove m_*.so
return (path.length() > 2 && isalpha(path[0]) && path[1] == ':');
}
-ConfigTag* ServerConfig::ConfValue(const std::string &tag, int offset)
+ConfigTag* ServerConfig::ConfValue(const std::string &tag)
{
- ConfigDataHash::size_type pos = offset;
- if (pos >= config_data.count(tag))
- return NULL;
-
ConfigDataHash::iterator iter = config_data.find(tag);
-
- for(int i = 0; i < offset; i++)
- iter++;
-
+ if (iter == config_data.end())
+ return NULL;
return iter->second;
}
-bool ConfigTag::readString(const std::string& key, std::string& value, bool allow_lf)
-{
- if (!this)
- return false;
- for(std::vector<KeyVal>::iterator j = items.begin(); j != items.end(); ++j)
- {
- if(j->first != key)
- continue;
- value = j->second;
- if (!allow_lf && (value.find('\n') != std::string::npos))
- {
- ServerInstance->Logs->Log("CONFIG",DEFAULT, "Value of <" + tag + ":" + key + "> at " + getTagLocation() +
- " contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces.");
- for (std::string::iterator n = value.begin(); n != value.end(); n++)
- if (*n == '\n')
- *n = ' ';
- }
- return true;
- }
- return false;
-}
-
-std::string ConfigTag::getString(const std::string& key, const std::string& def)
-{
- std::string res = def;
- readString(key, res);
- return res;
-}
-
-long ConfigTag::getInt(const std::string &key, long def)
-{
- std::string result;
- if(!readString(key, result))
- return def;
-
- const char* res_cstr = result.c_str();
- char* res_tail = NULL;
- long res = strtol(res_cstr, &res_tail, 0);
- if (res_tail == res_cstr)
- return def;
- switch (toupper(*res_tail))
- {
- case 'K':
- res= res* 1024;
- break;
- case 'M':
- res= res* 1024 * 1024;
- break;
- case 'G':
- res= res* 1024 * 1024 * 1024;
- break;
- }
- return res;
-}
-
-double ConfigTag::getFloat(const std::string &key, double def)
-{
- std::string result;
- if (!readString(key, result))
- return def;
- return strtod(result.c_str(), NULL);
-}
-
-bool ConfigTag::getBool(const std::string &key, bool def)
-{
- std::string result;
- if(!readString(key, result))
- return def;
-
- return (result == "yes" || result == "true" || result == "1" || result == "on");
-}
-
-std::string ConfigTag::getTagLocation()
-{
- return src_name + ":" + ConvToStr(src_line);
-}
-
-/** Read the contents of a file located by `fname' into a file_cache pointed at by `F'.
- */
-bool ServerConfig::ReadFile(file_cache &F, const std::string& fname)
+ConfigTagList ServerConfig::ConfTags(const std::string& tag)
{
- if (fname.empty())
- return false;
-
- FILE* file = NULL;
- char linebuf[MAXBUF];
-
- F.clear();
-
- if (!FileExists(fname.c_str()))
- return false;
- file = fopen(fname.c_str(), "r");
-
- if (file)
- {
- while (!feof(file))
- {
- if (fgets(linebuf, sizeof(linebuf), file))
- linebuf[strlen(linebuf)-1] = 0;
- else
- *linebuf = 0;
-
- F.push_back(*linebuf ? linebuf : " ");
- }
-
- fclose(file);
- }
- else
- return false;
-
- return true;
+ return config_data.equal_range(tag);
}
bool ServerConfig::FileExists(const char* file)
void ConfigReaderThread::Run()
{
- Config = new ServerConfig;
Config->Read();
done = true;
}
ServerInstance->Res->Rehash();
ServerInstance->ResetMaxBans();
Config->ApplyDisabledCommands(Config->DisabledCommands);
- User* user = TheUserUID.empty() ? ServerInstance->FindNick(TheUserUID) : NULL;
+ User* user = ServerInstance->FindNick(TheUserUID);
FOREACH_MOD(I_OnRehash, OnRehash(user));
ServerInstance->BuildISupport();
- delete old;
+ Config = old;
}
else
{
ServerInstance->Logs->CloseLogs();
ServerInstance->Config = old;
ServerInstance->Logs->OpenFileLogs();
- delete this->Config;
}
}