summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/inspircd.conf.example27
-rw-r--r--include/connection.h6
-rw-r--r--include/users.h15
-rw-r--r--src/commands.cpp4
-rw-r--r--src/dnsqueue.cpp2
-rw-r--r--src/inspircd.cpp5
-rw-r--r--src/inspircd_io.cpp13
-rw-r--r--src/modules/m_spanningtree.cpp8
-rw-r--r--src/modules/m_userip.cpp2
-rw-r--r--src/userprocess.cpp14
-rw-r--r--src/users.cpp60
-rw-r--r--src/xline.cpp2
12 files changed, 113 insertions, 45 deletions
diff --git a/docs/inspircd.conf.example b/docs/inspircd.conf.example
index 9665bfae9..2d753b337 100644
--- a/docs/inspircd.conf.example
+++ b/docs/inspircd.conf.example
@@ -145,13 +145,14 @@
# #
# Syntax is as follows: #
# #
-# <connect allow="ip or host"> #
-# <connect allow="ip or host" password="blahblah"> #
-# <connect allow="ip or host" password="blah" timeout="10"> #
-# <connect allow="ip or host" timeout="blah" flood="5"> #
-# <connect allow="ip or host" threshold="8" pingfreq="120"> #
-# <connect allow="ip or host" sendq="99999" revcq="696969"> #
-# <connect deny="ip or host"> #
+# <connect allow="ip mask"> #
+# <connect allow="ip mask" password="blahblah"> #
+# <connect allow="ip mask" password="blah" timeout="10"> #
+# <connect allow="ip mask" timeout="blah" flood="5"> #
+# <connect allow="ip mask" threshold="8" pingfreq="120"> #
+# <connect allow="ip mask" sendq="99999" revcq="696969"> #
+# <connect allow="ip mask" maxlocal="3" maxglobal="3"> #
+# <connect deny="ip mask"> #
# #
# You may optionally include timeout="x" on any allow line, which #
# specifies the amount of time given before an unknown connection #
@@ -188,9 +189,19 @@
# that of the user... Just to clear up any confusion or complaints #
# that these are backwards :p #
# #
+# The maxlocal and maxglobal values can be used to enforce local #
+# and global session limits on connections. The session limits are #
+# counted against all users, but applied only to users within the #
+# class. For example, if you had a class 'A' which has a session #
+# limit of 3, and a class 'B' which has a session limit of 5, and #
+# somehow, two users managed to get into class B which also match #
+# class A, there is only one connection left for this IP now in A, #
+# but if they can connect again to B, there are three. You get the #
+# idea (i hope). #
+# #
<connect allow="196.12.*" password="secret">
-<connect allow="*" timeout="60" flood="10" threshold="60" pingfreq="120" sendq="262144" recvq="4096">
+<connect allow="*" timeout="60" flood="10" threshold="60" pingfreq="120" sendq="262144" recvq="4096" maxlocal="3" maxglobal="3">
<connect deny="69.254.*">
diff --git a/include/connection.h b/include/connection.h
index d3e635aa9..db76859d7 100644
--- a/include/connection.h
+++ b/include/connection.h
@@ -44,11 +44,7 @@ class connection : public Extensible
/** Hostname of connection. Not used if this is a serverrec
*/
char host[160];
-
- /** IP of connection.
- */
- char ip[16];
-
+
/** Stats counter for bytes inbound
*/
int bytes_in;
diff --git a/include/users.h b/include/users.h
index c22964a4c..e1bf887bd 100644
--- a/include/users.h
+++ b/include/users.h
@@ -83,6 +83,14 @@ class ConnectClass : public classbase
/** Maximum size of recvq for users in this class (bytes)
*/
long recvqmax;
+
+ /** Local max when connecting by this connection class
+ */
+ long maxlocal;
+
+ /** Global max when connecting by this connection class
+ */
+ long maxglobal;
ConnectClass() : registration_timeout(0), flood(0), host(""), pingtime(0), pass(""), threshold(0), sendqmax(0), recvqmax(0)
{
@@ -204,6 +212,10 @@ class userrec : public connection
time_t reset_due;
long threshold;
+ /** IPV4 ip address
+ */
+ in_addr ip4;
+
/* Write error string
*/
std::string WriteError;
@@ -347,9 +359,8 @@ void DeleteOper(userrec* user);
void kill_link(userrec *user,const char* r);
void kill_link_silent(userrec *user,const char* r);
void AddWhoWas(userrec* u);
-void AddClient(int socket, char* host, int port, bool iscached, char* ip);
+void AddClient(int socket, int port, bool iscached, in_addr ip4);
void FullConnectUser(userrec* user, CullList* Goners);
-//void ConnectUser(userrec *user, CullList* Goners);
userrec* ReHashNick(char* Old, char* New);
void force_nickchange(userrec* user,const char* newnick);
diff --git a/src/commands.cpp b/src/commands.cpp
index e9b921beb..37f1fcef2 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -119,7 +119,7 @@ void do_whois(userrec* user, userrec* dest,unsigned long signon, unsigned long i
WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
if ((user == dest) || (strchr(user->modes,'o')))
{
- WriteServ(user->fd,"378 %s %s :is connecting from *@%s %s",user->nick, dest->nick, dest->host, dest->ip);
+ WriteServ(user->fd,"378 %s %s :is connecting from *@%s %s",user->nick, dest->nick, dest->host, (char*)inet_ntoa(dest->ip4));
}
std::string cl = chlist(dest,user);
if (cl.length())
@@ -309,7 +309,7 @@ bool ip_matches_everyone(std::string ip, userrec* user)
long matches = 0;
for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
{
- if (match(u->second->ip,ip.c_str()))
+ if (match((char*)inet_ntoa(u->second->ip4),ip.c_str()))
matches++;
}
float percent = ((float)matches / (float)clientlist.size()) * 100;
diff --git a/src/dnsqueue.cpp b/src/dnsqueue.cpp
index 7e2ad86c3..dee671aa1 100644
--- a/src/dnsqueue.cpp
+++ b/src/dnsqueue.cpp
@@ -125,7 +125,7 @@ public:
}
if ((hostname != "") && (usr->registered != 7))
{
- if (std::string(usr->ip) == ip)
+ if (std::string((char*)inet_ntoa(usr->ip4)) == ip)
{
strlcpy(usr->host,hostname.c_str(),MAXBUF);
strlcpy(usr->dhost,hostname.c_str(),MAXBUF);
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 4b390eeb0..a834d4d5c 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -714,7 +714,6 @@ int InspIRCd::Run()
{
in_port = ntohs(sock_us.sin_port);
log(DEBUG,"Accepted socket %d",incomingSockfd);
- target = (char*)inet_ntoa(client.sin_addr);
/* Years and years ago, we used to resolve here
* using gethostbyaddr(). That is sucky and we
* don't do that any more...
@@ -722,10 +721,10 @@ int InspIRCd::Run()
NonBlocking(incomingSockfd);
if (Config->GetIOHook(in_port))
{
- Config->GetIOHook(in_port)->OnRawSocketAccept(incomingSockfd, target, in_port);
+ Config->GetIOHook(in_port)->OnRawSocketAccept(incomingSockfd, (char*)inet_ntoa(client.sin_addr), in_port);
}
stats->statsAccept++;
- AddClient(incomingSockfd, target, in_port, false, target);
+ AddClient(incomingSockfd, in_port, false, client.sin_addr);
log(DEBUG,"Adding client on port %lu fd=%lu",(unsigned long)in_port,(unsigned long)incomingSockfd);
}
else
diff --git a/src/inspircd_io.cpp b/src/inspircd_io.cpp
index a52c5933b..8534af18e 100644
--- a/src/inspircd_io.cpp
+++ b/src/inspircd_io.cpp
@@ -149,6 +149,7 @@ void ServerConfig::Read(bool bail, userrec* user)
{
char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF],MW[MAXBUF],MCON[MAXBUF],MT[MAXBUF];
char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF],DNT[MAXBUF],pfreq[MAXBUF],thold[MAXBUF],sqmax[MAXBUF],rqmax[MAXBUF],SLIMT[MAXBUF];
+ char localmax[MAXBUF],globalmax[MAXBUF];
ConnectClass c;
std::stringstream errstr;
include_stack.clear();
@@ -293,6 +294,8 @@ void ServerConfig::Read(bool bail, userrec* user)
ConfValue("connect","threshold",i,thold,&Config->config_f);
ConfValue("connect","sendq",i,sqmax,&Config->config_f);
ConfValue("connect","recvq",i,rqmax,&Config->config_f);
+ ConfValue("connect","localmax",i,localmax,&Config->config_f);
+ ConfValue("connect","globalmax",i,globalmax,&Config->config_f);
if (*Value)
{
c.host = Value;
@@ -306,6 +309,16 @@ void ServerConfig::Read(bool bail, userrec* user)
c.threshold = 5;
c.sendqmax = 262144; // 256k
c.recvqmax = 4096; // 4k
+ c.maxlocal = 3;
+ c.maxglobal = 3;
+ if (atoi(localmax)>0)
+ {
+ c.maxlocal = atoi(localmax);
+ }
+ if (atoi(globalmax)>0)
+ {
+ c.maxglobal = atoi(globalmax);
+ }
if (atoi(thold)>0)
{
c.threshold = atoi(thold);
diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp
index e694c4570..160632bef 100644
--- a/src/modules/m_spanningtree.cpp
+++ b/src/modules/m_spanningtree.cpp
@@ -1069,7 +1069,7 @@ class TreeSocket : public InspSocket
clientlist[tempnick]->registered = 7;
clientlist[tempnick]->signon = age;
strlcpy(clientlist[tempnick]->modes, modes.c_str(),53);
- strlcpy(clientlist[tempnick]->ip,ip.c_str(),16);
+ inet_aton(ip.c_str(),&clientlist[tempnick]->ip4);
ucrec a;
a.channel = NULL;
@@ -1079,7 +1079,7 @@ class TreeSocket : public InspSocket
if (!this->bursting)
{
- WriteOpers("*** Client connecting at %s: %s!%s@%s [%s]",clientlist[tempnick]->server,clientlist[tempnick]->nick,clientlist[tempnick]->ident,clientlist[tempnick]->host,clientlist[tempnick]->ip);
+ WriteOpers("*** Client connecting at %s: %s!%s@%s [%s]",clientlist[tempnick]->server,clientlist[tempnick]->nick,clientlist[tempnick]->ident,clientlist[tempnick]->host,(char*)inet_ntoa(clientlist[tempnick]->ip4));
}
params[7] = ":" + params[7];
DoOneToAllButSender(source,"NICK",params,source);
@@ -1210,7 +1210,7 @@ class TreeSocket : public InspSocket
{
if (u->second->registered == 7)
{
- snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->modes,u->second->ip,u->second->fullname);
+ snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->modes,(char*)inet_ntoa(u->second->ip4),u->second->fullname);
this->WriteLine(data);
if (strchr(u->second->modes,'o'))
{
@@ -3028,7 +3028,7 @@ class ModuleSpanningTree : public Module
params.push_back(user->dhost);
params.push_back(user->ident);
params.push_back("+"+std::string(user->modes));
- params.push_back(user->ip);
+ params.push_back((char*)inet_ntoa(user->ip4));
params.push_back(":"+std::string(user->fullname));
DoOneToMany(Srv->GetServerName(),"NICK",params);
diff --git a/src/modules/m_userip.cpp b/src/modules/m_userip.cpp
index fe37ebc7f..48befe370 100644
--- a/src/modules/m_userip.cpp
+++ b/src/modules/m_userip.cpp
@@ -44,7 +44,7 @@ class cmd_userip : public command_t
userrec *u = Find(parameters[i]);
if (u)
{
- snprintf(junk,MAXBUF,"%s%s=+%s@%s ",u->nick,strchr(u->modes,'o') ? "*" : "",u->ident,u->ip);
+ snprintf(junk,MAXBUF,"%s%s=+%s@%s ",u->nick,strchr(u->modes,'o') ? "*" : "",u->ident,(char*)inet_ntoa(u->ip4));
strlcat(Return,junk,MAXBUF);
}
}
diff --git a/src/userprocess.cpp b/src/userprocess.cpp
index c7e7aa545..29560871f 100644
--- a/src/userprocess.cpp
+++ b/src/userprocess.cpp
@@ -148,9 +148,9 @@ void ProcessUser(userrec* cu)
}
else
{
- WriteOpers("*** Excess flood from %s",current->ip);
- log(DEFAULT,"Excess flood from: %s",current->ip);
- add_zline(120,Config->ServerName,"Flood from unregistered connection",current->ip);
+ WriteOpers("*** Excess flood from %s",(char*)inet_ntoa(current->ip4));
+ log(DEFAULT,"Excess flood from: %s",(char*)inet_ntoa(current->ip4));
+ add_zline(120,Config->ServerName,"Flood from unregistered connection",(char*)inet_ntoa(current->ip4));
apply_lines(APPLY_ZLINES);
}
return;
@@ -163,9 +163,9 @@ void ProcessUser(userrec* cu)
}
else
{
- WriteOpers("*** Excess flood from %s",current->ip);
- log(DEFAULT,"Excess flood from: %s",current->ip);
- add_zline(120,Config->ServerName,"Flood from unregistered connection",current->ip);
+ WriteOpers("*** Excess flood from %s",(char*)inet_ntoa(current->ip4));
+ log(DEFAULT,"Excess flood from: %s",(char*)inet_ntoa(current->ip4));
+ add_zline(120,Config->ServerName,"Flood from unregistered connection",(char*)inet_ntoa(current->ip4));
apply_lines(APPLY_ZLINES);
}
return;
@@ -197,7 +197,7 @@ void ProcessUser(userrec* cu)
}
else
{
- add_zline(120,Config->ServerName,"Flood from unregistered connection",current->ip);
+ add_zline(120,Config->ServerName,"Flood from unregistered connection",(char*)inet_ntoa(current->ip4));
apply_lines(APPLY_ZLINES);
}
return;
diff --git a/src/users.cpp b/src/users.cpp
index 8bc2f8baa..8089f5c23 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -64,7 +64,7 @@ template<typename T> inline string ConvToStr(const T &in)
userrec::userrec()
{
// the PROPER way to do it, AVOID bzero at *ALL* costs
- *nick = *ident = *host = *dhost = *fullname = *modes = *awaymsg = *oper = *ip = 0;
+ *nick = *ident = *host = *dhost = *fullname = *modes = *awaymsg = *oper = 0;
server = (char*)FindServerNamePtr(Config->ServerName);
reset_due = TIME;
lines_in = fd = lastping = signon = idle_lastmsg = nping = registered = 0;
@@ -554,14 +554,14 @@ void AddWhoWas(userrec* u)
}
/* add a client connection to the sockets list */
-void AddClient(int socket, char* host, int port, bool iscached, char* ip)
+void AddClient(int socket, int port, bool iscached, in_addr ip4)
{
string tempnick;
char tn2[MAXBUF];
user_hash::iterator iter;
tempnick = ConvToStr(socket) + "-unknown";
- sprintf(tn2,"%lu-unknown",(unsigned long)socket);
+ sprintf(tn2,"%d-unknown",socket);
iter = clientlist.find(tempnick);
@@ -588,19 +588,24 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
*/
clientlist[tempnick] = new userrec();
- log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip);
+ char *ipaddr = (char*)inet_ntoa(ip4);
+
+ log(DEBUG,"AddClient: %d %d %s",socket,port,ipaddr);
clientlist[tempnick]->fd = socket;
strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX);
- strlcpy(clientlist[tempnick]->host, host,160);
- strlcpy(clientlist[tempnick]->dhost, host,160);
+ /* We don't know the host yet, dns lookup could still be going on,
+ * so instead we just put the ip address here, for now.
+ */
+ strlcpy(clientlist[tempnick]->host, ipaddr, 160);
+ strlcpy(clientlist[tempnick]->dhost, ipaddr, 160);
clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName);
strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX);
clientlist[tempnick]->registered = 0;
clientlist[tempnick]->signon = TIME + Config->dns_timeout;
clientlist[tempnick]->lastping = 1;
+ clientlist[tempnick]->ip4 = ip4;
clientlist[tempnick]->port = port;
- strlcpy(clientlist[tempnick]->ip,ip,16);
// set the registration timeout for this user
unsigned long class_regtimeout = 90;
@@ -611,7 +616,7 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
{
- if (match(clientlist[tempnick]->host,i->host.c_str()) && (i->type == CC_ALLOW))
+ if (match(ipaddr,i->host.c_str()) && (i->type == CC_ALLOW))
{
class_regtimeout = (unsigned long)i->registration_timeout;
class_flood = i->flood;
@@ -660,10 +665,10 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
kill_link(clientlist[tempnick],"Server is full");
return;
}
- char* e = matches_exception(ip);
+ char* e = matches_exception(ipaddr);
if (!e)
{
- char* r = matches_zline(ip);
+ char* r = matches_zline(ipaddr);
if (r)
{
char reason[MAXBUF];
@@ -679,6 +684,29 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
WriteServ(clientlist[tempnick]->fd,"NOTICE Auth :*** Looking up your hostname...");
}
+long FindMatchingGlobal(userrec* user)
+{
+ long x = 0;
+ for (user_hash::const_iterator a = clientlist.begin(); a != clientlist.end(); a++)
+ {
+ if (a->second->ip4.s_addr == user->ip4.s_addr)
+ x++;
+ }
+ return x;
+}
+
+long FindMatchingLocal(userrec* user)
+{
+ long x = 0;
+ for (std::vector<userrec*>::const_iterator a = local_users.begin(); a != local_users.end(); a++)
+ {
+ userrec* comp = (userrec*)(*a);
+ if (comp->ip4.s_addr == user->ip4.s_addr)
+ x++;
+ }
+ return x;
+}
+
void FullConnectUser(userrec* user, CullList* Goners)
{
ServerInstance->stats->statsConnects++;
@@ -697,6 +725,16 @@ void FullConnectUser(userrec* user, CullList* Goners)
Goners->AddItem(user,"Invalid password");
return;
}
+ if (FindMatchingLocal(user) > a.maxlocal)
+ {
+ Goners->AddItem(user,"No more connections allowed from your host via this connect class (local)");
+ return;
+ }
+ if (FindMatchingGlobal(user) > a.maxglobal)
+ {
+ Goners->AddItem(user,"No more connections allowed from your host via this connect class (global)");
+ return;
+ }
char match_against[MAXBUF];
snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
@@ -752,7 +790,7 @@ void FullConnectUser(userrec* user, CullList* Goners)
FOREACH_MOD(I_OnUserConnect,OnUserConnect(user));
FOREACH_MOD(I_OnGlobalConnect,OnGlobalConnect(user));
user->registered = 7;
- WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip);
+ WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,(char*)inet_ntoa(user->ip4));
}
/* re-allocates a nick in the user_hash after they change nicknames,
diff --git a/src/xline.cpp b/src/xline.cpp
index ed16fc4c1..bfffd0d84 100644
--- a/src/xline.cpp
+++ b/src/xline.cpp
@@ -692,7 +692,7 @@ void apply_lines(const int What)
}
if ((What & APPLY_ZLINES) && (zlines.size() || pzlines.size()))
{
- if ((check = matches_zline(u->ip)))
+ if ((check = matches_zline((char*)inet_ntoa(u->ip4))))
{
snprintf(reason,MAXBUF,"Z-Lined: %s",check);
Goners->AddItem(u,reason);