ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/packet.c
Revision: 5347
Committed: Sun Jan 11 12:42:20 2015 UTC (10 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 10098 byte(s)
Log Message:
- Update copyright years

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 5347 * Copyright (c) 1997-2015 ircd-hybrid development team
5 adx 30 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * USA
20     */
21 michael 2916
22     /*! \file packet.c
23     * \brief Packet handlers.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28 michael 1011 #include "list.h"
29 adx 30 #include "s_bsd.h"
30 michael 1309 #include "conf.h"
31 michael 3347 #include "server.h"
32 adx 30 #include "client.h"
33     #include "ircd.h"
34     #include "parse.h"
35     #include "fdlist.h"
36     #include "packet.h"
37     #include "irc_string.h"
38     #include "memory.h"
39     #include "send.h"
40 michael 3347 #include "misc.h"
41 adx 30
42     #define READBUF_SIZE 16384
43    
44     static char readBuf[READBUF_SIZE];
45    
46 michael 4982
47     /*
48     * client_dopacket - copy packet to client buf and parse it
49     * client_p - pointer to client structure for which the buffer data
50     * applies.
51     * buffer - pointr to the buffer containing the newly read data
52     * length - number of valid bytes of data in the buffer
53     *
54     * Note:
55 michael 4989 * It is implicitly assumed that client_dopacket() is called only
56 michael 4982 * with client_p of "local" variation, which contains all the
57     * necessary fields (buffer etc..)
58     */
59     static void
60     client_dopacket(struct Client *client_p, char *buffer, size_t length)
61     {
62     /* Update messages received */
63     ++me.connection->recv.messages;
64     ++client_p->connection->recv.messages;
65    
66     /* Update bytes received */
67     client_p->connection->recv.bytes += length;
68     me.connection->recv.bytes += length;
69    
70     parse(client_p, buffer, buffer + length);
71     }
72    
73 adx 30 /* extract_one_line()
74     *
75     * inputs - pointer to a dbuf queue
76     * - pointer to buffer to copy data to
77     * output - length of <buffer>
78     * side effects - one line is copied and removed from the dbuf
79     */
80     static int
81     extract_one_line(struct dbuf_queue *qptr, char *buffer)
82     {
83     int line_bytes = 0, empty_bytes = 0, phase = 0;
84 michael 3107 unsigned int idx = 0;
85 michael 4815 dlink_node *node = NULL;
86 adx 30
87     /*
88     * Phase 0: "empty" characters before the line
89     * Phase 1: copying the line
90     * Phase 2: "empty" characters after the line
91     * (delete them as well and free some space in the dbuf)
92     *
93     * Empty characters are CR, LF and space (but, of course, not
94     * in the middle of a line). We try to remove as much of them as we can,
95     * since they simply eat server memory.
96     *
97     * --adx
98     */
99 michael 4815 DLINK_FOREACH(node, qptr->blocks.head)
100 adx 30 {
101 michael 4815 struct dbuf_block *block = node->data;
102 adx 30
103 michael 4815 if (node == qptr->blocks.head)
104 michael 3107 idx = qptr->pos;
105     else
106     idx = 0;
107    
108     for (; idx < block->size; ++idx)
109 adx 30 {
110 michael 3107 char c = block->data[idx];
111    
112 adx 30 if (IsEol(c) || (c == ' ' && phase != 1))
113     {
114 michael 3107 ++empty_bytes;
115 michael 3453
116 adx 30 if (phase == 1)
117     phase = 2;
118     }
119     else switch (phase)
120     {
121     case 0: phase = 1;
122     case 1: if (line_bytes++ < IRCD_BUFSIZE - 2)
123     *buffer++ = c;
124     break;
125     case 2: *buffer = '\0';
126     dbuf_delete(qptr, line_bytes + empty_bytes);
127     return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
128     }
129     }
130     }
131    
132     /*
133     * Now, if we haven't reached phase 2, ignore all line bytes
134     * that we have read, since this is a partial line case.
135     */
136     if (phase != 2)
137     line_bytes = 0;
138     else
139     *buffer = '\0';
140    
141     /* Remove what is now unnecessary */
142     dbuf_delete(qptr, line_bytes + empty_bytes);
143     return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
144     }
145     /*
146     * parse_client_queued - parse client queued messages
147     */
148     static void
149     parse_client_queued(struct Client *client_p)
150 michael 2916 {
151 adx 30 int dolen = 0;
152    
153     if (IsUnknown(client_p))
154     {
155 michael 4982 unsigned int i = 0;
156 adx 30
157 michael 3453 while (1)
158 adx 30 {
159     if (IsDefunct(client_p))
160 michael 2916 return;
161 adx 30
162 michael 4982 /* Rate unknown clients at MAX_FLOOD per loop */
163 adx 30 if (i >= MAX_FLOOD)
164     break;
165    
166 michael 4982 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
167 michael 4890
168 adx 30 if (dolen == 0)
169 michael 2916 break;
170 adx 30
171     client_dopacket(client_p, readBuf, dolen);
172 michael 4982 ++i;
173 adx 30
174 michael 4982 /*
175     * If they've dropped out of the unknown state, break and move
176 adx 30 * to the parsing for their appropriate status. --fl
177     */
178 michael 3453 if (!IsUnknown(client_p))
179 adx 30 break;
180     }
181     }
182    
183     if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
184     {
185     while (1)
186     {
187     if (IsDefunct(client_p))
188     return;
189 michael 4890
190 michael 4982 if ((dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf)) == 0)
191 adx 30 break;
192 michael 3453
193 adx 30 client_dopacket(client_p, readBuf, dolen);
194     }
195     }
196 adx 163 else if (IsClient(client_p))
197 adx 30 {
198 michael 4989 unsigned int checkflood = 1;
199 adx 30
200 michael 4989 if (ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER))
201     checkflood = 0;
202     else if (IsCanFlood(client_p))
203     checkflood = 0;
204    
205 adx 30 /*
206     * Handle flood protection here - if we exceed our flood limit on
207     * messages in this loop, we simply drop out of the loop prematurely.
208     * -- adrian
209     */
210 michael 3453 while (1)
211 adx 30 {
212     if (IsDefunct(client_p))
213 michael 2916 break;
214 adx 30
215 michael 4982 /*
216     * This flood protection works as follows:
217 adx 30 *
218     * A client is given allow_read lines to send to the server. Every
219     * time a line is parsed, sent_parsed is increased. sent_parsed
220     * is decreased by 1 every time flood_recalc is called.
221     *
222     * Thus a client can 'burst' allow_read lines to the server, any
223     * excess lines will be parsed one per flood_recalc() call.
224     *
225     * Therefore a client will be penalised more if they keep flooding,
226     * as sent_parsed will always hover around the allow_read limit
227     * and no 'bursts' will be permitted.
228     */
229 michael 4989 if (checkflood)
230 michael 4982 if (client_p->connection->sent_parsed >= client_p->connection->allow_read)
231 adx 30 break;
232 michael 2916
233 michael 4982 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
234 michael 4890
235 adx 30 if (dolen == 0)
236     break;
237    
238     client_dopacket(client_p, readBuf, dolen);
239 michael 4982 ++client_p->connection->sent_parsed;
240 adx 30 }
241     }
242     }
243    
244     /* flood_endgrace()
245     *
246     * marks the end of the clients grace period
247     */
248     void
249     flood_endgrace(struct Client *client_p)
250     {
251     SetFloodDone(client_p);
252    
253     /* Drop their flood limit back down */
254 michael 4588 client_p->connection->allow_read = MAX_FLOOD;
255 adx 30
256 michael 4982 /*
257     * sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
258 adx 30 * so reset it.
259     */
260 michael 4588 client_p->connection->sent_parsed = 0;
261 adx 30 }
262    
263     /*
264     * flood_recalc
265     *
266     * recalculate the number of allowed flood lines. this should be called
267     * once a second on any given client. We then attempt to flush some data.
268     */
269     void
270     flood_recalc(fde_t *fd, void *data)
271     {
272 michael 4982 struct Client *const client_p = data;
273 michael 2916
274 michael 4890 /*
275     * Allow a bursting client their allocation per second, allow
276 adx 30 * a client whos flooding an extra 2 per second
277     */
278     if (IsFloodDone(client_p))
279 michael 4982 client_p->connection->sent_parsed -= 2;
280 adx 30 else
281 michael 4982 client_p->connection->sent_parsed = 0;
282 michael 2916
283 michael 4982 if (client_p->connection->sent_parsed < 0)
284     client_p->connection->sent_parsed = 0;
285 michael 2916
286 adx 30 parse_client_queued(client_p);
287 michael 2916
288 adx 30 /* And now, try flushing .. */
289     if (!IsDead(client_p))
290     {
291     /* and finally, reset the flood check */
292     comm_setflush(fd, 1000, flood_recalc, client_p);
293     }
294     }
295    
296     /*
297     * read_packet - Read a 'packet' of data from a connection and process it.
298     */
299     void
300     read_packet(fde_t *fd, void *data)
301     {
302 michael 4982 struct Client *const client_p = data;
303 adx 30 int length = 0;
304    
305     if (IsDefunct(client_p))
306     return;
307    
308     /*
309     * Read some data. We *used to* do anti-flood protection here, but
310     * I personally think it makes the code too hairy to make sane.
311     * -- adrian
312     */
313 michael 2916 do
314     {
315 adx 30 #ifdef HAVE_LIBCRYPTO
316     if (fd->ssl)
317     {
318 michael 3453 length = SSL_read(fd->ssl, readBuf, sizeof(readBuf));
319 adx 30
320     /* translate openssl error codes, sigh */
321     if (length < 0)
322     switch (SSL_get_error(fd->ssl, length))
323 michael 2881 {
324 adx 30 case SSL_ERROR_WANT_WRITE:
325 michael 4461 comm_setselect(fd, COMM_SELECT_WRITE, sendq_unblocked, client_p, 0);
326 michael 2881 return;
327     case SSL_ERROR_WANT_READ:
328     errno = EWOULDBLOCK;
329 adx 30 case SSL_ERROR_SYSCALL:
330 michael 2881 break;
331 michael 428 case SSL_ERROR_SSL:
332     if (errno == EAGAIN)
333     break;
334 adx 30 default:
335 michael 2881 length = errno = 0;
336     }
337 adx 30 }
338     else
339     #endif
340     {
341 michael 3453 length = recv(fd->fd, readBuf, sizeof(readBuf), 0);
342 adx 30 }
343    
344     if (length <= 0)
345     {
346     /*
347     * If true, then we can recover from this error. Just jump out of
348     * the loop and re-register a new io-request.
349     */
350     if (length < 0 && ignoreErrno(errno))
351     break;
352    
353     dead_link_on_read(client_p, length);
354     return;
355     }
356    
357 michael 4588 dbuf_put(&client_p->connection->buf_recvq, readBuf, length);
358 adx 30
359 michael 4588 if (client_p->connection->lasttime < CurrentTime)
360     client_p->connection->lasttime = CurrentTime;
361 michael 4890
362 michael 4588 if (client_p->connection->lasttime > client_p->connection->since)
363     client_p->connection->since = CurrentTime;
364 michael 3453
365 adx 30 ClearPingSent(client_p);
366    
367     /* Attempt to parse what we have */
368     parse_client_queued(client_p);
369    
370     if (IsDefunct(client_p))
371     return;
372    
373     /* Check to make sure we're not flooding */
374 michael 4989 if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p)) &&
375     (dbuf_length(&client_p->connection->buf_recvq) >
376     get_recvq(&client_p->connection->confs)))
377 adx 30 {
378 michael 4989 exit_client(client_p, "Excess Flood");
379     return;
380 adx 30 }
381     }
382     #ifdef HAVE_LIBCRYPTO
383     while (length == sizeof(readBuf) || fd->ssl);
384     #else
385     while (length == sizeof(readBuf));
386     #endif
387    
388     /* If we get here, we need to register for another COMM_SELECT_READ */
389     comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
390     }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision