ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/packet.c
Revision: 7113
Committed: Sat Jan 23 20:31:25 2016 UTC (9 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 9059 byte(s)
Log Message:
- Remove some HAVE_TLS

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2016 ircd-hybrid development team
5 *
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 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file packet.c
23 * \brief Packet handlers.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "s_bsd.h"
30 #include "conf.h"
31 #include "server.h"
32 #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 #include "misc.h"
41
42
43 enum { READBUF_SIZE = 16384 };
44
45 static char readBuf[READBUF_SIZE];
46
47
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 * buffer - pointer to the buffer containing the newly read data
53 * length - number of valid bytes of data in the buffer
54 *
55 * Note:
56 * It is implicitly assumed that client_dopacket() is called only
57 * with client_p of "local" variation, which contains all the
58 * necessary fields (buffer etc..)
59 */
60 static void
61 client_dopacket(struct Client *client_p, char *buffer, unsigned int length)
62 {
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 /* 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 static unsigned int
82 extract_one_line(struct dbuf_queue *qptr, char *buffer)
83 {
84 unsigned int line_bytes = 0, eol_bytes = 0;
85 dlink_node *node;
86
87 DLINK_FOREACH(node, qptr->blocks.head)
88 {
89 const struct dbuf_block *block = node->data;
90 unsigned int idx;
91
92 if (node == qptr->blocks.head)
93 idx = qptr->pos;
94 else
95 idx = 0;
96
97 for (; idx < block->size; ++idx)
98 {
99 char c = block->data[idx];
100
101 if (IsEol(c))
102 {
103 ++eol_bytes;
104
105 /* Allow 2 eol bytes per message */
106 if (eol_bytes == 2)
107 goto out;
108 }
109 else if (eol_bytes)
110 goto out;
111 else if (line_bytes++ < IRCD_BUFSIZE - 2)
112 *buffer++ = c;
113 }
114 }
115
116 out:
117
118 /*
119 * Now, if we haven't found an EOL, ignore all line bytes
120 * that we have read, since this is a partial line case.
121 */
122 if (eol_bytes)
123 *buffer = '\0';
124 else
125 line_bytes = 0;
126
127 /* Remove what is now unnecessary */
128 dbuf_delete(qptr, line_bytes + eol_bytes);
129
130 return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
131 }
132
133 /*
134 * parse_client_queued - parse client queued messages
135 */
136 static void
137 parse_client_queued(struct Client *client_p)
138 {
139 unsigned int dolen = 0;
140
141 if (IsUnknown(client_p))
142 {
143 unsigned int i = 0;
144
145 while (1)
146 {
147 if (IsDefunct(client_p))
148 return;
149
150 /* Rate unknown clients at MAX_FLOOD per loop */
151 if (i >= MAX_FLOOD)
152 break;
153
154 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
155
156 if (dolen == 0)
157 break;
158
159 client_dopacket(client_p, readBuf, dolen);
160 ++i;
161
162 /*
163 * If they've dropped out of the unknown state, break and move
164 * to the parsing for their appropriate status. --fl
165 */
166 if (!IsUnknown(client_p))
167 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
178 if ((dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf)) == 0)
179 break;
180
181 client_dopacket(client_p, readBuf, dolen);
182 }
183 }
184 else if (IsClient(client_p))
185 {
186 unsigned int checkflood = 1;
187
188 if (ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER))
189 checkflood = 0;
190 else if (HasFlag(client_p, FLAGS_CANFLOOD))
191 checkflood = 0;
192
193 /*
194 * 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 * -- adrian
197 */
198 while (1)
199 {
200 if (IsDefunct(client_p))
201 break;
202
203 /*
204 * This flood protection works as follows:
205 *
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 if (checkflood)
218 if (client_p->connection->sent_parsed >= client_p->connection->allow_read)
219 break;
220
221 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
222
223 if (dolen == 0)
224 break;
225
226 client_dopacket(client_p, readBuf, dolen);
227 ++client_p->connection->sent_parsed;
228 }
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 AddFlag(client_p, FLAGS_FLOODDONE);
240
241 /* Drop their flood limit back down */
242 client_p->connection->allow_read = MAX_FLOOD;
243
244 /*
245 * sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
246 * so reset it.
247 */
248 client_p->connection->sent_parsed = 0;
249 }
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 struct Client *const client_p = data;
261
262 /*
263 * Allow a bursting client their allocation per second, allow
264 * a client who is flooding an extra 2 per second
265 */
266 if (IsFloodDone(client_p))
267 client_p->connection->sent_parsed -= 2;
268 else
269 client_p->connection->sent_parsed = 0;
270
271 if (client_p->connection->sent_parsed < 0)
272 client_p->connection->sent_parsed = 0;
273
274 parse_client_queued(client_p);
275
276 /* 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 struct Client *const client_p = data;
291 int length = 0;
292 int want_write = 0;
293
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 do
303 {
304 if (tls_isusing(&fd->ssl))
305 {
306 length = tls_read(&fd->ssl, readBuf, sizeof(readBuf), &want_write);
307
308 if (want_write)
309 comm_setselect(fd, COMM_SELECT_WRITE, sendq_unblocked, client_p, 0);
310 }
311 else
312 length = recv(fd->fd, readBuf, sizeof(readBuf), 0);
313
314 if (length <= 0)
315 {
316 /*
317 * If true, then we can recover from this error. Just jump out of
318 * 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 dbuf_put(&client_p->connection->buf_recvq, readBuf, length);
328
329 if (client_p->connection->lasttime < CurrentTime)
330 client_p->connection->lasttime = CurrentTime;
331
332 if (client_p->connection->lasttime > client_p->connection->since)
333 client_p->connection->since = CurrentTime;
334
335 DelFlag(client_p, FLAGS_PINGSENT);
336
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 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 {
348 exit_client(client_p, "Excess Flood");
349 return;
350 }
351 } while (length == sizeof(readBuf) || tls_isusing(&fd->ssl));
352
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 Revision