ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/packet.c
Revision: 8280
Committed: Tue Feb 20 19:30:33 2018 UTC (8 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 9059 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 8280 * Copyright (c) 1997-2018 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 4564 * 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 michael 6528
43 michael 6349 enum { READBUF_SIZE = 16384 };
44 adx 30
45     static char readBuf[READBUF_SIZE];
46    
47 michael 4983
48     /*
49     * client_dopacket - copy packet to client buf and parse it
50     * client_p - pointer to client structure for which the buffer data
51     * applies.
52 michael 6518 * buffer - pointer to the buffer containing the newly read data
53 michael 4983 * length - number of valid bytes of data in the buffer
54     *
55     * Note:
56 michael 4988 * It is implicitly assumed that client_dopacket() is called only
57 michael 4983 * with client_p of "local" variation, which contains all the
58     * necessary fields (buffer etc..)
59     */
60     static void
61 michael 5423 client_dopacket(struct Client *client_p, char *buffer, unsigned int length)
62 michael 4983 {
63     /* Update messages received */
64     ++me.connection->recv.messages;
65     ++client_p->connection->recv.messages;
66    
67     /* Update bytes received */
68     client_p->connection->recv.bytes += length;
69     me.connection->recv.bytes += length;
70    
71     parse(client_p, buffer, buffer + length);
72     }
73    
74 adx 30 /* extract_one_line()
75     *
76     * inputs - pointer to a dbuf queue
77     * - pointer to buffer to copy data to
78     * output - length of <buffer>
79     * side effects - one line is copied and removed from the dbuf
80     */
81 michael 5423 static unsigned int
82 adx 30 extract_one_line(struct dbuf_queue *qptr, char *buffer)
83     {
84 michael 5423 unsigned int line_bytes = 0, eol_bytes = 0;
85 michael 5420 dlink_node *node;
86 adx 30
87 michael 5420 DLINK_FOREACH(node, qptr->blocks.head)
88 adx 30 {
89 michael 5420 const struct dbuf_block *block = node->data;
90 michael 5412 unsigned int idx;
91 adx 30
92 michael 5420 if (node == qptr->blocks.head)
93 michael 3107 idx = qptr->pos;
94     else
95     idx = 0;
96    
97     for (; idx < block->size; ++idx)
98 adx 30 {
99 michael 3107 char c = block->data[idx];
100    
101 michael 5412 if (IsEol(c))
102 adx 30 {
103 michael 5412 ++eol_bytes;
104 michael 3454
105 michael 5412 /* Allow 2 eol bytes per message */
106     if (eol_bytes == 2)
107     goto out;
108 adx 30 }
109 michael 5412 else if (eol_bytes)
110     goto out;
111     else if (line_bytes++ < IRCD_BUFSIZE - 2)
112     *buffer++ = c;
113 adx 30 }
114     }
115    
116 michael 5412 out:
117    
118 adx 30 /*
119 michael 5412 * Now, if we haven't found an EOL, ignore all line bytes
120 adx 30 * that we have read, since this is a partial line case.
121     */
122 michael 5412 if (eol_bytes)
123     *buffer = '\0';
124     else
125 adx 30 line_bytes = 0;
126    
127     /* Remove what is now unnecessary */
128 michael 5412 dbuf_delete(qptr, line_bytes + eol_bytes);
129    
130 adx 30 return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
131     }
132 michael 5412
133 adx 30 /*
134     * parse_client_queued - parse client queued messages
135     */
136     static void
137     parse_client_queued(struct Client *client_p)
138 michael 2916 {
139 michael 5423 unsigned int dolen = 0;
140 adx 30
141     if (IsUnknown(client_p))
142     {
143 michael 4983 unsigned int i = 0;
144 adx 30
145 michael 3454 while (1)
146 adx 30 {
147     if (IsDefunct(client_p))
148 michael 2916 return;
149 adx 30
150 michael 4983 /* Rate unknown clients at MAX_FLOOD per loop */
151 adx 30 if (i >= MAX_FLOOD)
152     break;
153    
154 michael 4983 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
155 michael 4889
156 adx 30 if (dolen == 0)
157 michael 2916 break;
158 adx 30
159     client_dopacket(client_p, readBuf, dolen);
160 michael 4983 ++i;
161 adx 30
162 michael 4983 /*
163     * If they've dropped out of the unknown state, break and move
164 adx 30 * to the parsing for their appropriate status. --fl
165     */
166 michael 3454 if (!IsUnknown(client_p))
167 adx 30 break;
168     }
169     }
170    
171     if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
172     {
173     while (1)
174     {
175     if (IsDefunct(client_p))
176     return;
177 michael 4889
178 michael 4983 if ((dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf)) == 0)
179 adx 30 break;
180 michael 3454
181 adx 30 client_dopacket(client_p, readBuf, dolen);
182     }
183     }
184 adx 163 else if (IsClient(client_p))
185 adx 30 {
186 michael 4988 unsigned int checkflood = 1;
187 adx 30
188 michael 4988 if (ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER))
189     checkflood = 0;
190 michael 6314 else if (HasFlag(client_p, FLAGS_CANFLOOD))
191 michael 4988 checkflood = 0;
192    
193 adx 30 /*
194 michael 5546 * Handle flood protection here - if we exceed our flood limit on messages
195     * in this loop, we simply drop out of the loop prematurely.
196 adx 30 * -- adrian
197     */
198 michael 3454 while (1)
199 adx 30 {
200     if (IsDefunct(client_p))
201 michael 2916 break;
202 adx 30
203 michael 4983 /*
204     * This flood protection works as follows:
205 adx 30 *
206     * A client is given allow_read lines to send to the server. Every
207     * time a line is parsed, sent_parsed is increased. sent_parsed
208     * is decreased by 1 every time flood_recalc is called.
209     *
210     * Thus a client can 'burst' allow_read lines to the server, any
211     * excess lines will be parsed one per flood_recalc() call.
212     *
213     * Therefore a client will be penalised more if they keep flooding,
214     * as sent_parsed will always hover around the allow_read limit
215     * and no 'bursts' will be permitted.
216     */
217 michael 4988 if (checkflood)
218 michael 4983 if (client_p->connection->sent_parsed >= client_p->connection->allow_read)
219 adx 30 break;
220 michael 2916
221 michael 4983 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
222 michael 4889
223 adx 30 if (dolen == 0)
224     break;
225    
226     client_dopacket(client_p, readBuf, dolen);
227 michael 4983 ++client_p->connection->sent_parsed;
228 adx 30 }
229     }
230     }
231    
232     /* flood_endgrace()
233     *
234     * marks the end of the clients grace period
235     */
236     void
237     flood_endgrace(struct Client *client_p)
238     {
239 michael 6314 AddFlag(client_p, FLAGS_FLOODDONE);
240 adx 30
241     /* Drop their flood limit back down */
242 michael 4589 client_p->connection->allow_read = MAX_FLOOD;
243 adx 30
244 michael 4983 /*
245     * sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
246 adx 30 * so reset it.
247     */
248 michael 4589 client_p->connection->sent_parsed = 0;
249 adx 30 }
250    
251     /*
252     * flood_recalc
253     *
254     * recalculate the number of allowed flood lines. this should be called
255     * once a second on any given client. We then attempt to flush some data.
256     */
257     void
258     flood_recalc(fde_t *fd, void *data)
259     {
260 michael 4983 struct Client *const client_p = data;
261 michael 2916
262 michael 4889 /*
263     * Allow a bursting client their allocation per second, allow
264 michael 6519 * a client who is flooding an extra 2 per second
265 adx 30 */
266     if (IsFloodDone(client_p))
267 michael 4983 client_p->connection->sent_parsed -= 2;
268 adx 30 else
269 michael 4983 client_p->connection->sent_parsed = 0;
270 michael 2916
271 michael 4983 if (client_p->connection->sent_parsed < 0)
272     client_p->connection->sent_parsed = 0;
273 michael 2916
274 adx 30 parse_client_queued(client_p);
275 michael 2916
276 adx 30 /* And now, try flushing .. */
277     if (!IsDead(client_p))
278     {
279     /* and finally, reset the flood check */
280     comm_setflush(fd, 1000, flood_recalc, client_p);
281     }
282     }
283    
284     /*
285     * read_packet - Read a 'packet' of data from a connection and process it.
286     */
287     void
288     read_packet(fde_t *fd, void *data)
289     {
290 michael 4983 struct Client *const client_p = data;
291 adx 30 int length = 0;
292 michael 7106 int want_write = 0;
293 adx 30
294     if (IsDefunct(client_p))
295     return;
296    
297     /*
298     * Read some data. We *used to* do anti-flood protection here, but
299     * I personally think it makes the code too hairy to make sane.
300     * -- adrian
301     */
302 michael 2916 do
303     {
304 michael 7106 if (tls_isusing(&fd->ssl))
305 adx 30 {
306 michael 7106 length = tls_read(&fd->ssl, readBuf, sizeof(readBuf), &want_write);
307 adx 30
308 michael 7106 if (want_write)
309     comm_setselect(fd, COMM_SELECT_WRITE, sendq_unblocked, client_p, 0);
310 adx 30 }
311     else
312 michael 3454 length = recv(fd->fd, readBuf, sizeof(readBuf), 0);
313 adx 30
314     if (length <= 0)
315     {
316     /*
317 michael 5546 * If true, then we can recover from this error. Just jump out of
318 adx 30 * the loop and re-register a new io-request.
319     */
320     if (length < 0 && ignoreErrno(errno))
321     break;
322    
323     dead_link_on_read(client_p, length);
324     return;
325     }
326    
327 michael 4589 dbuf_put(&client_p->connection->buf_recvq, readBuf, length);
328 adx 30
329 michael 4589 if (client_p->connection->lasttime < CurrentTime)
330     client_p->connection->lasttime = CurrentTime;
331 michael 4889
332 michael 4589 if (client_p->connection->lasttime > client_p->connection->since)
333     client_p->connection->since = CurrentTime;
334 michael 3454
335 michael 6314 DelFlag(client_p, FLAGS_PINGSENT);
336 adx 30
337     /* Attempt to parse what we have */
338     parse_client_queued(client_p);
339    
340     if (IsDefunct(client_p))
341     return;
342    
343     /* Check to make sure we're not flooding */
344 michael 4988 if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p)) &&
345     (dbuf_length(&client_p->connection->buf_recvq) >
346     get_recvq(&client_p->connection->confs)))
347 adx 30 {
348 michael 4988 exit_client(client_p, "Excess Flood");
349     return;
350 adx 30 }
351 michael 7106 } while (length == sizeof(readBuf) || tls_isusing(&fd->ssl));
352 adx 30
353     /* If we get here, we need to register for another COMM_SELECT_READ */
354     comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
355     }

Properties

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