ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/packet.c
Revision: 9157
Committed: Mon Jan 13 14:56:38 2020 UTC (5 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 9032 byte(s)
Log Message:
- Replaced most occurences of 'SSL' with 'TLS'

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 9101 * Copyright (c) 1997-2020 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 michael 6527
43 michael 6350 enum { READBUF_SIZE = 16384 };
44 adx 30
45     static char readBuf[READBUF_SIZE];
46    
47 michael 4982
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 6517 * buffer - pointer to the buffer containing the newly read data
53 michael 4982 * length - number of valid bytes of data in the buffer
54     *
55     * Note:
56 michael 4989 * It is implicitly assumed that client_dopacket() is called only
57 michael 4982 * with client_p of "local" variation, which contains all the
58     * necessary fields (buffer etc..)
59     */
60     static void
61 michael 5422 client_dopacket(struct Client *client_p, char *buffer, unsigned int length)
62 michael 4982 {
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 8709 static size_t
82 adx 30 extract_one_line(struct dbuf_queue *qptr, char *buffer)
83     {
84 michael 8709 size_t line_bytes = 0, eol_bytes = 0;
85 michael 5421 dlink_node *node;
86 adx 30
87 michael 5421 DLINK_FOREACH(node, qptr->blocks.head)
88 adx 30 {
89 michael 5421 const struct dbuf_block *block = node->data;
90 michael 5413 unsigned int idx;
91 adx 30
92 michael 5421 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 5413 if (IsEol(c))
102 adx 30 {
103 michael 5413 ++eol_bytes;
104 michael 3453
105 michael 5413 /* Allow 2 eol bytes per message */
106     if (eol_bytes == 2)
107     goto out;
108 adx 30 }
109 michael 5413 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 5413 out:
117    
118 adx 30 /*
119 michael 5413 * 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 5413 if (eol_bytes)
123     *buffer = '\0';
124     else
125 adx 30 line_bytes = 0;
126    
127     /* Remove what is now unnecessary */
128 michael 5413 dbuf_delete(qptr, line_bytes + eol_bytes);
129    
130 adx 30 return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
131     }
132 michael 5413
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 adx 30 if (IsUnknown(client_p))
140     {
141 michael 4982 unsigned int i = 0;
142 adx 30
143 michael 8664 while (true)
144 adx 30 {
145     if (IsDefunct(client_p))
146 michael 2916 return;
147 adx 30
148 michael 4982 /* Rate unknown clients at MAX_FLOOD per loop */
149 adx 30 if (i >= MAX_FLOOD)
150     break;
151    
152 michael 8709 size_t dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
153 adx 30 if (dolen == 0)
154 michael 2916 break;
155 adx 30
156     client_dopacket(client_p, readBuf, dolen);
157 michael 4982 ++i;
158 adx 30
159 michael 4982 /*
160     * If they've dropped out of the unknown state, break and move
161 adx 30 * to the parsing for their appropriate status. --fl
162     */
163 michael 3453 if (!IsUnknown(client_p))
164 adx 30 break;
165     }
166     }
167    
168     if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
169     {
170 michael 8664 while (true)
171 adx 30 {
172     if (IsDefunct(client_p))
173     return;
174 michael 4890
175 michael 8709 size_t dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
176     if (dolen == 0)
177 adx 30 break;
178 michael 3453
179 adx 30 client_dopacket(client_p, readBuf, dolen);
180     }
181     }
182 adx 163 else if (IsClient(client_p))
183 adx 30 {
184 michael 8660 bool checkflood = true;
185 adx 30
186 michael 4989 if (ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER))
187 michael 8660 checkflood = false;
188 michael 6313 else if (HasFlag(client_p, FLAGS_CANFLOOD))
189 michael 8660 checkflood = false;
190 michael 4989
191 adx 30 /*
192 michael 5545 * Handle flood protection here - if we exceed our flood limit on messages
193     * in this loop, we simply drop out of the loop prematurely.
194 adx 30 * -- adrian
195     */
196 michael 8664 while (true)
197 adx 30 {
198     if (IsDefunct(client_p))
199 michael 2916 break;
200 adx 30
201 michael 4982 /*
202     * This flood protection works as follows:
203 adx 30 *
204     * A client is given allow_read lines to send to the server. Every
205     * time a line is parsed, sent_parsed is increased. sent_parsed
206     * is decreased by 1 every time flood_recalc is called.
207     *
208     * Thus a client can 'burst' allow_read lines to the server, any
209     * excess lines will be parsed one per flood_recalc() call.
210     *
211     * Therefore a client will be penalised more if they keep flooding,
212     * as sent_parsed will always hover around the allow_read limit
213     * and no 'bursts' will be permitted.
214     */
215 michael 8660 if (checkflood == true)
216 michael 8710 if (client_p->connection->sent_parsed >= (IsFloodDone(client_p) ? MAX_FLOOD : MAX_FLOOD_BURST))
217 adx 30 break;
218 michael 2916
219 michael 8709 size_t dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
220 adx 30 if (dolen == 0)
221     break;
222    
223     client_dopacket(client_p, readBuf, dolen);
224 michael 4982 ++client_p->connection->sent_parsed;
225 adx 30 }
226     }
227     }
228    
229     /* flood_endgrace()
230     *
231     * marks the end of the clients grace period
232     */
233     void
234     flood_endgrace(struct Client *client_p)
235     {
236 michael 8715 if (IsFloodDone(client_p))
237     return; /* Grace period has already ended */
238    
239 michael 6313 AddFlag(client_p, FLAGS_FLOODDONE);
240 adx 30
241 michael 4982 /*
242     * sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
243 adx 30 * so reset it.
244     */
245 michael 4588 client_p->connection->sent_parsed = 0;
246 adx 30 }
247    
248     /*
249     * flood_recalc
250     *
251     * recalculate the number of allowed flood lines. this should be called
252     * once a second on any given client. We then attempt to flush some data.
253     */
254     void
255 michael 8339 flood_recalc(fde_t *F, void *data)
256 adx 30 {
257 michael 4982 struct Client *const client_p = data;
258 michael 2916
259 michael 4890 /*
260     * Allow a bursting client their allocation per second, allow
261 michael 6520 * a client who is flooding an extra 2 per second
262 adx 30 */
263     if (IsFloodDone(client_p))
264 michael 4982 client_p->connection->sent_parsed -= 2;
265 adx 30 else
266 michael 4982 client_p->connection->sent_parsed = 0;
267 michael 2916
268 michael 4982 if (client_p->connection->sent_parsed < 0)
269     client_p->connection->sent_parsed = 0;
270 michael 2916
271 adx 30 parse_client_queued(client_p);
272 michael 2916
273 adx 30 /* And now, try flushing .. */
274     if (!IsDead(client_p))
275     {
276     /* and finally, reset the flood check */
277 michael 8941 comm_setflush(F, 1, flood_recalc, client_p);
278 adx 30 }
279     }
280    
281     /*
282     * read_packet - Read a 'packet' of data from a connection and process it.
283     */
284     void
285 michael 8339 read_packet(fde_t *F, void *data)
286 adx 30 {
287 michael 4982 struct Client *const client_p = data;
288 michael 8956 ssize_t length = 0;
289 adx 30
290 michael 8339 assert(client_p);
291     assert(client_p->connection);
292     assert(client_p->connection->fd);
293     assert(client_p->connection->fd == F);
294    
295 adx 30 if (IsDefunct(client_p))
296     return;
297    
298     /*
299     * Read some data. We *used to* do anti-flood protection here, but
300     * I personally think it makes the code too hairy to make sane.
301     * -- adrian
302     */
303 michael 8951 while (true)
304 michael 2916 {
305 michael 9157 if (tls_isusing(&F->tls))
306 adx 30 {
307 michael 8660 bool want_write = false;
308 michael 9157 length = tls_read(&F->tls, readBuf, sizeof(readBuf), &want_write);
309 adx 30
310 michael 8660 if (want_write == true)
311 michael 8339 comm_setselect(F, COMM_SELECT_WRITE, sendq_unblocked, client_p, 0);
312 adx 30 }
313     else
314 michael 8339 length = recv(F->fd, readBuf, sizeof(readBuf), 0);
315 adx 30
316     if (length <= 0)
317     {
318     /*
319 michael 8953 * If true, then we can recover from this error. Stop here and register for
320     * another COMM_SELECT_READ io-request.
321 adx 30 */
322 michael 8660 if (length < 0 && comm_ignore_errno(errno) == true)
323 michael 8953 comm_setselect(F, COMM_SELECT_READ, read_packet, client_p, 0);
324     else
325     dead_link_on_read(client_p, length);
326 adx 30 return;
327     }
328    
329 michael 4588 dbuf_put(&client_p->connection->buf_recvq, readBuf, length);
330 adx 30
331 michael 8919 client_p->connection->last_ping = event_base->time.sec_monotonic;
332     client_p->connection->last_data = event_base->time.sec_monotonic;
333 michael 4890
334 michael 6313 DelFlag(client_p, FLAGS_PINGSENT);
335 adx 30
336     /* Attempt to parse what we have */
337     parse_client_queued(client_p);
338    
339     if (IsDefunct(client_p))
340     return;
341    
342     /* Check to make sure we're not flooding */
343 michael 4989 if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p)) &&
344     (dbuf_length(&client_p->connection->buf_recvq) >
345     get_recvq(&client_p->connection->confs)))
346 adx 30 {
347 michael 4989 exit_client(client_p, "Excess Flood");
348     return;
349 adx 30 }
350 michael 8951 }
351 adx 30 }

Properties

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