mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-02 15:53:14 +02:00
Move "real command" stuff to src/api-command.c and move dopacket() to
src/parse.c. Also re-order functions in parse.c so they appear in logical order (1->2->3->4) rather than various helper functions first and some random order.
This commit is contained in:
@@ -948,3 +948,4 @@ extern int should_show_connect_info(Client *client);
|
||||
extern void send_invalid_channelname(Client *client, char *channelname);
|
||||
extern int is_extended_ban(const char *str);
|
||||
extern int valid_sid(char *name);
|
||||
extern void parse_client_queued(Client *client);
|
||||
|
||||
@@ -128,3 +128,102 @@ void CommandDel(Command *command)
|
||||
{
|
||||
CommandDelX(command, command->cmd);
|
||||
}
|
||||
|
||||
/** Calls the specified command for the user, as if it was received
|
||||
* that way on IRC.
|
||||
* @param client Client that is the source.
|
||||
* @param mtags Message tags for this command.
|
||||
* @param cmd Command to run, eg "JOIN".
|
||||
* @param parc Parameter count plus 1.
|
||||
* @param parv Parameter array.
|
||||
* @note Make sure you terminate the last parv[] parameter with NULL,
|
||||
* this can easily be forgotten, but certain functions depend on it,
|
||||
* you risk crashes otherwise.
|
||||
* @note Once do_cmd() has returned, be sure to check IsDead(client) to
|
||||
* see if the client has been killed. This may happen due to various
|
||||
* reasons, including spamfilter kicking in or some other security
|
||||
* measure.
|
||||
* @note Do not pass insane parameters. The combined size of all parameters
|
||||
* should not exceed 510 bytes, since that is what all code expects.
|
||||
* Similarly, you should not exceed MAXPARA for parc.
|
||||
*/
|
||||
void do_cmd(Client *client, MessageTag *mtags, char *cmd, int parc, char *parv[])
|
||||
{
|
||||
RealCommand *cmptr;
|
||||
|
||||
cmptr = find_Command_simple(cmd);
|
||||
if (cmptr)
|
||||
(*cmptr->func) (client, mtags, parc, parv);
|
||||
}
|
||||
|
||||
/**** This is the "real command" API *****
|
||||
* Perhaps one day we will merge the two, if possible.
|
||||
*/
|
||||
|
||||
RealCommand *CommandHash[256]; /* one per letter */
|
||||
|
||||
void init_CommandHash(void)
|
||||
{
|
||||
memset(CommandHash, 0, sizeof(CommandHash));
|
||||
CommandAdd(NULL, MSG_ERROR, cmd_error, MAXPARA, CMD_UNREGISTERED|CMD_SERVER);
|
||||
CommandAdd(NULL, MSG_VERSION, cmd_version, MAXPARA, CMD_UNREGISTERED|CMD_USER|CMD_SERVER);
|
||||
CommandAdd(NULL, MSG_INFO, cmd_info, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_DNS, cmd_dns, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_REHASH, cmd_rehash, MAXPARA, CMD_USER|CMD_SERVER);
|
||||
CommandAdd(NULL, MSG_RESTART, cmd_restart, 2, CMD_USER);
|
||||
CommandAdd(NULL, MSG_DIE, cmd_die, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_DALINFO, cmd_dalinfo, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_CREDITS, cmd_credits, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_LICENSE, cmd_license, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_MODULE, cmd_module, MAXPARA, CMD_USER);
|
||||
}
|
||||
|
||||
RealCommand *add_Command_backend(char *cmd)
|
||||
{
|
||||
RealCommand *c = safe_alloc(sizeof(RealCommand));
|
||||
|
||||
safe_strdup(c->cmd, cmd);
|
||||
|
||||
/* Add in hash with hash value = first byte */
|
||||
AddListItem(c, CommandHash[toupper(*cmd)]);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline RealCommand *find_Cmd(char *cmd, int flags)
|
||||
{
|
||||
RealCommand *p;
|
||||
for (p = CommandHash[toupper(*cmd)]; p; p = p->next) {
|
||||
if ((flags & CMD_UNREGISTERED) && !(p->flags & CMD_UNREGISTERED))
|
||||
continue;
|
||||
if ((flags & CMD_SHUN) && !(p->flags & CMD_SHUN))
|
||||
continue;
|
||||
if ((flags & CMD_VIRUS) && !(p->flags & CMD_VIRUS))
|
||||
continue;
|
||||
if ((flags & CMD_ALIAS) && !(p->flags & CMD_ALIAS))
|
||||
continue;
|
||||
if (!strcasecmp(p->cmd, cmd))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RealCommand *find_Command(char *cmd, short token, int flags)
|
||||
{
|
||||
Debug((DEBUG_NOTICE, "FindCommand %s", cmd));
|
||||
|
||||
return find_Cmd(cmd, flags);
|
||||
}
|
||||
|
||||
RealCommand *find_Command_simple(char *cmd)
|
||||
{
|
||||
RealCommand *c;
|
||||
|
||||
for (c = CommandHash[toupper(*cmd)]; c; c = c->next)
|
||||
{
|
||||
if (!strcasecmp(c->cmd, cmd))
|
||||
return c;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1060,121 +1060,6 @@ void proceed_normal_client_handshake(Client *client, struct hostent *he)
|
||||
finish_auth(client);
|
||||
}
|
||||
|
||||
int client_lagged_up(Client *client)
|
||||
{
|
||||
if (client->status < CLIENT_STATUS_UNKNOWN)
|
||||
return 0;
|
||||
if (IsServer(client))
|
||||
return 0;
|
||||
if (ValidatePermissionsForPath("immune:lag",client,NULL,NULL,NULL))
|
||||
return 0;
|
||||
if (client->local->since - TStime() < 10)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** read_packet
|
||||
**
|
||||
** Read a 'packet' of data from a connection and process it. Read in 8k
|
||||
** chunks to give a better performance rating (for server connections).
|
||||
** Do some tricky stuff for client connections to make sure they don't do
|
||||
** any flooding >:-) -avalon
|
||||
** If 'doread' is set to 0 then we don't actually read (no recv()),
|
||||
** however we still check if we need to dequeue anything from the recvQ.
|
||||
** This is necessary, since we may have put something on the recvQ due
|
||||
** to fake lag. -- Syzop
|
||||
** With new I/O code, things work differently. Surprise!
|
||||
** read_one_packet() reads packets in and dumps them as quickly as
|
||||
** possible into the client's DBuf. Then we parse data out of the DBuf,
|
||||
** after we're done reading crap.
|
||||
** -- nenolod
|
||||
*/
|
||||
static void parse_client_queued(Client *client)
|
||||
{
|
||||
int dolen = 0;
|
||||
char buf[READBUFSIZE];
|
||||
|
||||
if (IsDNSLookup(client))
|
||||
return; /* we delay processing of data until the host is resolved */
|
||||
|
||||
if (IsIdentLookup(client))
|
||||
return; /* we delay processing of data until identd has replied */
|
||||
|
||||
if (!IsUser(client) && !IsServer(client) && (iConf.handshake_delay > 0) &&
|
||||
(TStime() - client->local->firsttime < iConf.handshake_delay))
|
||||
{
|
||||
return; /* we delay processing of data until set::handshake-delay is reached */
|
||||
}
|
||||
|
||||
while (DBufLength(&client->local->recvQ) && !client_lagged_up(client))
|
||||
{
|
||||
dolen = dbuf_getmsg(&client->local->recvQ, buf);
|
||||
|
||||
if (dolen == 0)
|
||||
return;
|
||||
|
||||
dopacket(client, buf, dolen);
|
||||
|
||||
if (IsDead(client))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Put a packet in the client receive queue and process the data (if
|
||||
* the 'fake lag' rules permit doing so).
|
||||
* @param client The client
|
||||
* @param readbuf The read buffer
|
||||
* @param length The length of the data
|
||||
* @param killsafely If 1 then we may call exit_client() if the client
|
||||
* is flooding. If 0 then we use dead_socket().
|
||||
* @returns 1 in normal circumstances, 0 if client was killed.
|
||||
* @notes If killsafely is 1 and the return value is 0 then
|
||||
* the client was killed - IsDead() is true.
|
||||
* If this is a problem, then set killsafely to 0 when calling.
|
||||
*/
|
||||
int process_packet(Client *client, char *readbuf, int length, int killsafely)
|
||||
{
|
||||
dbuf_put(&client->local->recvQ, readbuf, length);
|
||||
|
||||
/* parse some of what we have (inducing fakelag, etc) */
|
||||
parse_client_queued(client);
|
||||
|
||||
/* We may be killed now, so check for it.. */
|
||||
if (IsDead(client))
|
||||
return 0;
|
||||
|
||||
/* flood from unknown connection */
|
||||
if (IsUnknown(client) && (DBufLength(&client->local->recvQ) > UNKNOWN_FLOOD_AMOUNT*1024))
|
||||
{
|
||||
sendto_snomask(SNO_FLOOD, "Flood from unknown connection %s detected",
|
||||
client->local->sockhost);
|
||||
if (!killsafely)
|
||||
ban_flooder(client);
|
||||
else
|
||||
dead_socket(client, "Flood from unknown connection");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* excess flood check */
|
||||
if (IsUser(client) && DBufLength(&client->local->recvQ) > get_recvq(client))
|
||||
{
|
||||
sendto_snomask(SNO_FLOOD,
|
||||
"*** Flood -- %s!%s@%s (%d) exceeds %d recvQ",
|
||||
client->name[0] ? client->name : "*",
|
||||
client->user ? client->user->username : "*",
|
||||
client->user ? client->user->realhost : "*",
|
||||
DBufLength(&client->local->recvQ), get_recvq(client));
|
||||
if (!killsafely)
|
||||
exit_client(client, NULL, "Excess Flood");
|
||||
else
|
||||
dead_socket(client, "Excess Flood");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void read_packet(int fd, int revents, void *data)
|
||||
{
|
||||
Client *client = data;
|
||||
|
||||
-147
@@ -20,150 +20,3 @@
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
RealCommand *CommandHash[256]; /* one per letter */
|
||||
|
||||
/*
|
||||
** dopacket
|
||||
** client - pointer to client structure for which the buffer data
|
||||
** applies.
|
||||
** buffer - pointr to the buffer containing the newly read data
|
||||
** length - number of valid bytes of data in the buffer
|
||||
**
|
||||
** Note:
|
||||
** It is implicitly assumed that dopacket is called only
|
||||
** with client of "local" variation, which contains all the
|
||||
** necessary fields (buffer etc..)
|
||||
**
|
||||
** Rewritten for linebufs, 19th May 2013. --kaniini
|
||||
*/
|
||||
void dopacket(Client *client, char *buffer, int length)
|
||||
{
|
||||
me.local->receiveB += length; /* Update bytes received */
|
||||
client->local->receiveB += length;
|
||||
if (client->local->receiveB > 1023)
|
||||
{
|
||||
client->local->receiveK += (client->local->receiveB >> 10);
|
||||
client->local->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
|
||||
}
|
||||
if (me.local->receiveB > 1023)
|
||||
{
|
||||
me.local->receiveK += (me.local->receiveB >> 10);
|
||||
me.local->receiveB &= 0x03ff;
|
||||
}
|
||||
|
||||
me.local->receiveM += 1; /* Update messages received */
|
||||
client->local->receiveM += 1;
|
||||
|
||||
parse(client, buffer, length);
|
||||
}
|
||||
|
||||
void init_CommandHash(void)
|
||||
{
|
||||
#ifdef DEVELOP_DEBUG
|
||||
RealCommand *p;
|
||||
int i;
|
||||
long chainlength;
|
||||
#endif
|
||||
|
||||
memset(CommandHash, 0, sizeof(CommandHash));
|
||||
CommandAdd(NULL, MSG_ERROR, cmd_error, MAXPARA, CMD_UNREGISTERED|CMD_SERVER);
|
||||
CommandAdd(NULL, MSG_VERSION, cmd_version, MAXPARA, CMD_UNREGISTERED|CMD_USER|CMD_SERVER);
|
||||
CommandAdd(NULL, MSG_INFO, cmd_info, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_DNS, cmd_dns, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_REHASH, cmd_rehash, MAXPARA, CMD_USER|CMD_SERVER);
|
||||
CommandAdd(NULL, MSG_RESTART, cmd_restart, 2, CMD_USER);
|
||||
CommandAdd(NULL, MSG_DIE, cmd_die, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_DALINFO, cmd_dalinfo, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_CREDITS, cmd_credits, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_LICENSE, cmd_license, MAXPARA, CMD_USER);
|
||||
CommandAdd(NULL, MSG_MODULE, cmd_module, MAXPARA, CMD_USER);
|
||||
|
||||
#ifdef DEVELOP_DEBUG
|
||||
for (i = 0; i <= 255; i++)
|
||||
{
|
||||
chainlength = 0;
|
||||
for (p = CommandHash[i]; p; p = p->next)
|
||||
chainlength++;
|
||||
if (chainlength)
|
||||
fprintf(stderr, "%c chainlength = %i\r\n",
|
||||
i, chainlength);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
RealCommand *add_Command_backend(char *cmd)
|
||||
{
|
||||
RealCommand *c = safe_alloc(sizeof(RealCommand));
|
||||
|
||||
safe_strdup(c->cmd, cmd);
|
||||
|
||||
/* Add in hash with hash value = first byte */
|
||||
AddListItem(c, CommandHash[toupper(*cmd)]);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline RealCommand *find_Cmd(char *cmd, int flags)
|
||||
{
|
||||
RealCommand *p;
|
||||
for (p = CommandHash[toupper(*cmd)]; p; p = p->next) {
|
||||
if ((flags & CMD_UNREGISTERED) && !(p->flags & CMD_UNREGISTERED))
|
||||
continue;
|
||||
if ((flags & CMD_SHUN) && !(p->flags & CMD_SHUN))
|
||||
continue;
|
||||
if ((flags & CMD_VIRUS) && !(p->flags & CMD_VIRUS))
|
||||
continue;
|
||||
if ((flags & CMD_ALIAS) && !(p->flags & CMD_ALIAS))
|
||||
continue;
|
||||
if (!strcasecmp(p->cmd, cmd))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RealCommand *find_Command(char *cmd, short token, int flags)
|
||||
{
|
||||
Debug((DEBUG_NOTICE, "FindCommand %s", cmd));
|
||||
|
||||
return find_Cmd(cmd, flags);
|
||||
}
|
||||
|
||||
RealCommand *find_Command_simple(char *cmd)
|
||||
{
|
||||
RealCommand *p;
|
||||
|
||||
for (p = CommandHash[toupper(*cmd)]; p; p = p->next) {
|
||||
if (!strcasecmp(p->cmd, cmd))
|
||||
return (p);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Calls the specified command for the user, as if it was received
|
||||
* that way on IRC.
|
||||
* @param client Client that is the source.
|
||||
* @param mtags Message tags for this command.
|
||||
* @param cmd Command to run, eg "JOIN".
|
||||
* @param parc Parameter count plus 1.
|
||||
* @param parv Parameter array.
|
||||
* @note Make sure you terminate the last parv[] parameter with NULL,
|
||||
* this can easily be forgotten, but certain functions depend on it,
|
||||
* you risk crashes otherwise.
|
||||
* @note Once do_cmd() has returned, be sure to check IsDead(client) to
|
||||
* see if the client has been killed. This may happen due to various
|
||||
* reasons, including spamfilter kicking in or some other security
|
||||
* measure.
|
||||
* @note Do not pass insane parameters. The combined size of all parameters
|
||||
* should not exceed 510 bytes, since that is what all code expects.
|
||||
* Similarly, you should not exceed MAXPARA for parc.
|
||||
*/
|
||||
void do_cmd(Client *client, MessageTag *mtags, char *cmd, int parc, char *parv[])
|
||||
{
|
||||
RealCommand *cmptr;
|
||||
|
||||
cmptr = find_Command_simple(cmd);
|
||||
if (cmptr)
|
||||
(*cmptr->func) (client, mtags, parc, parv);
|
||||
}
|
||||
|
||||
+185
-40
@@ -28,61 +28,137 @@ char backupbuf[8192];
|
||||
|
||||
static char *para[MAXPARA + 2];
|
||||
|
||||
/* Forward declarations of functions that are local (static) */
|
||||
static int do_numeric(int, Client *, MessageTag *, int, char **);
|
||||
static void cancel_clients(Client *, Client *, char *);
|
||||
static void remove_unknown(Client *, char *);
|
||||
static void parse2(Client *client, Client **fromptr, MessageTag *mtags, char *ch);
|
||||
static void parse_addlag(Client *client, int cmdbytes);
|
||||
static int client_lagged_up(Client *client);
|
||||
|
||||
/** Ban user that is "flooding from an unknown connection".
|
||||
* This is basically a client sending lots of data but not registering.
|
||||
* Note that "lots" in terms of IRC is a few KB's, since more is rather unusual.
|
||||
* @param client The client.
|
||||
/** Put a packet in the client receive queue and process the data (if
|
||||
* the 'fake lag' rules permit doing so).
|
||||
* @param client The client
|
||||
* @param readbuf The read buffer
|
||||
* @param length The length of the data
|
||||
* @param killsafely If 1 then we may call exit_client() if the client
|
||||
* is flooding. If 0 then we use dead_socket().
|
||||
* @returns 1 in normal circumstances, 0 if client was killed.
|
||||
* @notes If killsafely is 1 and the return value is 0 then
|
||||
* the client was killed - IsDead() is true.
|
||||
* If this is a problem, then set killsafely to 0 when calling.
|
||||
*/
|
||||
void ban_flooder(Client *client)
|
||||
int process_packet(Client *client, char *readbuf, int length, int killsafely)
|
||||
{
|
||||
if (find_tkl_exception(TKL_UNKNOWN_DATA_FLOOD, client))
|
||||
dbuf_put(&client->local->recvQ, readbuf, length);
|
||||
|
||||
/* parse some of what we have (inducing fakelag, etc) */
|
||||
parse_client_queued(client);
|
||||
|
||||
/* We may be killed now, so check for it.. */
|
||||
if (IsDead(client))
|
||||
return 0;
|
||||
|
||||
/* flood from unknown connection */
|
||||
if (IsUnknown(client) && (DBufLength(&client->local->recvQ) > UNKNOWN_FLOOD_AMOUNT*1024))
|
||||
{
|
||||
/* If the user is exempt we will still KILL the client, since it is
|
||||
* clearly misbehaving. We just won't ZLINE the host, so it won't
|
||||
* affect any other connections from the same IP address.
|
||||
*/
|
||||
exit_client(client, NULL, "Flood from unknown connection");
|
||||
sendto_snomask(SNO_FLOOD, "Flood from unknown connection %s detected",
|
||||
client->local->sockhost);
|
||||
if (!killsafely)
|
||||
ban_flooder(client);
|
||||
else
|
||||
dead_socket(client, "Flood from unknown connection");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
|
||||
/* excess flood check */
|
||||
if (IsUser(client) && DBufLength(&client->local->recvQ) > get_recvq(client))
|
||||
{
|
||||
/* place_host_ban also takes care of removing any other clients with same host/ip */
|
||||
place_host_ban(client, BAN_ACT_ZLINE, "Flood from unknown connection", UNKNOWN_FLOOD_BANTIME);
|
||||
sendto_snomask(SNO_FLOOD,
|
||||
"*** Flood -- %s!%s@%s (%d) exceeds %d recvQ",
|
||||
client->name[0] ? client->name : "*",
|
||||
client->user ? client->user->username : "*",
|
||||
client->user ? client->user->realhost : "*",
|
||||
DBufLength(&client->local->recvQ), get_recvq(client));
|
||||
if (!killsafely)
|
||||
exit_client(client, NULL, "Excess Flood");
|
||||
else
|
||||
dead_socket(client, "Excess Flood");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Parse any queued data for 'client', if permitted.
|
||||
* @param client The client.
|
||||
*/
|
||||
void parse_client_queued(Client *client)
|
||||
{
|
||||
int dolen = 0;
|
||||
char buf[READBUFSIZE];
|
||||
|
||||
if (IsDNSLookup(client))
|
||||
return; /* we delay processing of data until the host is resolved */
|
||||
|
||||
if (IsIdentLookup(client))
|
||||
return; /* we delay processing of data until identd has replied */
|
||||
|
||||
if (!IsUser(client) && !IsServer(client) && (iConf.handshake_delay > 0) &&
|
||||
(TStime() - client->local->firsttime < iConf.handshake_delay))
|
||||
{
|
||||
return; /* we delay processing of data until set::handshake-delay is reached */
|
||||
}
|
||||
|
||||
while (DBufLength(&client->local->recvQ) && !client_lagged_up(client))
|
||||
{
|
||||
dolen = dbuf_getmsg(&client->local->recvQ, buf);
|
||||
|
||||
if (dolen == 0)
|
||||
return;
|
||||
|
||||
dopacket(client, buf, dolen);
|
||||
|
||||
if (IsDead(client))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Add "fake lag" if needed.
|
||||
* The main purpose of fake lag is to create artificial lag when
|
||||
* processing incoming data from the client. So, if a client sends
|
||||
* a lot of commands, then next command will be processed at a rate
|
||||
* of 1 per second, or even slower. The exact algorithm is defined in this function.
|
||||
*
|
||||
* Servers are exempt from fake lag, so are IRCOps and clients tagged as
|
||||
* 'no fake lag' by services (rarely used). Finally, there is also an
|
||||
* option called class::options::nofakelag which exempts fakelag.
|
||||
* Exemptions should be granted with extreme care, since a client will
|
||||
* be able to flood at full speed causing potentially many Mbits or even
|
||||
* GBits of data to be sent out to other clients.
|
||||
*
|
||||
* @param client The client.
|
||||
* @param cmdbytes Number of bytes in the command.
|
||||
*/
|
||||
void parse_addlag(Client *client, int cmdbytes)
|
||||
/*
|
||||
** dopacket
|
||||
** client - pointer to client structure for which the buffer data
|
||||
** applies.
|
||||
** buffer - pointr to the buffer containing the newly read data
|
||||
** length - number of valid bytes of data in the buffer
|
||||
**
|
||||
** Note:
|
||||
** It is implicitly assumed that dopacket is called only
|
||||
** with client of "local" variation, which contains all the
|
||||
** necessary fields (buffer etc..)
|
||||
**
|
||||
** Rewritten for linebufs, 19th May 2013. --kaniini
|
||||
*/
|
||||
void dopacket(Client *client, char *buffer, int length)
|
||||
{
|
||||
if (!IsServer(client) && !IsNoFakeLag(client) &&
|
||||
#ifdef FAKELAG_CONFIGURABLE
|
||||
!(client->local->class && (client->local->class->options & CLASS_OPT_NOFAKELAG)) &&
|
||||
#endif
|
||||
!ValidatePermissionsForPath("immune:lag",client,NULL,NULL,NULL))
|
||||
me.local->receiveB += length; /* Update bytes received */
|
||||
client->local->receiveB += length;
|
||||
if (client->local->receiveB > 1023)
|
||||
{
|
||||
client->local->since += (1 + cmdbytes/90);
|
||||
}
|
||||
client->local->receiveK += (client->local->receiveB >> 10);
|
||||
client->local->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
|
||||
}
|
||||
if (me.local->receiveB > 1023)
|
||||
{
|
||||
me.local->receiveK += (me.local->receiveB >> 10);
|
||||
me.local->receiveB &= 0x03ff;
|
||||
}
|
||||
|
||||
me.local->receiveM += 1; /* Update messages received */
|
||||
client->local->receiveM += 1;
|
||||
|
||||
parse(client, buffer, length);
|
||||
}
|
||||
|
||||
void parse2(Client *client, Client **fromptr, MessageTag *mtags, char *ch);
|
||||
|
||||
/** Parse an incoming line.
|
||||
* A line was received previously, buffered via dbuf, now popped from the dbuf stack,
|
||||
@@ -167,7 +243,7 @@ void parse(Client *cptr, char *buffer, int length)
|
||||
* @param mtags Message tags received for this message.
|
||||
* @param ch The incoming line received (buffer), excluding message tags.
|
||||
*/
|
||||
void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, char *ch)
|
||||
static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, char *ch)
|
||||
{
|
||||
Client *from = cptr;
|
||||
char *s;
|
||||
@@ -449,6 +525,75 @@ void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, char *ch)
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Ban user that is "flooding from an unknown connection".
|
||||
* This is basically a client sending lots of data but not registering.
|
||||
* Note that "lots" in terms of IRC is a few KB's, since more is rather unusual.
|
||||
* @param client The client.
|
||||
*/
|
||||
void ban_flooder(Client *client)
|
||||
{
|
||||
if (find_tkl_exception(TKL_UNKNOWN_DATA_FLOOD, client))
|
||||
{
|
||||
/* If the user is exempt we will still KILL the client, since it is
|
||||
* clearly misbehaving. We just won't ZLINE the host, so it won't
|
||||
* affect any other connections from the same IP address.
|
||||
*/
|
||||
exit_client(client, NULL, "Flood from unknown connection");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* place_host_ban also takes care of removing any other clients with same host/ip */
|
||||
place_host_ban(client, BAN_ACT_ZLINE, "Flood from unknown connection", UNKNOWN_FLOOD_BANTIME);
|
||||
}
|
||||
}
|
||||
|
||||
/** Add "fake lag" if needed.
|
||||
* The main purpose of fake lag is to create artificial lag when
|
||||
* processing incoming data from the client. So, if a client sends
|
||||
* a lot of commands, then next command will be processed at a rate
|
||||
* of 1 per second, or even slower. The exact algorithm is defined in this function.
|
||||
*
|
||||
* Servers are exempt from fake lag, so are IRCOps and clients tagged as
|
||||
* 'no fake lag' by services (rarely used). Finally, there is also an
|
||||
* option called class::options::nofakelag which exempts fakelag.
|
||||
* Exemptions should be granted with extreme care, since a client will
|
||||
* be able to flood at full speed causing potentially many Mbits or even
|
||||
* GBits of data to be sent out to other clients.
|
||||
*
|
||||
* @param client The client.
|
||||
* @param cmdbytes Number of bytes in the command.
|
||||
*/
|
||||
void parse_addlag(Client *client, int cmdbytes)
|
||||
{
|
||||
if (!IsServer(client) && !IsNoFakeLag(client) &&
|
||||
#ifdef FAKELAG_CONFIGURABLE
|
||||
!(client->local->class && (client->local->class->options & CLASS_OPT_NOFAKELAG)) &&
|
||||
#endif
|
||||
!ValidatePermissionsForPath("immune:lag",client,NULL,NULL,NULL))
|
||||
{
|
||||
client->local->since += (1 + cmdbytes/90);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns 1 if the client is lagged up and data should NOT be parsed.
|
||||
* See also parse_addlag() for more information on "fake lag".
|
||||
* @param client The client to check
|
||||
* @returns 1 if client is lagged up and data should not be parsed, 0 otherwise.
|
||||
*/
|
||||
static int client_lagged_up(Client *client)
|
||||
{
|
||||
if (client->status < CLIENT_STATUS_UNKNOWN)
|
||||
return 0;
|
||||
if (IsServer(client))
|
||||
return 0;
|
||||
if (ValidatePermissionsForPath("immune:lag",client,NULL,NULL,NULL))
|
||||
return 0;
|
||||
if (client->local->since - TStime() < 10)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** Numeric received from a connection.
|
||||
* @param numeric The numeric code (range 000-999)
|
||||
* @param cptr The client
|
||||
|
||||
Reference in New Issue
Block a user