Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/VibeDevelopers/Comet.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379/* * ircd-ratbox: A slightly useful ircd. * packet.c: Packet handlers. * * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 2002-2005 ircd-ratbox development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */#include "stdinc.h"#include "s_conf.h"#include "s_serv.h"#include "client.h"#include "ircd.h"#include "parse.h"#include "packet.h"#include "match.h"#include "hook.h"#include "send.h"#include "s_assert.h"#include "s_newconf.h"
static char readBuf[READBUF_SIZE];static void client_dopacket(struct Client *client_p, char *buffer, size_t length);
/* * parse_client_queued - parse client queued messages */static voidparse_client_queued(struct Client *client_p){ int dolen = 0; int allow_read;
if(IsAnyDead(client_p)) return;
if(IsUnknown(client_p)) { allow_read = ConfigFileEntry.client_flood_burst_max; for (;;) { if(client_p->localClient->sent_parsed >= allow_read) break;
dolen = rb_linebuf_get(&client_p->localClient-> buf_recvq, readBuf, READBUF_SIZE, LINEBUF_COMPLETE, LINEBUF_PARSED);
if(dolen <= 0 || IsDead(client_p)) break;
client_dopacket(client_p, readBuf, dolen); client_p->localClient->sent_parsed++;
/* He's dead cap'n */ if(IsAnyDead(client_p)) return; /* if theyve dropped out of the unknown state, break and move * to the parsing for their appropriate status. --fl */ if(!IsUnknown(client_p)) { /* reset their flood limits, they're now * graced to flood */ client_p->localClient->sent_parsed = 0; break; }
} /* If sent_parsed is impossibly high, drop it down. * This is useful if the configuration is changed. */ if(client_p->localClient->sent_parsed > allow_read) client_p->localClient->sent_parsed = allow_read; }
if(IsAnyServer(client_p) || IsExemptFlood(client_p)) { while (!IsAnyDead(client_p) && (dolen = rb_linebuf_get(&client_p->localClient->buf_recvq, readBuf, READBUF_SIZE, LINEBUF_COMPLETE, LINEBUF_PARSED)) > 0) { client_dopacket(client_p, readBuf, dolen); } } else if(IsClient(client_p)) { if(IsFloodDone(client_p)) allow_read = ConfigFileEntry.client_flood_burst_max; else allow_read = ConfigFileEntry.client_flood_burst_rate; allow_read *= ConfigFileEntry.client_flood_message_time; /* allow opers 4 times the amount of messages as users. why 4? * why not. :) --fl_ */ if(IsOperGeneral(client_p) && ConfigFileEntry.no_oper_flood) allow_read *= 4; /* * Handle flood protection here - if we exceed our flood limit on * messages in this loop, we simply drop out of the loop prematurely. * -- adrian */ for (;;) { /* This flood protection works as follows: * * A client is given allow_read lines to send to the server. Every * time a line is parsed, sent_parsed is increased. sent_parsed * is decreased by 1 every time flood_recalc is called. * * Thus a client can 'burst' allow_read lines to the server, any * excess lines will be parsed one per flood_recalc() call. * * Therefore a client will be penalised more if they keep flooding, * as sent_parsed will always hover around the allow_read limit * and no 'bursts' will be permitted. */ if(client_p->localClient->sent_parsed >= allow_read) break;
/* post_registration_delay hack. Don't process any messages from a new client for $n seconds, * to allow network bots to do their thing before channels can be joined. */ if (rb_current_time() < client_p->localClient->firsttime + ConfigFileEntry.post_registration_delay) break;
dolen = rb_linebuf_get(&client_p->localClient-> buf_recvq, readBuf, READBUF_SIZE, LINEBUF_COMPLETE, LINEBUF_PARSED);
if(!dolen) break;
client_dopacket(client_p, readBuf, dolen); if(IsAnyDead(client_p)) return;
client_p->localClient->sent_parsed += ConfigFileEntry.client_flood_message_time; } /* If sent_parsed is impossibly high, drop it down. * This is useful if the configuration is changed. */ if(client_p->localClient->sent_parsed > allow_read + ConfigFileEntry.client_flood_message_time - 1) client_p->localClient->sent_parsed = allow_read + ConfigFileEntry.client_flood_message_time - 1; }}
/* flood_endgrace() * * marks the end of the clients grace period */voidflood_endgrace(struct Client *client_p){ SetFloodDone(client_p);
/* sent_parsed could be way over client_flood_burst_max but under * client_flood_burst_rate so reset it. */ client_p->localClient->sent_parsed = 0;}
/* * flood_recalc * * recalculate the number of allowed flood lines. this should be called * once a second on any given client. We then attempt to flush some data. */voidflood_recalc(void *unused){ rb_dlink_node *ptr, *next; struct Client *client_p;
RB_DLINK_FOREACH_SAFE(ptr, next, lclient_list.head) { client_p = ptr->data;
if(rb_unlikely(IsMe(client_p))) continue;
if(rb_unlikely(client_p->localClient == NULL)) continue;
if(IsFloodDone(client_p)) client_p->localClient->sent_parsed -= ConfigFileEntry.client_flood_message_num; else client_p->localClient->sent_parsed = 0;
if(client_p->localClient->sent_parsed < 0) client_p->localClient->sent_parsed = 0;
parse_client_queued(client_p);
if(rb_unlikely(IsAnyDead(client_p))) continue;
}
RB_DLINK_FOREACH_SAFE(ptr, next, unknown_list.head) { client_p = ptr->data;
if(client_p->localClient == NULL) continue;
client_p->localClient->sent_parsed--;
if(client_p->localClient->sent_parsed < 0) client_p->localClient->sent_parsed = 0;
parse_client_queued(client_p); }}
/* * read_packet - Read a 'packet' of data from a connection and process it. */voidread_packet(rb_fde_t * F, void *data){ struct Client *client_p = data; int length = 0; int binary = 0;
while(1) { if(IsAnyDead(client_p)) return;
/* * Read some data. We *used to* do anti-flood protection here, but * I personally think it makes the code too hairy to make sane. * -- adrian */ length = rb_read(client_p->localClient->F, readBuf, READBUF_SIZE);
if(length < 0) { if(rb_ignore_errno(errno)) rb_setselect(client_p->localClient->F, RB_SELECT_READ, read_packet, client_p); else error_exit_client(client_p, length); return; } else if(length == 0) { error_exit_client(client_p, length); return; }
if(client_p->localClient->lasttime < rb_current_time()) client_p->localClient->lasttime = rb_current_time(); client_p->flags &= ~FLAGS_PINGSENT;
if (client_p->flags & FLAGS_PINGWARN) { /* * if we warned about this server being unresponsive * before, let's let everyone know there's no need * to panic */ client_p->flags &= ~FLAGS_PINGWARN; sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Received response from previously unresponsive link %s", client_p->name); ilog(L_SERVER, "Received response from previously unresponsive link %s", log_client_name(client_p, HIDE_IP)); }
/* * Before we even think of parsing what we just read, stick * it on the end of the receive queue and do it when its * turn comes around. */ if(IsHandshake(client_p) || IsUnknown(client_p)) binary = 1;
(void) rb_linebuf_parse(&client_p->localClient->buf_recvq, readBuf, length, binary);
if(IsAnyDead(client_p)) return;
/* Attempt to parse what we have */ parse_client_queued(client_p);
if(IsAnyDead(client_p)) return;
/* Check to make sure we're not flooding */ if(!IsAnyServer(client_p) && (rb_linebuf_alloclen(&client_p->localClient->buf_recvq) + client_p->localClient->pending_batch_lines > ConfigFileEntry.client_flood_max_lines)) { if(!(ConfigFileEntry.no_oper_flood && IsOperGeneral(client_p))) { exit_client(client_p, client_p, client_p, "Excess Flood"); return; } }
/* bail if short read, but not for SCTP as it returns data in packets */ if (length < READBUF_SIZE && !(rb_get_type(client_p->localClient->F) & RB_FD_SCTP)) { rb_setselect(client_p->localClient->F, RB_SELECT_READ, read_packet, client_p); return; } }}
/* * client_dopacket - copy packet to client buf and parse it * client_p - 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_p of "local" variation, which contains all the * necessary fields (buffer etc..) */static voidclient_dopacket(struct Client *client_p, char *buffer, size_t length){ s_assert(client_p != NULL); s_assert(buffer != NULL);
if(client_p == NULL || buffer == NULL) return; if(IsAnyDead(client_p)) return; /* * Update messages received */ ++me.localClient->receiveM; ++client_p->localClient->receiveM;
/* * Update bytes received */ client_p->localClient->receiveB += length;
if(client_p->localClient->receiveB > 1023) { client_p->localClient->receiveK += (client_p->localClient->receiveB >> 10); client_p->localClient->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */ }
me.localClient->receiveB += length;
if(me.localClient->receiveB > 1023) { me.localClient->receiveK += (me.localClient->receiveB >> 10); me.localClient->receiveB &= 0x03ff; }
parse(client_p, buffer, buffer + length);}