int InspIRCd::BindPorts(FailedPortList& failed_ports) { int bound = 0; std::vector<ListenSocket*> old_ports(ports.begin(), ports.end()); ConfigTagList tags = ServerInstance->Config->ConfTags("bind"); for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; // Are we creating a TCP/IP listener? const std::string address = tag->getString("address"); const std::string portlist = tag->getString("port"); if (!address.empty() || !portlist.empty()) { // InspIRCd supports IPv4 and IPv6 natively; no 4in6 required. if (strncasecmp(address.c_str(), "::ffff:", 7) == 0) this->Logs.Log("SOCKET", LOG_DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead."); // A TCP listener with no ports is not very useful. if (portlist.empty()) this->Logs.Log("SOCKET", LOG_DEFAULT, "TCP listener on %s at %s has no ports specified!", address.empty() ? "*" : address.c_str(), tag->getTagLocation().c_str()); irc::portparser portrange(portlist, false); for (int port; (port = portrange.GetToken()); ) { irc::sockets::sockaddrs bindspec; if (!irc::sockets::aptosa(address, port, bindspec)) continue; if (!BindPort(tag, bindspec, old_ports)) failed_ports.push_back(std::make_pair(bindspec, errno)); else bound++; } continue; } #ifndef _WIN32 // Are we creating a UNIX listener? const std::string path = tag->getString("path"); if (!path.empty()) { // UNIX socket paths are length limited to less than PATH_MAX. irc::sockets::sockaddrs bindspec; if (path.length() > std::min(ServerInstance->Config->Limits.MaxHost, sizeof(bindspec.un.sun_path))) { this->Logs.Log("SOCKET", LOG_DEFAULT, "UNIX listener on %s at %s specified a path that is too long!", path.c_str(), tag->getTagLocation().c_str()); continue; } // Create the bindspec manually (aptosa doesn't work with AF_UNIX yet). memset(&bindspec, 0, sizeof(bindspec)); bindspec.un.sun_family = AF_UNIX; memcpy(&bindspec.un.sun_path, path.c_str(), sizeof(bindspec.un.sun_path)); if (!BindPort(tag, bindspec, old_ports)) failed_ports.push_back(std::make_pair(bindspec, errno)); else bound++; } #endif } std::vector<ListenSocket*>::iterator n = ports.begin(); for (std::vector<ListenSocket*>::iterator o = old_ports.begin(); o != old_ports.end(); ++o) { while (n != ports.end() && *n != *o) n++; if (n == ports.end()) { this->Logs.Log("SOCKET", LOG_DEFAULT, "Port bindings slipped out of vector, aborting close!"); break; } this->Logs.Log("SOCKET", LOG_DEFAULT, "Port binding %s was removed from the config file, closing.", (**n).bind_sa.str().c_str()); delete *n; // this keeps the iterator valid, pointing to the next element n = ports.erase(n); } return bound; }
int InspIRCd::BindPorts(FailedPortList &failed_ports) { int bound = 0; std::vector<ListenSocket*> old_ports(ports.begin(), ports.end()); ConfigTagList tags = ServerInstance->Config->ConfTags("bind"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string porttag = tag->getString("port"); std::string Addr = tag->getString("address"); if (strncasecmp(Addr.c_str(), "::ffff:", 7) == 0) this->Logs->Log("SOCKET", LOG_DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead."); irc::portparser portrange(porttag, false); int portno = -1; while (0 != (portno = portrange.GetToken())) { irc::sockets::sockaddrs bindspec; if (!irc::sockets::aptosa(Addr, portno, bindspec)) continue; std::string bind_readable = bindspec.str(); bool skip = false; for (std::vector<ListenSocket*>::iterator n = old_ports.begin(); n != old_ports.end(); ++n) { if ((**n).bind_desc == bind_readable) { (*n)->bind_tag = tag; // Replace tag, we know addr and port match, but other info (type, ssl) may not (*n)->ResetIOHookProvider(); skip = true; old_ports.erase(n); break; } } if (!skip) { ListenSocket* ll = new ListenSocket(tag, bindspec); if (ll->GetFd() > -1) { bound++; ports.push_back(ll); } else { failed_ports.push_back(std::make_pair(bind_readable, strerror(errno))); delete ll; } } } } std::vector<ListenSocket*>::iterator n = ports.begin(); for (std::vector<ListenSocket*>::iterator o = old_ports.begin(); o != old_ports.end(); ++o) { while (n != ports.end() && *n != *o) n++; if (n == ports.end()) { this->Logs->Log("SOCKET", LOG_DEFAULT, "Port bindings slipped out of vector, aborting close!"); break; } this->Logs->Log("SOCKET", LOG_DEFAULT, "Port binding %s was removed from the config file, closing.", (**n).bind_desc.c_str()); delete *n; // this keeps the iterator valid, pointing to the next element n = ports.erase(n); } return bound; }
/** Fill our conf vector with data */ void ReadConf() { DNSBLConfEntries.clear(); ConfigTagList dnsbls = ServerInstance->Config->ConfTags("dnsbl"); for(ConfigIter i = dnsbls.first; i != dnsbls.second; ++i) { ConfigTag* tag = i->second; reference<DNSBLConfEntry> e = new DNSBLConfEntry(); e->name = tag->getString("name"); e->ident = tag->getString("ident"); e->host = tag->getString("host"); e->reason = tag->getString("reason"); e->domain = tag->getString("domain"); if (tag->getString("type") == "bitmask") { e->type = DNSBLConfEntry::A_BITMASK; e->bitmask = tag->getInt("bitmask"); } else { memset(e->records, 0, sizeof(e->records)); e->type = DNSBLConfEntry::A_RECORD; irc::portparser portrange(tag->getString("records"), false); long item = -1; while ((item = portrange.GetToken())) e->records[item] = 1; } e->banaction = str2banaction(tag->getString("action")); e->duration = tag->getDuration("duration", 60, 1); /* Use portparser for record replies */ /* yeah, logic here is a little messy */ if ((e->bitmask <= 0) && (DNSBLConfEntry::A_BITMASK == e->type)) { std::string location = tag->getTagLocation(); ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): invalid bitmask", location.c_str()); } else if (e->name.empty()) { std::string location = tag->getTagLocation(); ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid name", location.c_str()); } else if (e->domain.empty()) { std::string location = tag->getTagLocation(); ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid domain", location.c_str()); } else if (e->banaction == DNSBLConfEntry::I_UNKNOWN) { std::string location = tag->getTagLocation(); ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid banaction", location.c_str()); } else { if (e->reason.empty()) { std::string location = tag->getTagLocation(); ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): empty reason, using defaults", location.c_str()); e->reason = "Your IP has been blacklisted."; } /* add it, all is ok */ DNSBLConfEntries.push_back(e); } } }
void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current) { typedef std::map<std::string, ConnectClass*> ClassMap; ClassMap oldBlocksByMask; if (current) { for(ClassVector::iterator i = current->Classes.begin(); i != current->Classes.end(); ++i) { ConnectClass* c = *i; if (c->name.compare(0, 8, "unnamed-", 8)) { 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; } } } size_t blk_count = config_data.count("connect"); if (blk_count == 0) { // No connect blocks found; make a trivial default block ConfigItems* items; ConfigTag* tag = ConfigTag::create("connect", "<auto>", 0, items); (*items)["allow"] = "*"; config_data.insert(std::make_pair("connect", tag)); blk_count = 1; } Classes.resize(blk_count); std::map<std::string, size_t> names; bool try_again = true; for(size_t tries = 0; try_again; tries++) { try_again = false; ConfigTagList tags = ConfTags("connect"); size_t i = 0; for(ConfigIter it = tags.first; it != tags.second; ++it, ++i) { ConfigTag* tag = it->second; if (Classes[i]) continue; ConnectClass* parent = NULL; std::string parentName = tag->getString("parent"); if (!parentName.empty()) { std::map<std::string, size_t>::const_iterator parentIter = names.find(parentName); if (parentIter == names.end()) { try_again = true; // couldn't find parent this time. If it's the last time, we'll never find it. 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"); std::string mask, typeMask; char type; if (tag->readString("allow", mask, false)) { type = CC_ALLOW; typeMask = 'a' + mask; } else if (tag->readString("deny", mask, false)) { 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 { typeMask = 'n' + name; } 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); me->name = name; me->registration_timeout = tag->getDuration("timeout", me->registration_timeout); me->pingtime = tag->getDuration("pingfreq", me->pingtime); std::string sendq; if (tag->readString("sendq", sendq)) { // attempt to guess a good hard/soft sendq from a single value unsigned long value = strtoul(sendq.c_str(), NULL, 10); if (value > 16384) me->softsendqmax = value / 16; else me->softsendqmax = value; me->hardsendqmax = value * 8; } me->softsendqmax = tag->getUInt("softsendq", me->softsendqmax); me->hardsendqmax = tag->getUInt("hardsendq", me->hardsendqmax); me->recvqmax = tag->getUInt("recvq", me->recvqmax); me->penaltythreshold = tag->getUInt("threshold", me->penaltythreshold); me->commandrate = tag->getUInt("commandrate", me->commandrate); me->fakelag = tag->getBool("fakelag", me->fakelag); me->maxlocal = tag->getUInt("localmax", me->maxlocal); me->maxglobal = tag->getUInt("globalmax", me->maxglobal); me->maxchans = tag->getUInt("maxchans", me->maxchans); me->maxconnwarn = tag->getBool("maxconnwarn", me->maxconnwarn); me->limit = tag->getUInt("limit", me->limit); me->resolvehostnames = tag->getBool("resolvehostnames", me->resolvehostnames); std::string ports = tag->getString("port"); if (!ports.empty()) { irc::portparser portrange(ports, false); while (int port = portrange.GetToken()) me->ports.insert(port); } ClassMap::iterator oldMask = oldBlocksByMask.find(typeMask); if (oldMask != oldBlocksByMask.end()) { ConnectClass* old = oldMask->second; oldBlocksByMask.erase(oldMask); old->Update(me); delete me; me = old; } Classes[i] = me; } } }
bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext) { bool match = false; bool positive = false; if (user->registered != REG_ALL) return false; if (opt_local && !IS_LOCAL(user)) return false; else if (opt_far && IS_LOCAL(user)) return false; if (opt_mode) { for (const char* n = matchtext; *n; n++) { if (*n == '+') { positive = true; continue; } else if (*n == '-') { positive = false; continue; } if (user->IsModeSet(*n) != positive) return false; } return true; } else { /* * This was previously one awesome pile of ugly nested if, when really, it didn't need * to be, since only one condition was ever checked, a chained if works just fine. * -- w00t */ if (opt_metadata) { match = false; const Extensible::ExtensibleStore& list = user->GetExtList(); for(Extensible::ExtensibleStore::const_iterator i = list.begin(); i != list.end(); ++i) if (InspIRCd::Match(i->first->name, matchtext)) match = true; } else if (opt_realname) match = InspIRCd::Match(user->fullname, matchtext); else if (opt_showrealhost) match = InspIRCd::Match(user->host, matchtext, ascii_case_insensitive_map); else if (opt_ident) match = InspIRCd::Match(user->ident, matchtext, ascii_case_insensitive_map); else if (opt_port) { irc::portparser portrange(matchtext, false); long portno = -1; while ((portno = portrange.GetToken())) if (IS_LOCAL(user) && portno == IS_LOCAL(user)->GetServerPort()) { match = true; break; } } else if (opt_away) match = InspIRCd::Match(user->awaymsg, matchtext); else if (opt_time) { long seconds = InspIRCd::Duration(matchtext); // Okay, so time matching, we want all users connected `seconds' ago if (user->age >= ServerInstance->Time() - seconds) match = true; } /* * Once the conditionals have been checked, only check dhost/nick/server * if they didn't match this user -- and only match if we don't find a match. * * This should make things minutely faster, and again, less ugly. * -- w00t */ if (!match) match = InspIRCd::Match(user->dhost, matchtext, ascii_case_insensitive_map); if (!match) match = InspIRCd::Match(user->nick, matchtext); /* Don't allow server name matches if HideWhoisServer is enabled, unless the command user has the priv */ if (!match && (ServerInstance->Config->HideWhoisServer.empty() || cuser->HasPrivPermission("users/auspex"))) match = InspIRCd::Match(user->server, matchtext); return match; } }