diff options
author | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2006-01-27 15:26:59 +0000 |
---|---|---|
committer | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2006-01-27 15:26:59 +0000 |
commit | 653638c68684ec035fd58bc2d0d91c9bf9aa2ab9 (patch) | |
tree | 364fd9cce4e2e8d6e86ddc3f1267b98dbed51854 | |
parent | 469c2e7f5ad7d3f4d7d150d643ce363a650f19b9 (diff) |
Improved IP handling. Now uses in_addr to store client ip, not char[16]!
Added global and local session limits
All of this needs TESTING.
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@2934 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r-- | docs/inspircd.conf.example | 27 | ||||
-rw-r--r-- | include/connection.h | 6 | ||||
-rw-r--r-- | include/users.h | 15 | ||||
-rw-r--r-- | src/commands.cpp | 4 | ||||
-rw-r--r-- | src/dnsqueue.cpp | 2 | ||||
-rw-r--r-- | src/inspircd.cpp | 5 | ||||
-rw-r--r-- | src/inspircd_io.cpp | 13 | ||||
-rw-r--r-- | src/modules/m_spanningtree.cpp | 8 | ||||
-rw-r--r-- | src/modules/m_userip.cpp | 2 | ||||
-rw-r--r-- | src/userprocess.cpp | 14 | ||||
-rw-r--r-- | src/users.cpp | 60 | ||||
-rw-r--r-- | src/xline.cpp | 2 |
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); |